Context in workflow?
I was curious to know if there a way of sharing a "context" between all activities in a workflow instance. I am looking at something analogous to HttpContext in ASP.NET and LogicalCallContext in Remoting.
Of course, I can resort to ThreadLocalStorage or AppDomain data myself, but I wondering whether there is a better way of handling this.
Thanks,
Manoj
[389 byte] By [
ManojG] at [2007-12-23]
I’m not sure this applies to your problem. But as a understand it, you’re invoking the workflow and you need to ”interact” with it (approve) before it finally executes the last activity.
Let’s assume you have a wf that looks something like this:
Create (Code activity) -> Approve (Code activity)-> Complete (Code activity).
If you’d changed the “Approve” activity to one CallExternalMethod activity, and one HandleExternalEvent activity:
Create (Code activity) -> Ready for Approval (CallExternalMethod activity)-> Approve (HandleExternalEvent activity)-> Complete (Code activity).
The “Ready for Approval” will raise an event which your aspx page will redirect to a approve page. The workflow will thereafter halt until the “Approve” is executed.
Since we are no longer using just code activities, we need to implement an interface:
[ExternalDataExchangeAttribute()]
interface IEMailApproval
{
void ReadyForAppoval(ExternalDataEventArgs e); // Invoked from workflow
event EventHandler<ExternalDataEventArgs> Approved; // Raised by aspx page
}
You’ll also need a service implementing the interface:
public class EmailApprovalService : IEMailApproval
{
/// <summary>
/// Invoked by client
/// </summary>
public void Approve()
{
if (this.Approved== null)
throw new Exception("There is no corresponding workflow subscribing this event.");
this.Approved(null, null);
}
/// <summary>
/// Subscribed by client
/// </summary>
#region IEMailApproval Members
/// <summary>
/// Invoked By WF
/// </summary>
/// <param name="e"></param>
public void ReadyForAppoval(System.Workflow.Activities.ExternalDataEventArgs e)
{
HttpContext.Current.Response.Redirect("http://localhost/approve.aspx", false);
}
/// <summary>
/// Subscribed by WF
/// </summary>
public event EventHandler<System.Workflow.Activities.ExternalDataEventArgs> Approved;
#endregion
}
When you have the interface you can set the properties of the “Ready for Approval”- and “Approve” activities (interface and method name/Event name).
In this samlpe I assume we are using two pages, one to create the mail, the second to approve it. We therefor need to have access to the runtime from both pages, so we need to cache the workflowruntime. There are different ways to do that. Get back to me if you don’t know how.
We need to add the ExternalDataExchange service to our runtime so that the workflow can subscribe to our event:
ExternalDataExchangeService de = new ExternalDataExchangeService();
workflowRuntimeHost.Runtime.AddService(de); // the “global host”
… and the add our service to the ExternalDataExchangeService:
EmailApprovalService emailApprovalService = new EmailApprovalService();
de.AddService(emailApprovalService);
workflowRuntimeHost.Runtime.StartRuntime();
After you’ve started the workflowruntime(Wich can only be done once):
WorkflowInstance wi = wr.CreateWorkflow([YOUR WORKFLOW TYPE]);
HttpContext.Current.Session[“workflowKey”] = wi.InstanceId;
wi.Start();
When the ReadyForAppoval activity is invoked from your workflow it will redirect to a new page (eg approve.aspx) where I assume we have a approve button:
protected void btnApprove_Click(object sender, EventArgs e)
{
object workflowInstanceID = HttpContext.Current.Session[“workflowKey”];
EmailApprovalService emailApprovalService = WorkflowRuntimeHost.Runtime.GetService<ExternalDataExchangeService>().GetService(typeof(EmailApprovalService)) as EmailApprovalService;
Guid wiID = (Guid)workflowInstanceID;
WorkflowInstance wi = WorkflowRuntimeHost.Runtime.GetWorkflow(wiID);
emailApprovalService.Approve(); //Call back to the WF.
}
I know this is a lot of code (you asked for it…). I haven’t tried it out, I’ve just ripped it from other similar applications. Hope it’ll help you.
Mikael
The ReadyForAppoval method takes a ExternalDataEventArgs as parameter. Create a class that inherits from ExternalDataEventArgs. Before you call the ReadyForAppoval from within your wf, add some activity/WF properties to the WorkflowEventArgs1.Properies.
[Serializable]
public class WorkflowEventArgs1 : ExternalDataEventArgs
{
public WorkflowEventArgs1(System.Guid InstanceId, List<string> properties)
: base(InstanceId)
{
this._properties = properties;
}
private List<string> _properties;
public List<string> Properties
{
get { return _properties; }
set { _properties = value; }
}
}
It might be easier if you send me your solution…