MaYunsong


Hi guys, morning!

As we know, The workflow runtime engine calls SaveWorkflowInstanceState a final time when the workflow instance is completed or terminated.

Now in my application, i load a persisted workflow instance through my FileWorkflowPersistenceService and make it continue to run successfully. But i don't want SaveWorkflowInstanceState to be called when the loaded workflow instance is completed.

So do we have any method to control this

I will appreciate any of your advice.

Thank you guys in advance!!!

Sincerely!

yours, Ma

------------This is my persistence service class----------------

using System;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.IO;
using System.Threading;
//using System.Collections.Specialized;
using CustomClassLibrary.Properties;
using System.Runtime.InteropServices;

namespace CustomClassLibrary
{
public class WFPersistenceServiceByFile : WorkflowPersistenceService
{
// Member.
private bool unloadOnIdle = false;

// Constructor.
public WFPersistenceServiceByFile(bool unloadOnIdle)
{
this.unloadOnIdle = unloadOnIdle;
}

// Method.
protected override bool UnloadOnIdle(Activity activity)
{
return unloadOnIdle;
}

protected override void SaveWorkflowInstanceState(Activity rootActivity,
bool unlock)
{
// Get the current workflow instance id.
Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);

SerializeToFile( WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity),
contextGuid);
}

private void SerializeToFile(byte[] workflowBytes, Guid id)
{
String filename = CustomClassLibraryResources.PersistFileDirectoryRequestSide + id.ToString();
FileStream fileStream = null;
try
{
if (File.Exists(filename))
{
File.Delete(filename);
}

fileStream = new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None);

// Get the serialized form
fileStream.Write(workflowBytes, 0, workflowBytes.Length);
}
finally
{
if (fileStream != null)
fileStream.Close();
}
}

protected override Activity LoadWorkflowInstanceState(Guid instanceId)
{
byte[] workflowBytes = DeserializeFromFile(instanceId);

Activity resultActivity = WorkflowPersistenceService.RestoreFromDefaultSerializedForm(
workflowBytes, null);

return resultActivity;
}

private byte[] DeserializeFromFile(Guid id)
{
String filename = CustomClassLibraryResources.PersistFileDirectoryApprovalSide + id.ToString();

FileStream fileStream = null;
try
{
// File opened for shared reads but no writes by anyone
fileStream = new FileStream(filename, FileMode.Open,
FileAccess.Read, FileShare.Read);
fileStream.Seek(0, SeekOrigin.Begin);
byte[] workflowBytes = new byte[fileStream.Length];

// Get the serialized form
fileStream.Read(workflowBytes, 0, workflowBytes.Length);

return workflowBytes;
}
finally
{
fileStream.Close();
}
}

protected override void SaveCompletedContextActivity(Activity activity)
{
}

protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
{
return null;
}

protected override void UnlockWorkflowInstanceState(Activity rootActivity)
{

}
}
}




Re: Question about workflowpersistenceservice

Konstantin Vyaznikov


Hi,

You can check the flag:

WorkflowStatus status = GetWorkflowStatus(rootActivity);

in SaveWorkflowInstanceState.

Thanks,

Konstantin.





Re: Question about workflowpersistenceservice

Mark Stafford

If you already have your own implementation of a persistence service and would like to keep it, why not simply add the logic to your overridden SaveWorkflowInstanceState

Mark






Re: Question about workflowpersistenceservice

MaYunsong

Thank you, Konstantin.

Would you please explain it in sorta any detail

I'm just wondering how i can make use of the flag you mentioned.

Thank you so much!!!

yours, Ma






Re: Question about workflowpersistenceservice

MaYunsong

Thank you, Mark.

I think your advice is good. And I'm just wondering what kind of logic i should add.

I'm not very clear about what you said. Would you please explain it in any sorta detail

Thank you so much!!

yours, Ma






Re: Question about workflowpersistenceservice

Konstantin Vyaznikov

Quote from your code below. Stuff which I added is in blue.

Code Snippet

protected override void SaveWorkflowInstanceState(Activity rootActivity,
bool unlock)
{

WorkflowStatus status = GetWorkflowStatus(rootActivity);

if(status == WorkflowStatus.Completed ||

status == WorkflowStatus.Terminated)

{

// do what you want here. For example:

return;

}

// Get the current workflow instance id.
Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);

SerializeToFile( WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity),
contextGuid);
}

Thanks,

Konstantin.





Re: Question about workflowpersistenceservice

MaYunsong

Thank you sincerely, dear KonstantinSmile

Best Wishes!






Re: Question about workflowpersistenceservice

MaYunsong

Dear Constantin, sorry to trouble you again.

i met some weird problem.

This is my code based on your advice.

protected override void SaveWorkflowInstanceState(Activity rootActivity,
bool unlock)
{

WorkflowStatus workflowStatus = GetWorkflowStatus(rootActivity);


if (workflowStatus == WorkflowStatus.Completed ||

workflowStatus == WorkflowStatus.Terminated)
{
return;
}
else
{
Guid contextGuid =

(Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);

SerializeToFile(
WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity),
contextGuid);

}
}

protected override Activity LoadWorkflowInstanceState(Guid instanceId)
{
byte[] workflowBytes = DeserializeFromFile(instanceId);

Activity resultActivity =
WorkflowPersistenceService.RestoreFromDefaultSerializedForm(
workflowBytes, null);

return resultActivity;
}

This is my host code.

for(........)

{

......................

......................

Guid wfInstanceID = new Guid(persistedFileName);
WorkflowInstance wfInstance =

wfRuntimeDocApprovalWorkflow.GetWorkflow(wfInstanceID);
wfInstance.Load();

// Raise our event.
WorkflowLoadedEventArgs workflowLoadedEventArgs =
new WorkflowLoadedEventArgs(wfInstanceID, eachApprovalFilePath);
passParas.RaiseEvent(workflowLoadedEventArgs);

waitHandle.WaitOne();

}

When the for loop is at its first time loop, everything's OK. The host's GetWorkflow function is called, then the service's LoadWorkflowInstanceState function is called, then the host's Load function is called and go on to the end. After the host's WaitOne function is called, a workflow instance persisted before continues to run from its persistence point. And after this workflow instance is completed, the service's SaveWorkflowInstanceState function is called again and we do nothing through checking the status. These are what we discussed before, right

Now my problem is that when the for loop is at its non-first time loop, like its second time one or its third time one, etc, everything goes fine until the host's Load function being called. After the host's Load function is called, a weird thing happens that the service's SaveWorkflowInstanceState is called, then the host's new WorkflowLoadedEventArgs, then the service's if (workflowStatus == WorkflowStatus.Completed || ....), then the host's RaiseEvent function, then the service's GetValue fuction and SerializeToFile function.

It's like the logic flow has been switching between the host and the service.

Would you please explain sth about this for me Cause i'm really confused about it.

Thank you so much and best wishes!!

yours, Ma






Re: Question about workflowpersistenceservice

Konstantin Vyaznikov

It happens because after GetWorkflow, workflow starts executing asyncronously on a separate thread and you see that system switches between host and service. Different threads run different workflows.

Thanks,

Konstantin.





Re: Question about workflowpersistenceservice

MaYunsong

Oh, no wonder it switches between each other.

I had been thinking that until my WaitOne() function is called, the runtime engine doesn't arranges the un-persisted workflow instance to work on another thread. So is my thought uncorrect or do i miss some important concepts

To be honest, your help is really appreciated!!!

Thank you sincerely!

yours, Ma






Re: Question about workflowpersistenceservice

Konstantin Vyaznikov

Workflow scheduler keeps launching workflows on it's own on different threads up to capacity of thread pool, which is configurable. Scheduler does not know what goes on around.

Thanks,

Konstantin.





Re: Question about workflowpersistenceservice

MaYunsong

Thank you so much, Kons!

i think i've got a general understanding more or less.

i will survey some related info.

Sincerely yours, Ma







databaseforum