Пример разработки кастомного бизнес-процесса
Разработка кастомных бизнес-процессов дает возможность нам объединить требования к системе с возможностями бизнес-процессов Microsoft CRM 4.0. Основными этими возможностями являются: настраиваемость через визуальный пользовательский интерфейс, многократность использования и т.д. Что делает реализацию той или иной задачи через бизнес-процессы весьма привлекательной.
Для примера разработки кастомного бизнес-процеса, рассмотрим такую часто встречающуюся заезжанную 🙂 задачу, как автонумирация записей. Как это будет выглядеть: поскольку каждая запись CRM уже сопровождается уникальным идентификатором, то велосипед изобретать не нужно – достаточно получить этот идентификатор (GUID). А чтобы как-то «отделить» его от GUID’а, добавим ему префикс «БП-» (сокращение от Бизнес-партнер — именно для него будем разрабатывать бизнес-процесс). Т.е. в конечном итоге наш номер будет иметь такой вид: «БП-» + GUID.
Настройка CRM
Прежде всего необходимо внести изменения в CRM – создайте в объекте Бизнес-партнер новой поле для хранения нашего номера:
- Имя: autonumber;
- Тип: текстовое.
Вынесите его на форму и сделайте доступным только для чтения.
Разработка бизнес-процесса
Для разработки кастомных бизнес-процессов используются следующие компоненты и инструменты:
- Microsoft Visual Studio 2005/2008 (для 2005 Вам возможно понадобятся установить Visual Studio 2005 extensions for .NET Framework 3.0 (Windows Workflow Foundation));
- Windows Workflow Foundation;
- Microsoft Dynamics CRM 4.0 SDK (скачайте и установите его);
- Plugin Registration Tool.
Приступим…
- Откройте Visual Studio (я буду показывать на 2008) и перейдите File — New — New Project. Выберите новый C#-проект с типом Workflow и шаблоном Workflow Activity Library;
- Откроется визуальный редактор Workflow – он нам не нужен – закройте его. Щелкните правой кнопкой мыши по файлу *.cs в Solution Explorer и выберите Code — таким образом Вы переключитесь на представление сгенерированного кода. Из этого кода видно, что сгенерированный класс работает в контексте SequenceActivity, которая в свою очередь основана на библиотеке Windows Workflow Foundation. Поэтому опеределение кастомного бизнес-процесса должно находится внутри этого класса.
Чтобы шаг кастомного бизнес-процесса был доступен через пользовательский Microsoft CRM 4.0, Вы должны объявить класс с атрибутом CrmWorkflowActivity и передать в качестве его параметров Имя шага и Имя группы, в которую он входит. Затем необходимо переопределить метод Execute, который вызывается во время выполнения бизнес-процесса, и выполнить какие-либо необходимые Вам действия. При этом метроду Execute передается ActivityExecutionContext, чтобы получить доступ к контексту бизнес-процесса, который содержит информацию о данном (выполняемом) экземпляре бизнес-процесса. Из контекста Вы можете получить информацию о primary entity (название, id, pre- и post-снимки) задействованного в бизнес-процесса, метод CreateCrmService, который возвращает ссылку на CrmService и т.д.
В основном, это все, что Вы должны сделать, чтобы внедрить кастомный бизнес-процесс в Microsoft CRM 4.0; - Добавьте ссылки на Microsoft.Crm.Sdk.dll и Microsoft.Crm.SdkTypeProxy.dll (найти их Вы сможете в папке \Bin, с установиленным Microsoft Dynamics CRM 4.0 SDK);
- Замените существующий код на такой:
using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Collections; using System.Drawing; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Design; using System.Workflow.Runtime; using System.Workflow.Activities; using System.Workflow.Activities.Rules; using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; using Microsoft.Crm.Workflow; using Microsoft.Crm.Workflow.Activities; using Microsoft.Crm.Sdk.Query; namespace Number { // Задаем имя (отображаемое на форме) кастомного шага бизнес-процесса, и имя группы в которую он входит [CrmWorkflowActivity("Автонумерация", "Мои бизнес-процессы")] // Класс кастомного workflow происходит из SequenceActivity public partial class Activity1 : SequenceActivity { // Создаем кастомные поля на форме кастомного шага бизнес процесса /* Свойство DependencyProperty используется, чтобы создать входной параметр. Оно объявляется с атрибутом CrmInput, чтобы получить доступ к параметру в пределах формы бизнес-процесса CRM. Параметр CrmReferenceTarget указывает на объект, который можно подставлять в это поле. */ // Задаем имя поля, его тип и имя класса к которому он относится public static DependencyProperty objectIDProperty = DependencyProperty.Register("objectID", typeof(Lookup), typeof(Activity1)); [CrmInput("objectID")] [CrmReferenceTarget("account")] public Lookup objectID { get { return (Lookup)base.GetValue(objectIDProperty); } set { base.SetValue(objectIDProperty, value); } } // Метод Execute вызывается бизнес-процессом во время работы, чтобы выполнить шаг // executionContext - контекст шага protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { // Получаем контект сервиса IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService)); IWorkflowContext context = contextService.Context; // Используем контекст сервиса, чтобы создать экземпляр класса CrmService ICrmService crmService = context.CreateCrmService(); // Получаем GUID записи, находящейся в кастомном поле, созданного на форме шага бизнес-процесса Guid guidID = new Guid(this.objectID.Value.ToString()); // Добавляем к GUID'у префикс string Number = "БП-" + guidID; // Создаем запрос, чтобы вернуть запись (в виде DynamicEntity) для которой выполнятеся бизнес-процесс TargetRetrieveAccount target = new TargetRetrieveAccount(); target.EntityId = guidID; RetrieveRequest getAccount = new RetrieveRequest(); getAccount.ReturnDynamicEntities = true; getAccount.Target = target; getAccount.ColumnSet = new AllColumns(); RetrieveResponse retrieved = (RetrieveResponse)crmService.Execute(getAccount); DynamicEntity regardingAccount = (DynamicEntity)retrieved.BusinessEntity; // Если у возвращенной записи (объекта DynamicEntity) есть поле new_autonumber, то обновляем его, иначе добавляем к DynamicEntity новое поле и задаем для него значение if (regardingAccount.Properties.Contains("new_autonumber")) { regardingAccount.Properties["new_autonumber"] = Number; } else { regardingAccount.Properties.Add(new StringProperty("new_autonumber", Number)); } // Обновляем запись, в отношении которой работает бизнес-процесс crmService.Update(regardingAccount); return ActivityExecutionStatus.Closed; } } }
В этом коде происходит следующее:
- Сначала задается имя нового кастомного шага и имя группы (шагов) в которую он будет входить;
- Следующим этапом мы создаем новое поле, которое будет отображаться в настройках шага в CRM. Задаем тип этого поля – lookup. Определяем что в этот лукап можно подставить только Бизнес-партнера;
- Получаем контекст выполнения бизнес-процесс, из которого создаем экземпляр класса CrmService;
- Из лукапа бизнес-партнера заданного в кастомном шаге (и который подставится во время выполнения бизнес-процесс) вытаскиваем GUID (а т.к. мы подставим в этот лукап текущую запись, то это GUID текущей записи; этот же GUID можно вытащить через контекст бизнес-процесса, но об этом как-нибудь в другой раз 🙂 );
- Формируем конечный вид номера: «БП-» + GUID;
- Вытаскиваем из CRM текущую запись Бизнес-партнера (также по GUID’у) и обновляем в ней поле new_autonumber.
При написании кода кастомного бизнес-процесса не используйте одно и то же имя для класса и для пространства имен – это может вызвать проблемы при публикации такого workflow в CRM.
- Перейдите в Solution Explorer к файлу *.Designer.cs и убедитесь что имя класса и пространства имен в точносьт совпадают с теми, что Вы объявили в файле *.cs (в этом примере используется Activity1 как имя класса и Number как пространство имен);
- Т.к. сборку бизнес-процесса необходимо будет зарегистрировать в CRM, то необходимо ее подписать цифровым ключом: щелкните правой кнопкой мыши по названию проекта в Solution Explorer — Properties — Signing — поставьте галку Sign the assembly — выберите в ниспадающем списке <New…> и введите какое-нибудь название для ключа;
- Соберите сборку и опубликуйте ее в CRM с помощью Plugin Registration Tool. При этом не нужно создавать никаких шагов – просто зарегистрируйте новую Assembly.
На этом собственно все – шаг кастомного бизнес-процесса теперь доуступен через пользовательский интерфейс CRM, поэтому можно тестировать…
Тестирование
- Создайте новый бизнес-процесс в CRM для объекта Бизнес-партнер;
- В качестве есдинственного шага выберите, только что созданный наши шаг бизнес-процесса;
- В его настройках укажите подставлять в лукап динамическое значение: запись текущего Бизнес-партнера;
- Опубликуйте бизнес-процесс и вызовите событие на которое Вы его зарегистрировали (я «ручками» запусти). Перйдите на закладку бизнес-процессов на форме Бизнес-партнеров и дождитесь пока экземпляр бизнес-процесса отработает. Затем обновите (F5) запись Бизнес-партнера и увидите что кастомное поле autonumber заполнено уникальным номером 🙂
Отладка кастомных бизнес-процессов
… мало чем отдичается от отладки плагинов: чтобы отладить кастомный бизнес-процесс, Вы должны скопировать файл *.pdb из папки \bin\Debug Вашего C#-проекта в папку <папка установки CRM>\Server\bin\assembly на Вашем CRM сервере, установить контрольные точки в методе Execute и подключить к проекту Asynchronous service (CrmAsyncService.exe).
Если у Вас не получается обновить файл в папке assembly, потому что уже есть другая копия файла, перезапуститеть пул сайта CRM в IIS (или перезагрузите сам IIS: iisreset) или и/или перезапускают MS Dynamics CRM Asynchronous service.
Обновление сборок
После окончания разработки кастомного бизнес-процесс, Вы должны регистрировать его с помощью Plugin Registration Tool. Но тут есть маленькая загвоздка: когда Вы пересобираете (измененную) сборку Вашего бизнес-процесса и с помощью Plugin Registration Tool обновляете ее в CRM – внесенные изменения не появляются сразу же в CRM. Это потому что, старый код закэшировался. Чтобы обновить его достаточно перезапустить пул приложений MS CRM в IIS’е (ну, или на крайняк рестартнуть сам IIS) и/или перезапускают MS Dynamics CRM Asynchronous service.
Кастомные входящие/исходящие поля для бизнес-процессов
Описание того, как добавить входящие и исходящие поля в Ваш кастомный бизнес-процесс Вы можете найти в статье на MSDN: http://msdn.microsoft.com/en-us/library/cc151132.aspx
Свойства контекста плагинов и бизнес-процессов
https://docs.google.com/View?id=dcvd2dvh_534k95jhq&pli=1
П.С. существует более функционально развитый плагин реализующий автонумерацию в CRM – Счетчик.
Подскажите, пожалуйста, у меня есть workflow который создает объекты по триггеру. Мне необходимо, прежде чем создавать эти записи, проверить наличие дубликатов — записей с такими же полями ( поле owner и parentobject). Подойдет ли вариант решения — создание вишеуказанных полей в настройках шага, а затем с помощью query expression поиск дублей?
p.s. жаль что стандартные правила проверки на дубли не отрабатываю в случае workflow
Не совсем понял задумку. Но в кастомном шаге Вы можете проверить все что угодно 🙂