|  26.10.2009, 09:10 | #1 | 
| Участник | Бизнес-процесс: применение определенного алгоритма к каждой записи CRMGrid 
			
			Доброе утро! Нужно создать бизнес-процесс, который бы пробегал по всем записям данной сущности и если у записи определенный атрибут установлен в Активен, то получить из этой записи определенные атрибуты, как параметры и выполнить заданный алгоритм. Начал писать правило для бизнес-процесса, для этого воспользовался примером из книги Майка Снайдера: Код: using System;
using System.Workflow.ComponentModel;
using System.Workflow.Activities;
using Microsoft.Crm.Workflow;
namespace BP_CRMScaner
{
    [CrmWorkflowActivity("Выполнить сканирование", "Сканирование WEB-ресурсов")]
    public partial class Activity1 : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            //получение контекста
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext ctx = contextService.Context;
            //Здесь выполняется пользовательская логика
            //Доступ к свойствам ввода и вывода осуществляется следующим образом
            this.InputExample = "foo";
            this.OutputExample = this.InputExample + "bar";
            return base.Execute(executionContext);
        }
        //Задание свойств ввода
        public static DependencyProperty InputExampleProperty = DependencyProperty.Register("InputExample", typeof(string), typeof(Activity1));
        [CrmInput("InputExample")]
        public string InputExample
        {
            get
            {
                return (string)base.GetValue(InputExampleProperty);
            }
            set
            {
                base.SetValue(InputExampleProperty, value);
            }
        }
        //Задание свойства вывода
        public static DependencyProperty OutputExampleProperty = DependencyProperty.Register("OutputExample", typeof(string), typeof(Activity1));
        [CrmOutput("OutputExample")]
        public string OutputExample
        {
            get
            {
                return (string)base.GetValue(OutputExampleProperty);
            }
            set
            {
                base.SetValue(OutputExampleProperty, value);
            }
        }
    }
}Последний раз редактировалось Tarasov E; 26.10.2009 в 09:31. | 
|  | 
|  26.10.2009, 09:39 | #2 | 
| Moderator | 
			
			Опишите задачу на конкретном примере, пожалуйста. Мне кажется что вы не верно понимаете суть бизнес процессов. БП используются для обработки различных событий, а не для обработки базы. Чтобы вычитать запись по определенными критериями нужно использовать метод CrmService.RetrieveMultiple, а не перебирать все записи. 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | 
|  26.10.2009, 09:52 | #3 | 
| Участник | 
			
			Описываю более подробно: Есть сущность new_web с множеством записей. У каждой записи есть набор атрибутов: периодичность сканирования, стутус(активно, отключено) и атрибуты-парметры, которые необходимо передать на выполнение в определенный алгоритм. Так вот, нужен бизнес-процесс, который раз в "Периодичность" обращается к записи(у каждой записи периодичность своя, хотя на начальном этапе можно попробовать задать общую периодичность в самом БП), получает атрибуты-параметры и выполняет определенный алгоритм, результатом которого будет создание некоторых файлов на диске. Ниже прикрепляю скрин: при запуске бизнес процесса, если состояние "Активно", из записи (я полагаю по GUID) мы получаем определенные атрибуты и выполняем алгоритм. | 
|  | 
|  26.10.2009, 10:07 | #4 | 
| Moderator | 
			
			БП не умеет стартовать по расписанию. Проще написать windows службу, которая будет выполнять все описанные выше операции. p.s. Очень и очень странная задача для CRM системы! В чем суть сканирования, если не секрет? 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | 
|  26.10.2009, 10:23 | #5 | 
| Участник | 
			
			Суть в том, чтобы просканировав заданные сайты - получать только интересующую информацию с их вэб-ресурсов. Допустим только новости, а весь остальной мусор отбрасывать.  А если немного схитрить: сделать 2 поля: дата сканирования и периодичность. за 24 часа до наступления "Дата сканирования" выполнить бизнес-процесс и прибавить к "Дата сканирования" периодичность. Как то так? И кстати да, неверно понял, мне на самом деле не нужно пробегать по всем записям из CRMGrid'а, ведь бизнес-процесс будет реагировать на "Дату сканирования" каждой записи в отдельности". Последний раз редактировалось Tarasov E; 26.10.2009 в 11:01. | 
|  | 
|  26.10.2009, 11:46 | #6 | 
| Moderator | 
			
			Ну, реализация задач с повторением уже не раз обсуждалась, попробуйте поискать эти топики. Скажу сразу - нужно долго извращаться. В CRM 5.0 они заявлены как стандартный функционал.
		 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | 
|  26.10.2009, 15:51 | #7 | 
| Moderator | 
			
			Я поддерживаю Артема с его предложением написать Windows службу.
		 | 
|  | 
|  27.10.2009, 09:05 | #8 | 
| Консультант-джедай | Цитата: 
		
			Сообщение от Tarasov E
			   Суть в том, чтобы просканировав заданные сайты - получать только интересующую информацию с их вэб-ресурсов. Допустим только новости, а весь остальной мусор отбрасывать.  А если немного схитрить: сделать 2 поля: дата сканирования и периодичность. за 24 часа до наступления "Дата сканирования" выполнить бизнес-процесс и прибавить к "Дата сканирования" периодичность. Как то так? И кстати да, неверно понял, мне на самом деле не нужно пробегать по всем записям из CRMGrid'а, ведь бизнес-процесс будет реагировать на "Дату сканирования" каждой записи в отдельности". http://mmcrm.ru/?p=385 
				__________________ Крокодил, крокожу и буду крокодить. Человек человеку - волк , а зомби зомби - зомби. Экстремал и буду экстремать!  Блога | 
|  | |
| За это сообщение автора поблагодарили: Tarasov E (1). | |
|  27.10.2009, 09:59 | #9 | 
| Участник | |
|  | 
|  27.10.2009, 11:53 | #10 | 
| Участник | 
			
			Появился вопрос по первому способу: Можно ли при обновление - параметр обновления брать из другого поля, чтобы для каждой записи была своя периодичность выполнения бизнес процесса? Например как-нибудь так: {час.:new_period.DataValue После ...и т.д} То что мне нужно более понятно обрисовано на скрине | 
|  | 
|  27.10.2009, 12:17 | #11 | 
| Moderator | 
			
			Можно: нужно писать кастомный степ для плагина, который прибавит к дате произвольное число дней и запишет в нужную ячейку. Еще раз повторяю: вы пытаетесь использовать workflow не по назначению! Ожидание и повторение - не его конек! Требуют хранить расписание в CRM - ради бога, храните. Но заведите стандартный сервис, который будет читать из CRM данные по расписанию, выполнять сканирование и заливать данные обратно. Кучу времени себе сэкономите! 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | |
| За это сообщение автора поблагодарили: Tarasov E (1). | |
|  27.10.2009, 13:19 | #12 | 
| Участник | 
			
			Хорошо, про кастомный стэп понятно...вернемся все же к первой части вопроса: как в workflow activity получить данные из полей формы, для их обработки?
		 | 
|  | 
|  27.10.2009, 13:27 | #13 | 
| Чайный пьяница | Цитата: Регистрируете инпут проперти - лукапом на сущность из которой планируете получить данные, в коде степа при помощи Retrieve вычитываете данную сущность, суммируете дату и период, на выход (output property) отдаёте полученную суммированием дату. Собственно всё. 
				__________________ Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit | 
|  | 
|  27.10.2009, 14:19 | #14 | 
| Участник | Цитата: 
		
			Сообщение от a33ik
			   Точно так же - при прмрщи кастомного экшена. Регистрируете инпут проперти - лукапом на сущность из которой планируете получить данные, в коде степа при помощи Retrieve вычитываете данную сущность, суммируете дату и период, на выход (output property) отдаёте полученную суммированием дату. Собственно всё. Код: public static DependencyProperty InputExampleProperty = DependencyProperty.Register("InputExample", typeof(string), typeof(Activity1));
        [CrmInput("InputExample")]
        public string InputExample
        {
            get
            {
                return (string)base.GetValue(InputExampleProperty);
            }
            set
            {
                base.SetValue(InputExampleProperty, value);
            }Далее мы уже с помощью retrieve сможем выдирать атрибуты и обрабатывать как нам угодно? А что за тип данных должен, чтобы в настройках стэпа указать ссылку на сущность? typeof(Lookup) почему то он не понимает... Последний раз редактировалось Tarasov E; 27.10.2009 в 14:22. | 
|  | 
|  27.10.2009, 14:30 | #15 | 
| Чайный пьяница | Цитата: 
		
			Сообщение от Tarasov E
			   Тоесть если я правильно понял то пример из первого сообщения Код: public static DependencyProperty InputExampleProperty = DependencyProperty.Register("InputExample", typeof(string), typeof(Activity1));
        [CrmInput("InputExample")]
        public string InputExample
        {
            get
            {
                return (string)base.GetValue(InputExampleProperty);
            }
            set
            {
                base.SetValue(InputExampleProperty, value);
            }Далее мы уже с помощью retrieve сможем выдирать атрибуты и обрабатывать как нам угодно? А что за тип данных должен, чтобы в настройках стэпа указать ссылку на сущность? typeof(Lookup) почему то он не понимает... 
				__________________ Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit | 
|  | |
| За это сообщение автора поблагодарили: Tarasov E (1). | |
|  27.10.2009, 14:31 | #16 | 
| Участник | Цитата: 
		
			You can use the System.Workflow.ComponentModel.PersistOnClose...
		
	 | 
|  | 
|  27.10.2009, 14:37 | #17 | 
| Чайный пьяница | 
			
			Сборки, референсы на которые нужны для CustomWorkflowAction.   
				__________________ Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit | 
|  | 
|  29.10.2009, 11:19 | #18 | 
| Чайный пьяница | 
				__________________ Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit | 
|  | 
|  29.10.2009, 11:26 | #19 | 
| Участник | 
			
			Спасибо, a33ik, с библиотеками разобрался, сделал как было указано выше: Код: namespace BP_CRMScaner
{
    [CrmWorkflowActivity("Выполнить сканирование", "Сканирование WEB-ресурсов")]
    public class Activity1 : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            //получение контекста
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext ctx = contextService.Context;
            //Здесь выполняется пользовательская логика
            return base.Execute(executionContext);
        }
        //Задание свойств ввода
        public static DependencyProperty ScanProperty = DependencyProperty.Register("Scaner", typeof(Lookup), typeof(Activity1));
        [CrmInput("Субъект сканирования")]
        [CrmReferenceTarget("new_web")]
        public Lookup Scaner
        {
            get
            {
                return (Lookup)base.GetValue(ScanProperty);
            }
            set
            {
                base.SetValue(ScanProperty, value);
            }
        }
        
    }
}Цитата: 
		
			Error	1	Could not create activity of type 'BP_CRMScaner.Activity1'. System.ArgumentException: Type 'BP_CRMScaner.Activity1' does not define a static dependency property with name 'ScanerProperty'. Parameter name: ownerType at System.Workflow.ComponentModel.DependencyProperty.ValidateAndRegister(String name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, Type validatorType, Boolean isRegistered) at System.Workflow.ComponentModel.DependencyProperty.Register(String name, Type propertyType, Type ownerType) at BP_CRMScaner.Activity1..cctor() | 
|  | 
|  29.10.2009, 11:31 | #20 | 
| Чайный пьяница | Цитата: 
		
			Сообщение от Tarasov E
			   Спасибо, a33ik, с библиотеками разобрался, сделал как было указано выше: Код: namespace BP_CRMScaner
{
    [CrmWorkflowActivity("Выполнить сканирование", "Сканирование WEB-ресурсов")]
    public class Activity1 : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            //получение контекста
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext ctx = contextService.Context;
            //Здесь выполняется пользовательская логика
            return base.Execute(executionContext);
        }
        //Задание свойств ввода
        public static DependencyProperty ScanProperty = DependencyProperty.Register("Scaner", typeof(Lookup), typeof(Activity1));
        [CrmInput("Субъект сканирования")]
        [CrmReferenceTarget("new_web")]
        public Lookup Scaner
        {
            get
            {
                return (Lookup)base.GetValue(ScanProperty);
            }
            set
            {
                base.SetValue(ScanProperty, value);
            }
        }
        
    }
}В чем проблема? Вроде все делал по образцу Код: namespace BP_CRMScaner
{
    [CrmWorkflowActivity("Выполнить сканирование", "Сканирование WEB-ресурсов")]
    public class Activity1 : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            //получение контекста
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext ctx = contextService.Context;
            //Здесь выполняется пользовательская логика
            return base.Execute(executionContext);
        }
        //Задание свойств ввода
        public static DependencyProperty ScanerProperty = DependencyProperty.Register("Scaner", typeof(Lookup), typeof(Activity1));
        [CrmInput("Субъект сканирования")]
        [CrmReferenceTarget("new_web")]
        public Lookup Scaner
        {
            get
            {
                return (Lookup)base.GetValue(ScanerProperty);
            }
            set
            {
                base.SetValue(ScanerProperty, value);
            }
        }
        
    }
}
				__________________ Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit | 
|  |