Я пытаюсь создать функцию последовательного рабочего процесса в Visual Studio для SharePoint 2007 / MOSS. Сложность заключается в размещении действия OnWorkflowItemChanged в Replicator / Sequence ... Я столкнулся с этим на "реальной" WF, которую я строил, и после того, как некоторое время забил мою голову, создал минималистичный тест WF для воспроизведения проблемы.
Обзор моей тестовой WF заключается в том, что она связана с настраиваемым списком с двумя настраиваемыми столбцами («Первый» и «Второй», обе из одной строки текста). WF запускается при добавлении элемента и зацикливается / ждет, пока не обновится первое поле. Затем он зацикливается / ждет, пока обновится второе поле, и затем завершается.
Мой макет рабочего процесса выглядит следующим образом:
Примечания:
- replicatorActivity1 имеет тип выполнения, установленный в последовательность
- onWorkflowActivation1 и onWorkflowItemChanged1 оба используют один и тот же токен корреляции, родительским элементом которого является Workflow (Workflow1)
- whileActivity1 имеет свое Условие, установленное как Условие кода (полагал, что так будет проще показать)
Код этого довольно прост, но для полноты вот он:
public sealed partial class Workflow1 : SequentialWorkflowActivity {
#region auto-created by VS
public Workflow1() {
InitializeComponent();
}
public Guid workflowId = default(System.Guid);
public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
#endregion
// used to exit while loop
public Boolean currentTaskDone = false;
// when WF starts, just log to the WF history
private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e) {
WorkflowHistory.writeSuccess(this.workflowProperties.Web, this.workflowId, "Workflow started.");
}
// initialize the replicator with 2 items
private void replicatorActivity1_Initialized(object sender, EventArgs e) {
this.replicatorActivity1.InitialChildData = new List<String>();
this.replicatorActivity1.InitialChildData.Add("First");
this.replicatorActivity1.InitialChildData.Add("Second");
}
// stop looping once this.currentTaskDone is true (written as: keep looping while false)
private void keepLooping(object sender, ConditionalEventArgs e) {
e.Result = !this.currentTaskDone;
}
// Whenever the request item is changed, check if the current field we're looking for (based on which
// child of the Replicator we're currently in) is set, if so: exit the loop
private void onWorkflowItemChanged1_Invoked(object sender, ExternalDataEventArgs e) {
WorkflowHistory.writeSuccess(this.workflowProperties.Web, this.workflowId, "Workflow item changed...");
string nameOfFieldToCheck = this.replicatorActivity1.CurrentChildData[this.replicatorActivity1.CurrentIndex].ToString();
string fieldValue = this.workflowProperties.Item.Fields[nameOfFieldToCheck].GetFieldValueAsText(this.workflowProperties.Item[nameOfFieldToCheck]);
this.currentTaskDone = (0 != fieldValue.Trim().Length);
}
// at end of loop: reset for next iteration + log position
private void logSequenceEnd_ExecuteCode(object sender, EventArgs e) {
this.currentTaskDone = false;
WorkflowHistory.writeSuccess(this.workflowProperties.Web, this.workflowId, "Exiting sequence '" + this.replicatorActivity1.CurrentChildData[this.replicatorActivity1.CurrentIndex].ToString() + "'");
}
Примечания * * 1023
WorkflowHistory - это пользовательский статический класс, который делает именно то, о чем вы думаете,
Проблема в том, что обработчик события onWorkflowItemChanged1 НИКОГДА не сработает (каждый раз, когда он делает это, он должен написать «Элемент рабочего процесса изменен ...» в список истории).
Оглядываясь вокруг, я нашел очень похожую запись здесь ( Рабочий процесс SharePoint с replicatorActivity и onWorkflowItemChanged , опубликовав это как новый вопрос для пояснения примеров), который ссылается на другую аналогичную запись ( Событие OnTaskChanged вызывается внутри ListenActivity, но не OnWorkflowItemChanged ), который утверждает, что имеет ответ. Основываясь на объяснениях Яниса во втором посте, я изменил свой рабочий процесс, как показано ниже (добавил действие intializeWorkflow1):
Примечания
- Без изменений кода (без обработчика initializeWorkflow1)
- initializeWorkflow1 и onWorkflowItemChanged1 теперь используют новый токен корреляции, в то время как onWorkflowActivation1 продолжает использовать исходный токен, связанный с Workflow1
Сначала у меня был токен корреляции для intializeWorkflow1 и onWorkflowItemChanged1, присоединенный к sequenceActivity1, но затем обработчик сработал только один раз для моего элемента. Поэтому я переключил его на replicatorActivity1, и теперь WF умирает, когда он должен нажать на initializeWorkflow1 во второй раз (после первого запуска logSequenceEnd) со следующими данными в журналах ULS:
System.InvalidOperationException: Correlation value on declaration "taskToken" is already initialized.
Кто-нибудь знает способ обойти это? Это выглядит так просто ...
Редактировать 2011-08-31 9:50 (EDT) (результаты тестирования)
Одна вещь, которую я забыл упомянуть, это то, что в некоторых конфигурациях я получаю Предупреждения компилятора, когда я строю свою функцию в VS. Вот разбивка не только комбинаций и ошибок, как уже объяснено выше, но также и этих предупреждений (извините, теги TABLE не допускаются):
В то время как N-
- Использование initializeWorkflow? Нет
- "Внутренний токен" * активность владельца: whileActivity1
- Предупреждение компилятора: Предупреждение проверки активности «onWorkflowItemChanged1»: корреляция может быть неинициализирована.
- WF Результат выполнения: Обработчик НИКОГДА не срабатывает
N-Seq
- Использование initializeWorkflow? Нет
- "Внутренний токен" * активность владельца: sequenceActivity1
- Предупреждение компилятора: Предупреждение проверки 'Activity' onWorkflowItemChanged1 ': корреляция может быть неинициализирована.
- WF Результат выполнения: Обработчик НИКОГДА не срабатывает
N-Rep
- Использование initializeWorkflow? Нет
- "Внутренний токен" * активность владельца: replicatorActivity1
- Предупреждение компилятора: Предупреждение проверки 'Activity' onWorkflowItemChanged1 ': корреляция может быть неинициализирована.
- WF Результат выполнения: Обработчик НИКОГДА не срабатывает
N-WF
- Использование initializeWorkflow? Нет
- "Внутренний токен" * активность владельца: workflow1
- Предупреждения компилятора:
- Предупреждение проверки действия "onWorkflowItemChanged1": ссылочная переменная CorrelationToken 'taskToken' должна быть объявлена в родительской операции нескольких экземпляров 'replicatorActivity1'.
- Предупреждение о проверке действия onWorkflowItemChanged1: корреляция может быть неинициализирована.
должен быть объявлен в родительском множественном действии 'replicatorActivity1'.
- WF Результат выполнения: Обработчик НИКОГДА не срабатывает
Y-Seq
- Использование initializeWorkflow? Да
- "Внутренний токен" * активность владельца: sequenceActivity1
- Предупреждение компилятора: Нет
- WF Результат выполнения: Обработчик срабатывает правильно один раз, никогда больше. Нет ошибок.
Y-Rep
- Использование initializeWorkflow? Да
- "Внутренний токен" * активность владельца: replicatorActivity1
- Предупреждение компилятора: Нет
- WF Runtime result: Обработчик срабатывает корректно один раз, а затем сразу выдает ошибки.
Y-WF
- Использование initializeWorkflow? Да
- "Внутренний токен" * активность владельца: workflow1
- Предупреждения компилятора:
- Предупреждение проверки действия 'initializeWorkflow1': ссылочная переменная CorrelationToken 'loopToken'
должен быть объявлен в родительском множественном действии 'replicatorActivity1'.
- Предупреждение проверки активности "onWorkflowItemChanged1": ссылочная переменная CorrelationToken 'loopToken'
должен быть объявлен в родительском множественном действии 'replicatorActivity1'.
- WF Runtime result: Обработчик корректно срабатывает один раз, а затем сразу выдает ошибки.
* «Внутренний токен» - это тот, который используется onWorkflowItemChanged и (если он существует) initializeWorkflow