This work fine. But if I close the application (runtime instance is gone) while the EventSink is waiting and start the Application again, the EventSink doesnt notice that the Event was fired. I think because of the fact, that the Local Service Instance isn's stored persistent, the Event isnt registred anymore. Because the Local Service is a new instance now. How can I change that !
Can't EventSinks listen to an Event who was registred bevor the restart of the application Or is there a better way to solve this problem
The Persistence-Service works fine (other Workflows with normal Activities starts at the correct position) I think I'm doing something wrong with Local Service. Or this feature isn't implemented yet (Im using Beta 1) !
Thanks!
Thomas Roethlisberger
student, switzerland
runtime:
runtime = new WorkflowRuntime("WorkflowRuntime"); IWorklistLocalService worklistService = new WorklistLocalService(); runtime.AddService(worklistService); |
local service:
[DataExchangeService,CorrelationParameter("titel")] public interface IWorklistLocalService { [CorrelationAlias("titel", "e.Titel")] event EventHandler<WorklistEventArgs> WorkDone; [CorrelationInitializer()] void CreateWorklistEntry(string titel, string username, string todo, Guid instanceId); void ReportWorklistDone(Guid instanceId, string titel); } public class WorklistEventArgs : WorkflowMessageEventArgs { private string titel = null; public WorklistEventArgs(Guid instanceID, string titel) : base(instanceID) { this.titel = titel; } public string Titel { get { return titel; } } } public class WorklistLocalService : IWorklistLocalService { public event EventHandler<WorklistEventArgs> WorkDone; public void CreateWorklistEntry(string titel, string username, string todo, Guid instanceId) { WorklistData data = new WorklistData(); WorklistData.WFWorklistRow row = data.WFWorklist.NewWFWorklistRow(); row.Username = username; row.Titel = titel; row.Todo = todo; row.InstanceId = instanceId; try { data.WFWorklist.AddWFWorklistRow(row); DACs.User.SaveWorklistData(data); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } } public void ReportWorklistDone(Guid instanceId, string titel) { if(WorkDone!=null) WorkDone(null, new WorklistEventArgs(instanceId, titel)); } } |
Activities:
public class CreateEntryIvokeMethode : InvokeMethodActivity { ActivityBind activitybind = new ActivityBind(); public CreateEntryIvokeMethode() { this.InterfaceType = typeof(IWorklistLocalService); this.MethodName = "CreateWorklistEntry"; } protected override Status Execute(ActivityExecutionContext context) { IWorklistLocalService service = context.GetService(typeof(IWorklistLocalService)) as IWorklistLocalService; if ((service == null)) { throw new System.InvalidOperationException(); } service.CreateWorklistEntry((string)Parent.GetValue(DependencyProperty.FromName("Titel", typeof(WorklistEntry))), (string)Parent.GetValue(DependencyProperty.FromName("Username", typeof(WorklistEntry))), (string)Parent.GetValue(DependencyProperty.FromName("ToDo", typeof(WorklistEntry))), this.WorkflowInstanceId); return Status.Closed; } } public class WorkDoneEventSink : EventSinkActivity { ActivityBind activitybind = new ActivityBind(); public WorkDoneEventSink() { this.InterfaceType = typeof(IWorklistLocalService); this.EventName = "WorkDone"; } protected override void Initialize(IServiceProvider context) { IWorklistLocalService service = context.GetService(typeof(IWorklistLocalService)) as IWorklistLocalService; service.WorkDone += this.OnWorkDone; } private void OnWorkDone(Object sender, WorklistEventArgs args) { } } [DesignerAttribute(typeof(ActivityDesigner))] [ToolboxItemAttribute(typeof(ActivityToolboxItem))] public class WorklistEntry : Sequence { [LockedActivityAttribute(true, true)] private CreateEntryIvokeMethode createEntry; [LockedActivityAttribute(true, true)] private WorkDoneEventSink workDone; public CorrelationReference CorrRef = new CorrelationReference(); public WorklistEntry() { this.ID = "WorklistEntry"; ActivityBind activitybind = new ActivityBind(); activitybind.ID = "/Parent"; activitybind.Path = "CorrRef"; this.createEntry = new CreateEntryIvokeMethode(); this.workDone = new WorkDoneEventSink(); this.createEntry.ID = "createEntry"; this.createEntry.CorrelationReference = activitybind; this.workDone.ID = "workDone"; this.workDone.CorrelationReference = activitybind; this.Activities.Add(this.createEntry); this.Activities.Add(this.workDone); } public static DependencyProperty TitelProperty = DependencyProperty.Register("Titel", typeof(System.String), typeof(WorklistEntry)); public static DependencyProperty ToDoProperty = DependencyProperty.Register("ToDo", typeof(System.String), typeof(WorklistEntry)); public static DependencyProperty UsernameProperty = DependencyProperty.Register("Username", typeof(System.String), typeof(WorklistEntry)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [ValidationVisibilityAttribute(ValidationVisibility.Optional)] [BrowsableAttribute(true)] [DescriptionAttribute("Titel des Arbeitsauftrages")] [CategoryAttribute("Arbeitsauftrag")] public string Titel { get { return ((String)(base.GetValue(WorklistEntry.TitelProperty))); } set { base.SetValue(WorklistEntry.TitelProperty, value); } } [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [ValidationVisibilityAttribute(ValidationVisibility.Optional)] [BrowsableAttribute(true)] [DescriptionAttribute("Zu Erledigende Arbeit")] [CategoryAttribute("Arbeitsauftrag")] public string Todo { get { return ((String)(base.GetValue(WorklistEntry.ToDoProperty))); } set { base.SetValue(WorklistEntry.ToDoProperty, value); } } [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [ValidationVisibilityAttribute(ValidationVisibility.Optional)] [BrowsableAttribute(true)] [DescriptionAttribute("Beauftragter Mitarbeiter")] [CategoryAttribute("Arbeitsauftrag")] public string Username { get { return ((String)(base.GetValue(WorklistEntry.UsernameProperty))); } set { base.SetValue(WorklistEntry.UsernameProperty, value); } } } |

Persistence with Local Service (InvokeMethod/EventSink/Correlation)
MyoZaw
Thanks a lot for your quick answer! You're right, I didn't load the workflows again after restart, but for normal workflows this wasnt needed. They were reloaded automaticly. But for activities who have to hook up an event again I have to load them expicitly.
My question now is: If I load the workflow as you told me with the following Code it works fine. But therefore I need the GUID of the idle workflow instance. Do I really have to read the GUID manually from the persistence and load them expicitly
public void StartRuntime()
{
if (!runtime.IsStarted)
{
runtime.StartRuntime();
WorklistData wlData = DACs.User.GetAllWorklist();
foreach (WorklistData.WFWorklistRow wlrow in wlData.WFWorklist)
{
runtime.GetWorkflow(wlrow.InstanceId).Load();
}
Trace.WriteLine(DateTime.UtcNow + ": Engine started...");
}
}
Do you have a better idea for this Do I really have to know all the GUIDs of the stored workflow instances
Thanks!
Thomas
OROCHKA
In Beta1, you do have to call Load() before raising an event. You could choose to do it at startup (like you're doing above), or alternatively, call Load() before raising the event. You'll need to know the Guids of the stored workflow instances in any case, because that's the only way to raise events back to the workflow instances.
Arjun
jsena
How are you reloading the instance from persistence once the application is restarted In Beta1, the individual instance needs to be reloaded for the events to be hooked up again (via a call to WorkflowRuntime's GetWorkflow() & then the WorkflowInstance's Load(). We have fixed this for Beta2 so that the events are rewired whenever the service is added to the runtime container.
Hope this helps
Arjun