.

Сценарий

Предположим, некая компания использует список SharePoint (названный RFQ) для отслеживания запросов на цены, которые поступают от потенциальных потребителей через сайт компании, основанный на SharePoint 2010. Список интегрирован с рядом бизнес-процессов, которые облегчают процесс ответа на RFQ. Бизнес–процесс включает в себя составление сметы для RFQ, создание формального рабочего задания statement of work (SOW), состоящего из сметы, одобрения SOW и предоставления SOW потенциальному потребителю. Сотрудники компании используют приложения Windows 8 для отслеживания RFQ и создания смет для них. Как только завершается процесс ответа на RFQ, список SharePoint обновляется, и сотрудники получают уведомления на свои компьютеры и планшеты Windows 8. Уведомления информируют их о статусе процесса для каждого RFQ и любого этапа действий, который сотрудник должен выполнить.

В частности, в статье будет показано, как отсылать уведомления в приложение Windows 8, когда потенциальному покупателю предоставляется новый RFQ, и как обновлять список RFQ, когда создается смета для RFQ с помощью приложения Windows 8.

Компоненты

Необходимая архитектура для создания бизнес–процесса извещающего уведомления в приложении сайта SharePoint 2010, состоит из четырех компонентов.

  • Сервер SharePoint 2010 – проверяет изменения элементов списка и передает их службе, как это делает приложение ASP.NET MVC 4.
  • Приложение ASP.NET MVC 4 – получает события от SharePoint, упаковывает их и отсылает службам Windows Push Notification Services.
  • Службы Windows Push Notification Services (WNS) – получают запросы об уведомлениях и направляют уведомления подписчикам.
  • Приложение Windows 8 – показывает уведомления, полученные от WNS.

На рисунке 1 показаны компоненты, составляющие решение. Прямоугольник Windows 8 слева обозначает компьютер с работающей на нем Windows 8. Встроенная платформа уведомлений Notification Client Platform операционной системы Windows 8 получает уведомления и отсылает их к приложениям Windows 8.

 

Архитектура решения для отправки уведомлений
Рисунок 1. Архитектура решения для отправки уведомлений

На сервере SharePoint приемник событий с элементами списка, который прикреплен к списку SharePoint RFQ, сработает тогда, когда какой-либо элемент в списке будет создан или обновлен. Приемник событий с элементами списка инициирует отсылку всплывающего уведомления и уведомления-«плитки» в приложение Windows 8, выполняя запрос в локальную или «облачную» службу, который, в свою очередь, вызывает Windows Push Notification Service (WNS). Затем WNS передает уведомления в приложение Windows 8.

Хотя этот пример использует приемник событий с элементами списка для инициирования передачи уведомлений, вы также можете задействовать запуск задания по расписанию или пользовательский код, вызываемый веб-частью или другим компонентом. Например, можно вызвать службу ASP.NET MVC 4 для отсылки уведомления из рабочего процесса.

Необходима промежуточная служба между приемником событий с элементами списка и WNS, потому что библиотеки WNS API подчиняются. NET 4 Framework. Таким образом, никакие сборки, развернутые на SharePoint, не могут ссылаться на эти библиотеки. Это означает, что на библиотеки WNS нельзя ссылаться и вызывать их напрямую из приемника событий с элементами списка.

Чтобы обойти это ограничение, я развернул службу ASP.NET MVC 4. Служба ASP.NET MVC 4 использует библиотеки WNS, поэтому она как раз подходит. Вы можете развернуть службу и на других технологиях, которые поддерживают библиотеки WNS (например, ASP.NET Web API). Служба ASP.NET MVC 4 (или любая другая) может быть размещена либо локально (в компании), либо в «облаке» – на ваш выбор.

Аутентификация

Помните, что в этом сценарии не только система Windows 8 получает уведомления, когда данные изменяются в SharePoint, но и сотрудники просматривают RFQ и создают сметы с использованием приложения Windows 8. Это означает, что приложение Windows 8 должно аутентифицироваться на сервере SharePoint, прежде чем оно сможет запросить список RFQ.

Приложение Windows 8 использует один из двух подходов к аутентификации на сервере SharePoint, в зависимости от того, как сотрудник зарегистрировался на компьютере Windows 8 и как он подсоединяется к сети, к которой относится сервер SharePoint 2010. Когда приложение Windows 8 работает на компьютере, на котором пользователь зарегистрировался с учетными данными домена и подсоединенного к сети домена, данные аутентификации передаются автоматически на сервер SharePoint. Когда приложение Windows 8 работает на компьютере, на котором пользователь не зарегистрирован с учетной записью домена и не подсоединен к сети домена, приложение Windows 8 выдает ему запрос на учетные данные. Для обеспечения этого варианта никакого специального кода не требуется. Приложение Windows 8 автоматически запрашивает учетные данные, когда это необходимо.

Уведомления

Теперь давайте вернемся к началу процесса, когда новый элемент списка добавляется к RFQ, и рассмотрим код для отсылки уведомлений. Во-первых, приемник событий с элементами списка создает один или несколько URL, чтобы вызвать службу ASP.NET MVC 4, которая, в свою очередь, вызовет WNS для передачи уведомлений. Эти URL содержат информацию, которая помогает службе ASP.NET MVC 4 определить тип отсылаемого уведомления и то, какие данные должны быть включены в него. В зависимости от того, какие изменения внесены в список RFQ, приемник событий с элементами списка создает один или несколько подходящих URL для передачи всплывающего уведомления или уведомления-«плитки» в приложение Windows 8. Например, когда добавляется новый элемент к списку RFQ, код в листингах 1, 2 и 3 выполняет метод ItemAdded для элемента списка в приемнике событий. Этот код создает одно всплывающее уведомление и три уведомления-«плитки».

Заметьте, что событие ItemUpdated в приемнике событий элементов списка следует тому же самому примеру для отсылки уведомлений. Однако мы не будем подробно останавливаться на этом в данной статье. Событие ItemUpdated оценивает столбец статуса в списке RFQ и отсылает уведомления об обновлении статуса RFQ сотрудникам. Событие ItemUpdated также отсылает обновленную информацию о продажах, когда покупатель принимает условия в SOW. Я подчеркиваю это для того, чтобы показать, что вы можете применять уведомления для нескольких типов событий, которые происходят со списками SharePoint.

Всплывающее уведомление. Первый тип уведомлений – это всплывающее уведомление (рисунок 2).

 

Пример всплывающего уведомления
Рисунок 2. Пример всплывающего уведомления

Уведомление оповещает сотрудника о начале задания (в данном случае – создании сметы). Всплывающие уведомления появляются на экране Windows 8 Start. В листинге 1 показан код, который генерирует URL для отсылки всплывающего уведомления через службу ASP.NET MVC 4.

Уведомление-«плитка». Второй тип уведомления – это уведомление-«плитка». На рисунке 3 показаны три таких уведомления. Посмотрите на первую «плитку», которая информирует сотрудников о том, что в системе есть новая задача. Код, который генерирует это уведомление-«плитку», показан в листинге 2.

 

Пример уведомлений-«плиток»
Рисунок 3. Пример уведомлений-«плиток»

Уведомления появляются на «плитке», соответствующей приложению Windows 8, которое их выводит на экране Windows 8 Start.

Центральное уведомление-«плитка» на рисунке 3 предоставляет пользователям самую важную информацию. Код, генерирующий это уведомление-«плитку», имеет доступ к файлу Excel, который хранится на сервере SharePoint и считывает ежегодные доходы (листинг 3).

Код, который генерирует нижнее уведомление-«плитку», показанное на рисунке 3, имеет доступ к файлу Excel, хранящемуся на сервере SharePoint и считывающему информацию о ежеквартальных доходах (листинг 4).

HttpWebRequest. Вероятно, вы заметили строку кода, которая содержит Util.PostData(url) в листингах 1, 2, 3 и 4. Чтобы вызвать службу ASP.NET MVC 4 и передать уведомление WNS, приемник событий с элементами списка делает запрос HttpWebRequest внутри этого метода (листинг 5).

Когда служба ASP.NET MVC 4 получает запрос, она проверят URL, чтобы определить, какой тип уведомления нужно послать, и вызывает соответствующий код для отсылки уведомления WNS (листинг 6).

Заметьте, что прежде чем использовать WNS, вы должны зарегистрировать свое приложение и получить учетные данные для своей службы. Процесс регистрации приложения при помощи Windows Store Dashboard и другие инструкции описаны в MSDN (http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh913756.aspx). Загляните в мой блог, там есть ссылки на образцы кодов MSDN, которые также иллюстрируют шаблон для SharePoint 2013 (http://toddbaginski.com/blog/).

По мере того как я демонстрирую образцы кодов, вы увидите, что это сравнительно несложный шаблон – код совсем простой. Самое важное –понять и обойти ограничения, которые ассоциируются с библиотеками WNS (о них я рассказывал выше).

В зависимости от применяемого типа уведомления вызывается один из двух методов в службы ASP.NET MVC 4, чтобы послать уведомление WNS. Оба метода следуют шаблону, задокументированному на сайте MSDN (http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh913756.aspx). Давайте рассмотрим его.

Метод SendToastNotification. Метод SendToastNotification (листинг 7) отсылает всплывающие уведомления. Первое, что делает метод — это вызов метода GetAccessToken. Метод GetAccessToken посылает ID клиента и секретный ключ службе Windows Live ID Service и возвращает токен доступа для соединения с WNS. ID клиента и секретный ключ предоставляются тогда, когда вы регистрируете свое приложение на Windows Store Dashboard.

Переменная channelUrl (листинг 7) обращается к каналу, который вы установили с WNS. Канал позволяет приложению (в данном случае, службе ASP.NET MVC 4) взаимодействовать с WNS.

Данные переменной определяет часть пакета данных, которые отсылаются на WNS через POST HttpWebRequest (листинг 7). Данные переменной комбинируются с названием и конвертируются в массив байтов, прежде чем пакет данных отсылается WNS. WNS использует пакет данных для передачи уведомлений приложению Windows 8. Заметьте, что токен доступа добавляется к заголовкам запроса для его аутентификации.

Метод SendTileNotification. Метод SendTileNotification (листинг 8) отсылает уведомления-«плитки». Он следует такому же шаблону, как и метод SendToastNotification, за исключением того, что он отсылает уведомления-«плитки». Обратите внимание, что этот метод поддерживает отправку нескольких уведомлений-«плиток» через одну точку входа. Параметр tileNotificationType определяет, какое уведомление-«плитка» отсылается.

Переменные cell1, cell2 и cell3 в листинге 8 представляют данные из рабочей книги Excel, которые пересылаются через URL, назначенный соответствующему приемнику событий с элементами списка, для вызова службы ASP.NET MVC 4. Их значения являются частью уведомлений на «плитке», показанных на рисунке 3, которые представляют финансовые данные.

Наконец, переменная imageUrl в листинге 8 включает путь к образу на сервере SharePoint, который представляет собой значок диаграммы, появляющийся на уведомлении-«плитке», как на рисунке 3.

Запросы

Теперь, когда я показал, каким образом отсылать уведомления, давайте вернемся к запросу данных SharePoint из приложения Windows 8. Когда в приложении Windows 8 создается новая задача по сделке, общее значение сметы сохраняется в столбце доходов в списке RFQ. Столбец LeadStatusValue обновляется значением со статусом «создан». Это действие запускает метод ItemUpdated в приемнике событий с элементами списка, который в свою очередь посылает сотрудникам уведомления через WNS. Таким образом сотрудники узнают, что эта часть процесса RFQ завершена. Приложение Windows 8 использует SharePoint 2010 ListData из API протокола Representational State Transfer (REST) для обновления столбца значений. Листинг 9 демонстрирует, как этот API вызывается из JavaScript в приложении Windows 8.

Вы можете производить и другие операции при помощи SharePoint 2010 ListData REST API для выполнения всего набора операций создания, чтения, обновления и удаления в списках SharePoint из приложений Windows 8.

Уведомления правят бизнесом

Вы можете комбинировать SharePoint, Windows 8 и WNS для создания линейки бизнес-приложений следующего поколения, которые сообщают пользователям новейшую информацию и помогают предприятиям работать максимально эффективно. Уведомления могут поступать на пользовательский компьютер или мобильное устройство (через приложения Windows Phone), что делает их универсальными. В данной статье представлен сценарий, уведомляющий сотрудников о статусе RFQ и задачах, которые должны быть завершены в ходе процесса, но шаблон может быть применен и во многих других ситуациях.

Листинг 1. Код, который генерирует всплывающее уведомление через службу ASP.NET MVC 4

string toastTitle = Convert.ToString(properties.AfterProperties[«Title»]);
string company = Convert.ToString(properties.AfterProperties[«Company»]);
string toast = string.Format(«Please create the estimate for the {0}
project for company {1}.», toastTitle, company);
string url = PostUrl + string.Format(«?itemTitle={0}¬Type={1}»,
Util.HttpEncode(toast), NotificationType.Toast);
Util.PostData(url);

Листинг 2. Код, который генерирует уведомление о новой задаче через службу ASP.NET MVC 4

string tileTitle = «A new sales lead has been entered into the system»;
url = PostUrl + string.Format(«?itemTitle={0}¬Type={1}&tileType={2}&imageUrl={3}»,
Util.HttpEncode(tileTitle), NotificationType.Tile, TileType.TileWideText03,
Util.HttpEncode(properties.WebUrl + «/Shared%20Documents/star.jpg»));
Util.PostData(url);

Листинг 3. Код, генерирующий уведомление о ежегодных доходах через службу ASP.NET MVC 4

tileTitle = «Yearly Rev»;
string imageUrl = properties.WebUrl + Util.GetYearlyRevImage(company);
url = PostUrl +
string.Format(«?itemTitle={0}¬Type={1}» +
«&tileType={2}&imageUrl={3}&cell1={4}» +
«&cell2={5}&cell3={6}», Util.HttpEncode(tileTitle), NotificationType.Tile,
TileType.TileWideImage, Util.HttpEncode(imageUrl),
Util.GetACellValueFromExcel(company, «2010», web),
Util.GetACellValueFromExcel(company, «2011», web),
Util.GetACellValueFromExcel(company, «2012», web));
Util.PostData(url);

Листинг 4. Код, генерирующий уведомление об информации о ежеквартальных доходах через службу ASP.NET MVC 4

tileTitle = «Quarterly Rev»;
imageUrl = properties.WebUrl + Util.GetQuarterlyRevImage(company);
url = PostUrl +
string.Format(«?itemTitle={0}¬Type={1}» +
«&tileType={2}&imageUrl={3}&cell1={4}&cell2={5}&cell3={6}»,
Util.HttpEncode(tileTitle), NotificationType.Tile,
TileType.TileWideSmallImageAndText01, Util.HttpEncode(imageUrl),
Util.GetACellValueFromExcel(company, «2011 Q4», web),
Util.GetACellValueFromExcel(company, «2012 Q1», web),
Util.GetACellValueFromExcel(company, «2012 Q2», web));
Util.PostData(url);

Листинг 5. Вызов службы ASP.NET MVC 4 из приемника событий с элементами списка

public static void PostData(string purl)
{
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(purl);
req.Timeout = 90000;
req.Method = «Post»;
req.ContentType = «application/x-www-form-urlencoded»;
req.ContentLength = 0;
HttpWebResponse rep = (HttpWebResponse)req.GetResponse();
}
catch (Exception ex)
{
}
}

Листинг 6. Определение типа уведомления для подготовки вызова WNS

[HttpPost]
public ActionResult SendNotification()
{
try
{
ChannelURL = Util.GetConfigValue(«channelUrl»);
NotificationType notificationType =
Util.GetNotificationType(Convert.ToString(Request[«notType»]));
string title =Util.HttpDecode(Convert.ToString(Request[«itemTitle»]));
if (notificationType == NotificationType.Tile)
{
TileType tileType = Util.GetTileType(Convert.ToString(Request[«tileType»]));
string imageUrl = Convert.ToString(Request[«imageUrl»]);
Util.SendTileNotification(title, imageUrl, ChannelURL, tileType);
}
else
{
Util.SendToastNotification(title, ChannelURL);
}
}
catch
{ }
return new EmptyResult();
}

Листинг 7. Отправка всплывающего уведомления через WNS

public static void SendToastNotification(string title, string channelUrl)
{
string accessToken = GetAccessToken();
var subscriptionUri = new Uri(channelUrl);
var request = (HttpWebRequest)WebRequest.Create(subscriptionUri);
request.Method = «POST»;
request.ContentType = «text/xml»;
request.Headers = new WebHeaderCollection();
request.Headers.Add(«X-WNS-Type», «wns/toast»);
request.Headers.Add(«Authorization», «Bearer» + accessToken);
string data = «}» +
«}» +
«{0}»;
byte[] notificationMessage = Encoding.Default.GetBytes(string.Format(data, title));
request.ContentLength = notificationMessage.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
var response = (HttpWebResponse)request.GetResponse();
}

Листинг 8. Отправка уведомлений-«плиток» через WNS

public static void SendTileNotification(string title, string imageUrl, string channelUrl,
TileType tileNotificationType)
{
var subscriptionUri = new Uri(channelUrl);
string accessToken = GetAccessToken();
var request = (HttpWebRequest)WebRequest.Create(subscriptionUri);
request.Method = «POST»;
request.ContentType = «text/xml»;
request.Headers = new WebHeaderCollection();
request.Headers.Add(«X-WNS-Type», «wns/tile»);
string data = string.Empty;
if (tileNotificationType == TileType.TileWideText03)
{
request.Headers.Add(«X-WNS-Tag», «aa11»);
data = string.Format(«» +
«» +
«» +
«{0}» +
«» +
«», title);
}
string cell1 = Convert.ToString(System.Web.HttpContext.Current.Request[«cell1»]);
string cell2 = Convert.ToString(System.Web.HttpContext.Current.Request[«cell2»]);
string cell3 = Convert.ToString(System.Web.HttpContext.Current.Request[«cell3»]);
if (tileNotificationType == TileType.TileWideImage)
{
request.Headers.Add(«X-WNS-Tag», «aa22»);
imageUrl = «/img/chart.png»;
data = string.Format(«» +
«» +
«» +
«» +
«{1}» +
«2010: ${2}» +
«2011: ${3}» +
«2012: ${4}» +
«» +
«» +
«», imageUrl, title, cell1, cell2, cell3);
}
if (tileNotificationType == TileType.TileWideSmallImageAndText01)
{
request.Headers.Add(«X-WNS-Tag», «aa33»);
imageUrl = «http:///img/chart.png»;
data = string.Format(«» +
«» +
«» +
«» +
«{1}» +
«2011 Q4: ${2}» +
«2012 Q1: ${3}» +
«2012 Q2: ${4}» +
«» +
«» +
«», imageUrl, title, cell1, cell2, cell3);
}
request.Headers.Add(«X-WNS-TTL», «600000»);
request.Headers.Add(«Authorization», «Bearer» + accessToken);
byte[] notificationMessage = Encoding.Default.GetBytes(data);
request.ContentLength = notificationMessage.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
var response = (HttpWebResponse)request.GetResponse();
}

Листинг 9. Использование данных SharePoint ListData API для обновления элемента списка SharePoint

function putSharePointData(item, handle) {
var spListItemRestSrvUri =
WinJS.Resources.getString(«intranet.contoso.com»).value +
«/_vti_bin/listdata.svc/RFQ(» + item.Id + «)",
spItem = {
Revenue: item.Revenue,
LeadStatusValue:»Estimate Created«
},
etag = item._etag;
WinJS.xhr({
url: spListItemRestSrvUri,
type:»POST«,
data: JSON.stringify(spItem),
headers: {
accept: 'application/json',
»Content-Type«: 'application/json; charset=utf-8',
»If-Match«: etag,
»X-HTTP-Method«: "MERGE» }
}).
then(
function complete(result) {
handle();
},
function error(error) {
logger.log(«Not able to put data to SharePoint», «error»,
«spData.js», error.status, error.statusText);
});
}