В русскоязычном интернете этой проблеме уделено весьма мало внимания... Где можно почитать? Я нашел вот эти работы: на rsdn, gotdotnet и т.д..
Эти статьи либо достаточно поверхностны, либо подразумевают (как последняя) что вы уже все знаете :).
Поэтому давайте попробуем решить поставленную задачу (сохранение workflow во внешнем хранилище) медленно и по шагам.
Итак, для решения данной задачи нам понадобится VS 2008 + MS SQL (версия последнего не особенно принципиальна).
1. Идем сюда и читаем как нам подготовить MS SQL.
2. Создаем простенький workflow на котором будем ставить эксперименты. Для простоты я воспользовался следующим:
Первое состояние стартовое и мы его сразу покидаем. Второе вызывает метод Print из нижеописанного интерфейса и ждет событие из него же. Третье служит для того чтобы сказать что событие успешно получено и обработано.
Обещанный интерфейс:
[ExternalDataExchangeAttribute()]
public interface IMethodAndEvents
{
event EventHandler<ExternalDataEventArgs> MyEvent;
void PrintText(string p_text);
}
* This source code was highlighted with Source Code Highlighter.
2. Тестировать будем при помощи формы следующего вида:
Кнопки 2 и 3 создают WorkflowRuntime и все необходимые сервисы, а кроме того кнопка 2 создает экземпляр workflow.
private void button2_Click(object sender, RoutedEventArgs e)
{
button3_Click(null, null);
_instance = _runtime.CreateWorkflow(typeof(Workflow1));
_instance.Start();
textBox1.Text = _instance.InstanceId.ToString();
}
private void button3_Click(object sender, RoutedEventArgs e)
{
_runtime = new WorkflowRuntime();
// Create the SqlWorkflowPersistenceService.
string connectionString = "Initial Catalog=WorkflowPersistenceStore;Data Source=localhost;Integrated Security=SSPI;";
bool unloadOnIdle = true;
TimeSpan instanceOwnershipDuration = TimeSpan.MaxValue;
TimeSpan loadingInterval = new TimeSpan(0, 2, 0);
SqlWorkflowPersistenceService persistService = new SqlWorkflowPersistenceService(connectionString, unloadOnIdle, instanceOwnershipDuration, loadingInterval);
_runtime.AddService(persistService);
ExternalDataExchangeService externalDataExchangeService = new ExternalDataExchangeService();
_runtime.AddService(externalDataExchangeService);
externalDataExchangeService.AddService(this);
_runtime.StartRuntime();
}
* This source code was highlighted with Source Code Highlighter.
Как видим из метода 2 кнопки Id workflow выводится в textBox.
Кнопка 1 отправляет событие в workflow идентификатор которого берет из поля формы:
private void button1_Click(object sender, RoutedEventArgs e)
{
if (MyEvent != null)
{
MyEvent(null, new ExternalDataEventArgs(_instance.InstanceId));
}
}
* This source code was highlighted with Source Code Highlighter.
А вот кнопка 4 отправляет событие в workflow чей идентификатор берется из textBox-а.
private void button4_Click(object sender, RoutedEventArgs e)
{
if (MyEvent != null)
{
Guid id = new Guid(textBox1.Text);
MyEvent(null, new ExternalDataEventArgs(id));
}
}
* This source code was highlighted with Source Code Highlighter.
В чем отличие? Если в textBox попадает тот же идентификатор что хранится в поле _instance? смотрим следующий шаг!
3. Запускаем приложение и тестируем работу workflow кликнув на кнопке 2, а затем 1. Поток отрабатывает как и ожидалось, в чем мы можем убедится за счет вызова метода Print например такого содержания:
delegate void PrintHandler(string p_text);
public void PrintText(string p_text)
{
// Проверяем совпадает ли поток диспетчера с потоком вызвавшим метод
if (Dispatcher.Thread == Thread.CurrentThread)
{
// Все замечательно :) меняем значение textbox-а
label1.Content = p_text;
}
else
{
// Нет :( все плохо :( перезапускаем метод в потоке диспетчера
Dispatcher.Invoke(new PrintHandler(PrintText), new object[] { p_text });
}
}
* This source code was highlighted with Source Code Highlighter.
А теперь самое интересное! Перезапускаем приложение нажимаем на кнопку 2, копируем в буфер обмена значение идентификатора и?..
Перезапускаем приложение!
В новой копии приложения создаем рунтайм (но не workflow) кнопкой 3. Вставляем из буфера в textBox идентификатор. Нажимаем на кнопку 4 и видем в label подтверждение обработки события в workflow.
Или иными словами созданный workflow был успешно сохранен во внешнем хранилище, а при повторном запуске приложения и попытке отправить ему события извлечен из оного. Что собственно говоря и требовалось по условию задачи.
На этом можно бы и закончить, но рекомендую попробовать написать все это самостоятельно ручками ;)
Комментариев нет:
Отправить комментарий