Все большее количество компаний внедряет решения Microsoft Dynamics CRM 4.0 и обнаруживает необходимость в создании внешних приложений, которые можно интегрировать с существующим API на основе веб-сервисов.
Создание приложений Silverlight для взаимодействия с Microsoft Dynamics CRM 4.0 (далее CRM 4.0 для краткости) может оказаться непростой задачей из-за асинхронной природы вызовов Silverlight и ее неспособности напрямую вызывать веб-сервисы CRM 4.0. В этой статье подробно поясняется, как создать приложение Silverlight, которое может читать и записывать данные через CRM 4.0 Web service API.
Обзор решения
Silverlight 4 и CRM 4.0 — мощные технологии, но их не так-то просто интегрировать. Я расскажу о том, что стоит за этой интеграцией, исследовав асинхронное взаимодействие между Silverlight и CRM 4.0 Web service API.
В типичных приложениях, не имеющих отношения к Silverlight, вызов веб-сервиса осуществляется синхронно: он вызывается, и приложение ждет, пока не будет получен ответ. В течение этого времени пользователь не может взаимодействовать с приложением и должен ждать окончания вызова. В асинхронном приложении, например на основе Silverlight, вызов сервиса выдается, но приложение остается полностью функциональным даже до получения ответа. Это значительно улучшает удобство использования приложения, но предъявляет более высокие требования к разработчику.
Чтобы понять, как осуществляется это взаимодействие, я представлю несколько примеров. Для начала мы посмотрим, как настроить приложение Silverlight, и пошагово пройдем все операции, необходимые для взаимодействия с веб-сервисом, который будет действовать как оболочка CRM 4.0 API. Затем мы изучим детали работы с CRM 4.0 API и обсудим, как читать и записывать данные с использованием оболочки — веб-сервиса. Мы поработаем с базовой сущностью System User в CRM 4.0, а также рассмотрим работу с динамическими сущностями. Наконец, вы узнаете, как обращаться с наборами результатов, возвращаемых в Silverlight. В итоге вы сможете легко интегрировать свои приложения Silverlight с CRM 4.0.
Создание приложения Silverlight 4
Чтобы сконфигурировать приложение Silverlight на взаимодействие с CRM 4.0, потребуется выполнить ряд операций. Хотя можно ссылаться на CRM 4.0 SDK или Web service API прямо из проекта Silverlight, большинство интерфейсов и методов на самом деле из кода вызываться не будет. Для взаимодействия с CRM 4.0 API нужно создать оболочку в виде веб-сервиса. Этот веб-сервис станет посредником при вызовах между приложением Silverlight и CRM 4.0 API в формате, который будет понятен Silverlight. Оболочку в виде веб-сервиса можно добавить прямо в приложение SilverlightCRMDemo.Web.
Начните с создания нового решения Silverlight в Visual Studio 2010 и назовите его CRM40SilverlightDemo. При создании приложения Silverlight в Visual Studio всегда генерируются два проекта. Один является базовым приложением Silverlight, а второй — приложением ASP.NET, встраивающим приложение Silverlight в веб-страницу. Это приложение ASP.NET также будет хостом для веб-сервиса, который будет взаимодействовать с CRM 4.0 API. Приложение Silverlight будет ссылаться на этот веб-сервис через Service Reference.
Чтобы создать оболочку в виде веб-сервиса, добавьте новый веб-сервис в приложение ASP.NET и назовите его CrmServiceWrapper. В этом примере нужно добавить в сервис два веб-метода: один — для получения CRM-данных, а второй — для их отправки. На рис. 1 показано, как на данном этапе должны выглядеть эти методы. Когда вы добьетесь успешного взаимодействия приложения Silverlight с этим сервисом-оболочкой, вы модифицируете эти методы для реального вызова CRM 4.0 API.
Рис. 1. Заглушки веб-методов
public class CrmServiceWrapper : System.Web.Services.WebService
{
[WebMethod]
public string GetCRMData()
{
return "This is the stubbed return for retrieving";
}
[WebMethod]
public string PostCRMData()
{
return "This is the stubbed return for posting data";
}
}
После включения веб-сервиса в приложение ASP.NET самый простой способ добавить ссылку на него из приложения Silverlight — запустить его в отладочном режиме и получить URL, с которого отладчик запускает приложение ASP.NET (вы можете скопировать URL из всплывающего окна браузера). Теперь вы можете добавить новую Service Reference с именем CrmServiceReference в приложение Silverlight и вставить этот URL. Все релевантные конфигурационные файлы и код будут автоматически скорректированы. Если вы решите не делать этого, вам придется иметь дело с исключениями ссылок между доменами и немного повозиться с настройкой, чтобы успешно отладить свое приложение.
Теперь, когда у вас есть ссылка, можно приступать к реальному кодированию в приложении Silverlight. Код должен подключать обработчик событий для каждого веб-метода и создавать два метода для обработки данных по завершении вызовов этих веб-методов. Код, показанный на рис. 2, можно напрямую вставить в файл MainPage.xaml.cs приложения Silverlight. Запуск этого файла приведет к одновременному выполнению обоих методов.
Рис. 2. Добавление кода в MainPage.xaml.cs
using CRM40SilverlightDemo.CrmServiceReference;
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
// Call the GetCRMData Web method.
CrmServiceWrapperSoapClient proxyGet =
new CrmServiceWrapperSoapClient();
proxyGet.GetCRMDataCompleted +=
new EventHandler<GetCRMDataCompletedEventArgs>(proxy_GetCRMDataCompleted);
proxyGet.GetCRMDataAsync();
// Call the PostCRMData Web method.
CrmServiceWrapperSoapClient proxyPost = new CrmServiceWrapperSoapClient();
proxyPost.PostCRMDataCompleted +=
new EventHandler<PostCRMDataCompletedEventArgs>(proxy_PostCRMDataCompleted);
proxyPost.PostCRMDataAsync();
}
// Called asynchronously when the GetCRMData Web method returns data.
void proxy_GetCRMDataCompleted(object sender, GetCRMDataCompletedEventArgs e)
{
// Do something with the data returned.
string result = e.Result.ToString();
}
// Called asynchronously when the PostCRMData Web method returns data.
void proxy_PostCRMDataCompleted(object sender, PostCRMDataCompletedEventArgs e)
{
// Do something with the data returned.
string result = e.Result.ToString();
}
}
Убедившись, что ваше приложение Silverlight выполняется без ошибок и получает данные от веб-сервиса, вы можете переключиться на вызовы CRM 4.0 API. Все эти вызовы будет исходить из уже созданных веб-методов GetCRMData и PostCRMData оболочки веб-сервиса.
Взаимодействие с CRM 4.0 API
Через CRM 4.0 доступны два основных веб-сервиса: CRMService и MetadataService. На эти веб-сервисы, в целом, можно ссылаться из любого проекта (но они не дают особой функциональности, если вы ссылаетесь на них из приложения Silverlight). Самый распространенный и эффективный способ работы с этим API — использование Microsoft Dynamics CRM SDK (можно скачать по ссылке bit.ly/6M3PvV). SDK содержит множество классов и методов и упрощает взаимодействие между .NET-кодом и веб-сервисами CRM 4.0. В этом разделе вы научитесь взаимодействовать с API из оболочки веб-сервиса, используя SDK.
Первый шаг — добавление ссылок на соответствующие сборки CRM SDK. В приложении ASP.NET, где размещается оболочка в виде веб-сервиса, добавьте ссылки на две сборки SDK: microsoft.crm.sdk.dll и microsoft.crm.sdktypeproxy.dll. После этого включите необходимые директивы в начало страницы CrmServiceWrapper.asmx:
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;
Следующий шаг — напишите код для создания экземпляра CRM-сервиса, который позволит вам подключаться к экземпляру CRM 4.0. Этот код будет использоваться веб-методами GetCRMData и PostCRMData, поэтому его нужно выделить в собственный метод. Этот метод (рис. 3) требует двух ключевых полей: названия организации для вашего экземпляра CRM 4.0 и URL основного CRM-сервиса (находится по адресу /MSCRMServices/2007/crmservice.asmx). Заметьте, что эти поля лучше всего размещать в конфигурационном файле для упрощения их модификации после компиляции кода.
Рис. 3. Метод GetCRMService
static public CrmService GetCRMService()
{
CrmService service = new CrmService();
CrmAuthenticationToken token =
new Microsoft.Crm.Sdk.CrmAuthenticationToken();
token.OrganizationName = "Contoso";
service.Url = "http://localhost:5555/MSCRMServices/2007/crmservice.asmx";
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.CrmAuthenticationTokenValue = token;
return service;
}
Запрос CRM-данных
Теперь вы можете переключить свое внимание на запрос данных от CRM 4.0. Важно знать, что в CRM 4.0 есть два типа сущностей: базовые системные и собственные. С базовыми системными сущностями работать немного легче, чем с собственными сущностями. По умолчанию все свойства базовых сущностей можно получать через строго типизированные объекты в C#. Собственные сущности, как правило, запрашиваются в виде Dynamic Entities, хотя в качестве альтернативы их тоже можно обрабатывать как строго типизированные объекты. Я продемонстрирую запрос данных от двух типов сущностей.
Пример запроса базовой системной сущности (System User) показан на рис. 4. Этот код заменяет веб-метод с тем же именем, который был в виде заглушки ранее в этой статье. В новом коде, который запрашивает от CRM 4.0 всех системных пользователей, вы заметите несколько важных вещей. Во-первых, тип объекта, с которым мы имеем дело, — systemuser. Все базовые сущности имеют свои типы. Во-вторых, возвращаемый результат является строковым представлением XML-документа.
Рис. 4. Запрос сущности System User
[WebMethod]
public string GetCRMData()
{
// This will return all users in CRM in a single XML structure.
StringBuilder xml = new StringBuilder();
CrmService service = GetCRMService();
QueryExpression query = new QueryExpression();
query.EntityName = "systemuser";
query.ColumnSet = new AllColumns();
RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
retrieve.Query = query;
retrieve.ReturnDynamicEntities = false;
RetrieveMultipleResponse retrieved =
(RetrieveMultipleResponse)service.Execute(retrieve);
xml.Append("<Users>");
for (int i = 0; i <
retrieved.BusinessEntityCollection.BusinessEntities.Count; i++)
{
systemuser user =
(systemuser)retrieved.BusinessEntityCollection.BusinessEntities[i];
// Create a string represenation to return to Silverlight app.
xml.Append("<User");
xml.Append(" FirstName ='" + user.firstname + "'");
xml.Append(" LastName = '" + user.lastname + "'");
xml.Append(" SystemUserId = '" + user.systemuserid.ToString() + "'");
xml.Append(" JobTitle = '" + user.jobtitle + "'");
xml.Append("/>");
}
xml.Append("</Users>");
return xml.ToString();
}
Вы обнаружите, что варианты возврата данных в Silverlight весьма ограничены. Например, вы не можете получить BusinessEntityCollection, так как Silverlight не позволяет напрямую работать с этим API. Также есть ограничения на передачу XML в Silverlight через веб-сервис. Поэтому в итоге лучший вариант — простая строка.
Запрос собственных сущностей может оказаться посложнее. Наиболее распространенный способ получения данных — использование Dynamic Entity для извлечения результатов (пример такого рода показан на рис. 5). Проблема с этим подходом в том, как работать со специфическими атрибутами в фильтрах внутри выражений запроса. И хотя все это возможно, особой помощи от IntelliSense не ждите.
Рис. 5. Получение данных с использованием Dynamic Entity
public static DynamicEntity GetCRMEntity(
CrmService tmpService, String entityId, String entityName)
{
DynamicEntity crmEntity = null;
TargetRetrieveDynamic targetRetrieve = new TargetRetrieveDynamic();
// Set the properties of the target.
targetRetrieve.EntityName = entityName;
targetRetrieve.EntityId = new Guid(entityId);
// Create the request object.
RetrieveRequest retrieve = new RetrieveRequest();
// Set the properties of the request object.
retrieve.Target = targetRetrieve;
retrieve.ColumnSet = new AllColumns();
// Retrieve as a DynamicEntity.
retrieve.ReturnDynamicEntities = true;
// Execute the request.
RetrieveResponse retrieved = (RetrieveResponse)tmpService.Execute(retrieve);
// Extract the DynamicEntity from the request.
DynamicEntity entity = (DynamicEntity)retrieved.BusinessEntity;
crmEntity = entity;
return crmEntity;
}
Подход с Dynamic Entity, вероятно, самый распространенный, но, если вы хотите полностью видеть структуру своей сущности в Visual Studio и взаимодействовать с ней так же, как и со стандартной сущностью, вы можете создать прокси для CrmService. Во многих случаях это может дать более широкие возможности в разработке и обеспечить большую гибкость в том, как пишется код. Прокси — это не более чем C#-файл, сгенерированный на основе самого нового экземпляра CrmService WSDL. Чтобы создать класс прокси для основного сервиса CrmService, откройте командную строку Visual Studio и введите следующее, заменив URL ссылкой на свою страницу crmservice.asmx:
wsdl.exe /out:CrmSdk.cs /namespace:CRM40SilverlightDemo.WebReferences.CrmSdkhttp://localhost:5555/mscrmservices/2007/crmservice.asmx?wsdl
Эта команда создаст C#-файл CrmSdk.cs в каталоге, откуда вы запустили wsdl.exe. Этот файл нужно добавить в ваш проект. После этого вы можете работать с любой собственной сущностью точно так же, как с базовыми системными сущностями. Если сущность изменилась, просто обновите свой C#-файл прокси, и новые атрибуты (или другие модификации) станут доступными. В нашем текущем упражнении C#-файл прокси не используется.
Обновление данных в CRM 4.0
Разобравшись в том, как получать данные от CRM 4.0, вы сможете понять и то, как их передавать. Код на рис. 6 показывает, как обновить запись системного пользователя. Для этого нужно передать два свойства: уникальный идентификатор записи CRM 4.0 и свой ник. Чтобы отправить эти строки, в файле MainPage.xaml.cs нужно модифицировать одну строку кода:
proxyPost.PostCRMDataAsync("f04b02d9-ad5f-e011-a513-000c29330bd5","My Nickname");
Заметьте, что этот идентификатор «зашит» в вызов метода PostCRMData. На практике вы предпочтете создать механизм для динамического получения идентификаторов.
Рис. 6. Отправка данных в CRM 4.0
[WebMethod]
public string PostCRMData(string userId, string nickname)
{
CrmService service = GetCRMService();
Key kid = new Key();
kid.Value = new Guid(userId);
systemuser entity = new systemuser();
entity.systemuserid = kid;
entity.nickname = nickname;
service.Update(entity);
return "success";
}
Обработка результатов в Silverlight
К этому моменту решение должно извлекать данные из CRM 4.0 и отправлять их. Однако мы пока ничего не делали со строковыми результатами, возвращаемыми в Silverlight. Метод GetCRMData вызовращает строку данных, содержащую XML-документ со всеми пользовательскими записями, но что делать с этими данными? В зависимости от конкретного элемента управления вы можете напрямую связать его с XML или предварительно разобрать возвращаемый XML и работать с индивидуальными элементами данных.
Пример разбора результатов в цикле показан на рис. 7. Этот код демонстрирует, как загрузить строку в XML-документ и перебрать данные. Для работы с XML-документами в Silverlight самая универсальная функциональность заключена в классе XDocument. Для его использования нужно добавить в свой проект Silverlight ссылку на System.Xml.Linq.
Рис. 7. Работа с XDocument
void proxy_GetCRMDataCompleted(object sender, GetCRMDataCompletedEventArgs e)
{
XDocument xDoc = XDocument.Parse(e.Result);
string firstName;
string lastName;
string ID;
string title;
// Loop through the results.
foreach (XElement element in xDoc.Descendants("User"))
{
firstName = GetAttributeValue(element, "FirstName");
lastName = GetAttributeValue(element, "LastName");
ID = GetAttributeValue(element, "SystemUserId");
title = GetAttributeValue(element, "JobTitle");
}
}
private string GetAttributeValue(XElement element, string strAttributeName)
{
if (element.Attribute(strAttributeName) != null)
{
return element.Attribute(strAttributeName).Value;
}
return string.Empty;
}
Безграничные возможности
При интеграции эти двух технологий вы получаете безграничные возможности. Некоторые шаги, которые вы наверняка захотите предпринять, — разобраться в подходах к обработке исключений (многие элементы управления Silverlight скрывают исключения, поэтому в каждом случае потребуется индивидуальный подход) и интеграции с различными элементами управления. Независимо от выбранного вами направления дальнейшей работы у вас теперь есть все, что нужно для создания решений Silverlight, способных читать и записывать данные CRM 4.0.