Steps for integrating WCF and WF
hi
i am in learning stage of WCF and WF, I want to know that
1. while integrating wheather WCF hosts the WF or WF hosts the WCF.
2. Is there any detailed document about how to integrate WCF and WF
3. what are the necessary steps to follow for integration of WCF and WF.
thanks,
Answers
Hi,
1. Ive looked at this a little with the .net 3 release. As a proof of concept, i built a console app that hosted both the WCF services, and the WF workflow runtime. I implemented code in the WCF services to interace with the WF runtime, and create and manage the workflows.
2. I've not seen any good docs for how to do this with .net 3, but there's a cople of good blog articles on doing this with .net 3.5 beta 1 and Orcas posted by Guy Burstein:
http://blogs.microsoft.co.il/blogs/bursteg/
3. I'd recomend taking a look at beta 1 of Orcas if it's possible in your project. It seems that the new version provides much better OOB integration.
Regards,
Alan
All Replies
Hi,
1. Ive looked at this a little with the .net 3 release. As a proof of concept, i built a console app that hosted both the WCF services, and the WF workflow runtime. I implemented code in the WCF services to interace with the WF runtime, and create and manage the workflows.
2. I've not seen any good docs for how to do this with .net 3, but there's a cople of good blog articles on doing this with .net 3.5 beta 1 and Orcas posted by Guy Burstein:
http://blogs.microsoft.co.il/blogs/bursteg/
3. I'd recomend taking a look at beta 1 of Orcas if it's possible in your project. It seems that the new version provides much better OOB integration.
Regards,
Alan
- It is certainly possible to integrate WF and WCF today using custom ServiceHosts and invoking workflows directly. I'll be doing a session at TechED US on that topic - http://www.masteringbiztalk.com/blogs/jon/PermaLink,guid,116a206e-db52-41de-afb4-17a6e022e093.aspx and hopefully around that time or soon after that a sample I've built for MS will be made public that relates to WF autohosting in WCF using .NET 3.0 and not Orcas.
ramkasarla,
- Definitely, you should look at the OrcasBeta1 features, that's the primary goal of the .netfx 3.5 - connected systems using these technologies.
- For the current .netfx 3.0 version, the WCF/WF hosting and raising the workflow HEEA event can be really simply like is shown in the following code snippet, service1.svc file:
Code Snippet<%@ServiceHost
Language=C#
Debug="true"
Service="ServiceTest1"
Factory="RKiss.WorkflowEventService.ServiceHostActivation, WorkflowEventService" %>// .netfx3
using System;
using System.ServiceModel;
using System.Workflow.Activities;// WCF/WF integration
using RKiss.WorkflowEventService;// application specific
using WorkflowLibrary1;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ServiceTest1
{
[OperationContract(IsOneWay = true)]
[WorkflowFireEvent(EventType = typeof(IWorkflowEvent))]
public void Approve(object sender, ExternalDataEventArgs e)
{
throw new NotImplementedException();
}
}where, the Factory attribute of the @ServiceHost enables to integrate WCF hosting with WorkflowRuntime. The following example shows its implementation:
Code Snippetusing
System;using
System.Diagnostics;using
System.Collections.Generic;using
System.Text;using
System.Workflow.Runtime;using
System.ServiceModel;using
System.ServiceModel.Activation;using
System.Reflection;namespace
ConsoleApplication1{
public class WorkflowRuntime2 : WorkflowRuntime, IExtension<ServiceHostBase>
{
public WorkflowRuntime2() : this("WorkflowRuntimeConfig") { }
public WorkflowRuntime2(string configSection) : base(configSection) { }
public void Attach(ServiceHostBase owner)
{
base.StartRuntime();
}
public void Detach(ServiceHostBase owner)
{
if (base.IsStarted)
base.StopRuntime();
}
}
public class ServiceHostActivation : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, params Uri[] baseAddresses)
{
return Create(constructorString, baseAddresses);
}
public static ServiceHost Create(string constructorString, params Uri[] baseAddresses)
{
// find the type of the service
Type serviceType = Type.GetType(constructorString, false);
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(constructorString, false);
if (serviceType != null)
{
break;
}
}
// validate type
if (serviceType == null)
throw new ArgumentException("Can't find the assembly to create a service type");
return Create(serviceType, baseAddresses);
}
public static ServiceHost Create(Type serviceType, params Uri[] baseAddresses)
{
// create wcf host
ServiceHost host = new ServiceHost(serviceType, baseAddresses);
host.Closing += new EventHandler(host_Closing);
// Service extension for WF
WorkflowRuntime2 workflowRuntime = new WorkflowRuntime2();
// Add the Extension to the ServiceHost collection
host.Extensions.Add(workflowRuntime);
return host;
}
private static void host_Closing(object sender, EventArgs e)
{
WorkflowRuntime wr = (sender as ServiceHost).Extensions.Find<WorkflowRuntime>();
if (wr != null)
{
wr.Dispose();
}
}
}
}
The above servive.svc file also integrates a service operation contract with a workflow contract using the custom WorkflowFireEvent attribute described in the article Fire WorkflowEvent from WCF. This attribute enables to forward the wcf message to the workflow queue.
The service.svc needs to have a web.config file, where are located all metadata for this connected systems:
Code Snippet<configuration>
<configSections>
<section name="WorkflowRuntimeConfig" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<section name ="LocalServicesConfig" type ="System.Workflow.Activities.ExternalDataExchangeServiceSection, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>
<WorkflowRuntimeConfig >
<Services>
<add type="System.Workflow.Activities.ExternalDataExchangeService, System.Workflow.Activities, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ConfigurationSection="LocalServicesConfig" />
<!--<add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>-->
<add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="10" ConnectionString="Initial Catalog=PersistenceStore;Data Source=localhost\SQLEXPRESS;Integrated Security=SSPI;"/>
<add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="10" ConnectionString="Initial Catalog=TrackingStore;Data Source=localhost\SQLEXPRESS;Integrated Security=SSPI;" />
</Services>
</WorkflowRuntimeConfig>
<LocalServicesConfig>
<Services>
</Services>
</LocalServicesConfig>
<system.serviceModel>
<services>
<service name="ServiceTest1" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding"/>
<endpoint address="" contract="ServiceTest1" binding="wsHttpBinding"/>
</service>
</services>
<bindings>
<wsHttpBinding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.Workflow.Activities,
Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
</system.web>
</configuration>
Thanks
Roman
RKiss,
Do you have a solution for this posted somewhere? Or does anybody have an example of the ExpenseReporting V2 service where they've modified it to work with WCF being hosted via IIS?
Thanks.
For easy WCF/WF integration you can also use the Custom activities I published on CodePlex that provide an implementation like the ASMX input and output activities currently in the product. This way you can pick an interface and method you want to implement in your workflow and add a corresponding output activity when you have the results of the service method.
The code will handle workflow instantiation, correlation between input and output and also plugs into the correct workflow runtime you are hosting.
Using these activities will keep you from writing plumbing code yourself and keep your code as clean as possible so you can easily migrate to ORCAS features once they ship.
You can find the docs and samples as http://www.codeplex.com/WCFWorkflow
Regards,
Marcel
Marcel,
Thanks for the post. Questions.
1) Where is the source to these activities? Not sure about anybody else but not a good practice to implement components in production posted on the web without the source to be able to troubleshoot and fix in house if necessary? I've been looking but have yet to run across the bits behind the activities. Are these available.
2) I would still like to know the process of doing this behind the scenes. MS should put out more real world examples and hosting WCF via IIS seems like a theme of interest. The Expense Reporting V2 example is a pretty decent sample but like most others relies on a console app for hosting which I would contend that not many writing real world apps is going to rely on? I'm trying to modify pick through snippets here and there to try and figure out how to configure the web.config etc to get a version of the ExpenseReporting sample to work using IIS as a host?
Has anybody already done this and could post? Or anybody with experience of integrating WF with WCF possibly be willing to look at the expense reporting example and post the mods necessary. RKiss's post seems to be on the right track but seems to be missing some relavent info to completely get things work.
Thanks.
kfrost,
The following steps are WCF and WF basic integration:
1. Hosting: - WCF and WF hosting is done in the .svc file using the Factory attribute. This is a custom hosting based on the ServiceHostFactoryBase class and its source code can be downloaded from Fire WorkflowEvent from WCF or from this thread - see my previously post.
Code Snippet, service1.svc<%@ServiceHost
Language=C#
Debug="true"
Service="ServiceTest1"CodeBehind="~/App_Code/Service1.cs"
Factory="RKiss.WorkflowEventService.ServiceHostActivation, WorkflowEventService" %>2. Invoking Worfklow in the codeBehind using a Worfklow Local Service:
Code Snippet[ServiceContract]
public class ServiceTest1 : IMyInterface
{
[OperationContract]
public void Approve(object sender, ExternalDataEventArgs e)
{
// Get reference to the WorkflowRuntime
WorkflowRuntime workflowRuntime = OperationContext.Current.Host.Extensions.Find<WorkflowRuntime>();// raise event on the Worfklow Local Service
// todo:
}
}Thanks
Roman
Hey Roman,
Thanks for the post but not using code behind in the svc file. I would imagine anybody writing a production app, the code for the service is in a separate assembly.
I've been trying to piece through your example from your website and I've found links on the Factory setting at.
Thread on IIS hosting
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1588040&SiteID=1
@ServiceHost parameters in a svc file.
http://msdn2.microsoft.com/en-us/library/aa967286.aspx
Even still trying to piece meal incomplete code snippets from forums still not happening, getting an error that it can't load specific type. You use ServiceHostFactoryBase but Microsoft examples use just ServiceHostFactory. Not sure why the difference but again, it's fighting through trying to get something to work.
My comments were in hopes that Microsoft was monitoring these threads. It would be nice to have examples such as expenseReporting that mimicked real world. The app and concepts itself are good, but the host as with most, a console app was used which is fine as a for an example that could be followed for hosting via a windows service but Not very helpful when utilizing IIS.
Sure will get through it eventually but it would be nice to have complete relevant examples from Microsoft to cut out the "get through it eventually" portions everytime trying to learn a product from them.
Thanks again for the posts
kfrost,
- To perform IIS/WCF hosting via @ServiceHost directive, the type on the optional attribute Factory must be derived from ServiceHostFactoryBase class in order to call its abstract method:
public abstract ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses);
where the constructorString parameter is a name of the service type. The method has a responsibility to convert this string to the actually type and returning the ServiceHost reference:
return new ServiceHost(serviceType, baseAddresses);
Additionally, in my custom ServiceHostActivation class, the WorkflowRuntime is attached to the service host.
I think, the problem can be related to the assembly reference or endpoint configuration. Check the assemblies in the /bin folder.
Thanks
Roman
well I posted everything on codeplex and there you can download the latest changeset that contains all the sources.(including a sample applciation and step by step guide)
See following link to the latest change set: http://www.codeplex.com/WCFWorkflow/SourceControl/DownloadSourceCode.aspx?changeSetId=2184
Also the installer intalls the sources of the activities in the program files/beyondDotNet folder. There you will also find the step by step guide.
Hope that helps,
Regards,
Marcel
Ok, still plugging away at this thing. MS, if you are watching would be tremendously nice if you could post a complete example of this working. Everybody else that has posted, thanks but it's a pain trying to sort through others half posts trying to piece together. Roman, tried to add an IIS host to your example but keep running into nagging glitches you get when you haven't done something before and you have an hour or two here and there per week to try and make sense of a bunch of piece meal.
Looking at it all today, I'm back to the expense reporting example to possibly get it to work. It appears that everything in the wcfextensions file is needed. But when you want utilize IIS as a host, you need to add the factory class as roman has pointed out. What I'm experimenting with now is just adding his code at the bottom of his file like this.
public class ServiceHostActivation : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, params Uri[] baseAddresses)
{
return Create(constructorString, baseAddresses);
}public static ServiceHost Create(string constructorString, params Uri[] baseAddresses)
{
// find the type of the service
Type serviceType = Type.GetType(constructorString, false);foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(constructorString, false);
if (serviceType != null)
{
break;
}
}// validate type
if (serviceType == null)
{
throw new ArgumentException("Can't find the assembly to create a service type");
}
return Create(serviceType, baseAddresses);
}public static ServiceHost Create(Type serviceType, params Uri[] baseAddresses)
{
// create wcf host
ServiceHost host = new ServiceHost(serviceType, baseAddresses);
host.Closing += new EventHandler(host_Closing);// Service extension for WF Supply Web.Config section with parameters
WfWcfExtension workflowRuntime = new WfWcfExtension("WorkflowRuntimeConfig");// Add the Extension to the ServiceHost collection
host.Extensions.Add(workflowRuntime);return host;
}
private static void host_Closing(object sender, EventArgs e)
{
WorkflowRuntime wr = (sender as ServiceHost).Extensions.Find<WorkflowRuntime>();
if (wr != null)
{
wr.Dispose();
}
}
}Then the svc file looks as such: (To do this you'll need to setup a IIS website and add a wcf service file)
<%@ ServiceHost Language="C#" Debug="true"
Service="ExpenseServices.ExpenseService, ExpenseService"
Factory="WcfExtensions.ServiceHostActivation, WcfExtensions" %>With the web.config looking like this so far. (May be some kinks with it that I haven't worked out.)
<configuration>
<configSections>
<section name="WorkflowRuntimeConfig" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections><WorkflowRuntimeConfig>
<Services>
<add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ConnectionString="Initial Catalog=WorkflowPersistence;Data Source=sc430x64-01;Integrated Security=SSPI;"/>
<add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ConnectionString="Initial Catalog=WorkflowTracking;Data Source=sc430x64-01;Integrated Security=SSPI;" IsTransactional="false" UseDefaultProfile="true" TrackXomlDocument="True"/>
</Services>
</WorkflowRuntimeConfig>
<system.serviceModel>
<services>
<!-- Before deployment, you should remove the returnFaults behavior configuration to avoid disclosing information in exception messages -->
<service name="ExpenseServices.ExpenseService" behaviorConfiguration="ExpenseServiceBehavior">
<endpoint contract="ExpenseContracts.IExpenseService" binding="wsHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ExpenseServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<appSettings/>
<connectionStrings/>Trying to get everything to compile and then try to change the Expense and Manager App to utilize the IIS svc and see where it gets me.
I'll post results when I get finished
Roman,
With Expense Reporting with the mods above I'm back to the same problem I had trying to utilize your code in another example. I'm not understanding this intent for this section of code.
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(constructorString, false);
if (serviceType != null)
{
break;
}
}// validate type
if (serviceType == null)
{
throw new ArgumentException("Can't find the assembly to create a service type");
}there are plenty of assemblies but all equate to null and throws an exception. To add to this, if I comment this section of my code then things appear to work. Roman, could you please ellobrate on this section and by chance have any comments as to whether it's needed or not?
Thanks.
Can't find the assembly to create a service type
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: Can't find the assembly to create a service type
Source Error:
Line 113: if (serviceType == null) Line 114: { Line 115: throw new ArgumentException("Can't find the assembly to create a service type"); Line 116: } Line 117: return Create(serviceType, baseAddresses);
Source File: C:\Data\TFS\corp-tfs-01\Template\ExpenseReporting\ExpenseReporting\WCFExtensions\WfWcfExtension.cs Line: 115
Stack Trace:kfrost,
- all assemblies must be in the \bin folder or GAC.
- correct my code by the following code snippet.
Code Snippet - correction// find the type of the serviceType serviceType = Type.GetType(constructorString, false);
if(serviceType == null)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(constructorString, false);
if (serviceType != null)
{
break;
}
}
}
Thanks
Roman
Yes, but why. I wouldn't really care to register the assemblies in the GAC in this case. That wouldn't seem impratical. Plus if I just remove that code, the call into the factory has the correct config string and everything and appears to work if I comment the code out you posted.
What would the code in question here buy me and if it were something important is there another way because registering the assemblies in this case in the GAC would probably not be an option.
Thanks.
kfrost,
- that's the option by IIS (~/bin or GAC)
- have a look at the @Assembly directive
- in order to configure WCF service, the Service attribute (aka constructorString) must be converted to the service type for creating a ServiceHost.
In your case: Service="ExpenseServices.ExpenseService" will find a service type through walking all loaded assemblies.
Thanks
Roman
Ah, ok I think I'm a little more clear on your thought process. The web project does have a reference to the ExpenseService project and the dll for this assembly is created in the Bin folder of the IIS project. Earlier I was having a problem indicating the method for assembly ExpenseService could not be loaded. In the error it pointed out where the assembly had to be located and bin file was an option as you mentioned. (My problem there was I erroneous had the serviceHostActivation class nested inside the WfWcfExtension class in the WcfWfExtensions namespace.)
Past that, now when I attach the debugger to aspnetwp.exe and I step into it. When the Create class is fired from the CreateServiceHost constructor, constructor string is set to ExpenseServices.ExpenseService and serviceType does have a valid value. As I mention, if I comment out your foreach loop, serviceType upon the inital call is set to a valid value and everything appears to work. (I'll know for sure when I have a chance to change the host the apps are utilizing in the sample.)
So with that said, i kind of see what was being done with the foreach loop but confused as to why it's needed because what I see at present, the serviceType is getting set to the correct Type in the first call.
// find the type of the service
Type serviceType = Type.GetType(constructorString, false);The foreach loop appears to be trying to find the exact same thing. Shouldn't there be a conditional statement surrounding the foreach in the example to where if serviceType is not null as a result of:
Type serviceType = Type.GetType(constructorString, false);
As I talk about it an understand it now, it seems as if this statement would populate serviceType correctly if you add a reference to the correct assembly and it's present in the bin file. (As I'm witnessing.) If not present here, then the foreach loop would be used to go out and try to find it in the gac as you mentioned?
kfrost,
- that's correct, I apologize for the following bug:
Code Snippet - correction// find the type of the service
Type serviceType = Type.GetType(constructorString, false);
if(serviceType == null)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(constructorString, false);
if (serviceType != null)
{
break;
}
}
}
Btw., in the .Net Framework 3.5 (Orcas/B1), the Service attribute can have also a name of the xoml file - see the System.ServiceModel.Activation.WorkflowServiceHostFactory class.
Thanks
Roman
Thanks Roman,
I think I've got everything setup to where the Workflow runtime is loading and have it referencing the local service. Now I'm into the bindings trying to mimick what expense reporting has in a console app.
I used wcf to create extra bindings that point to IExpenseManager and IExpenseServiceClient but when I try to open the svc I get the error.
A binding instance has already been associated to listen URI 'http://clt-wxp-11.clt.pcts.com/ExpenseReporting/ExpenseService.svc'. If two endpoints want to share the same ListenUri, they must also share the same binding object instance. The two conflicting endpoints were either specified in AddServiceEndpoint() calls, in a config file, or a combination of AddServiceEndpoint() and config.
I've tried adding a new service in the WCF editor but can't because ExpenseService is the only service available in the projects?
I'm wondering if I have to create 2 more svc files, one for the client and one for the manager to get this to work and then set the contracts to the appropriate interfaces?
Any thoughts?
Ok, per this article:
http://msdn.microsoft.com/msdnmag/issues/07/06/ServiceStation/
Appears you have to add relative addresses for each additional endpoint bound to a service. I did this and ran the add service reference from the ManagerApplication and notice in the app.config file it does add the endpoints as ExpenseReporting/ExpenseService.svc/client
Ok, hit a snag. Utilizing the expense reporting and other examples thought I had everything up and running. However, I found the following is generating an exception.
private
void SetUpWorkflowEnvironment(){
if (arithmeticLocalService == null){
WfWcfExtension extension = OperationContext.Current.Host.Extensions.Find<WfWcfExtension>();workflowRuntime = extension.WorkflowRuntime;
// We will try and fetch the instance from the active WorkflowRuntime's // ExtenalDataExchangeService and if it currently does not have an // activated instance, we will create a new instance and add it. ExternalDataExchangeService dataExchangeService =workflowRuntime.GetService<
ExternalDataExchangeService>();arithmeticLocalService =
(
ArithmeticLocalService)dataExchangeService.GetService(typeof(ArithmeticLocalService)); if (arithmeticLocalService == null){
arithmeticLocalService =
new ArithmeticLocalService(workflowRuntime);dataExchangeService.AddService(arithmeticLocalService);
}
// Events are then wired up to our local event handlers //arithmeticLocalService.ManagerApprovalRequested += // new EventHandler<ManagerApprovalRequestedEventArgs>(arithmeticLocalService_ManagerApprovalRequested); //arithmeticLocalService.ManagerReviewed += // new EventHandler<ManagerReviewedEventArgs>(arithmeticLocalService_ManagerReviewedOrTimeout);}
}
workflowRuntime.GetService<ExternalDataExchangeService>();
Kind of puzzled how that call is causing the exception, "More than one Runtime Service exists of Type: ExternalDataExchangeService"
This is supposed to be getting registered in the web.config. Plus that statement to me means it's going out and trying to look for it, not create it so the error doesn't make sense.
Any ideas?
The above exception turned out to be valid. To get around the problem above I commented out the add section in the web.config. I found a piece of code in the WcfExtensions code i borrowed from the expenseReporting example and commented it out to resolve the problem.
Now to the next dilemma. I have everything running and working but I see some potential pitfals.
First I had to utilize an AutoResetEvent and implement waitOne after the call to start the workflow Instance.
private
AutoResetEvent _waitHandle = new AutoResetEvent(false);SetUpWorkflowEnvironment();
// If client supplies instanceId to an existing or persisted workflow, // use it, if not create a new one if (instanceId != Guid.Empty){
instanceId = clientInstanceId;
}
else{
instanceId =
Guid.NewGuid();}
Assembly asm = Assembly.Load("ArithmeticWF"); Type workflowType = asm.GetType("ArithmeticWF.DivideWorkflow"); // Need to populate Dictionary here to pass params in. Dictionary<string, object> wfParams = new Dictionary<string, object>(); // Params of dictionary must match the object name in the workflowwfParams.Add(
"ProductObj", product); WorkflowInstance workflowInstance = workflowRuntime.CreateWorkflow(workflowType, wfParams, instanceId);workflowInstance.Start();
// This must be here to give the workflow time to run and it uses the workflow_completed event to populate // result. if you remove this, returnValue will return back as 0._waitHandle.WaitOne();
// Return value was set in the workflow_completed event using e.OutputParameters["DivideWorkflow_ReturnVal"]
response.ReturnVal = product.Val1 /
this.ReturnValue;This works but the problem is, that the waitOne() causes the workflowRuntime to block until the workflow is finished. So you take a one workflow that takes 15 seconds to finish and then you start handling hundreds to thousands of simultaneous client requests, then we're moving towards performance problems.
I'm assuming the next thing I have to figure out is in this environment how to spin up new workflowRuntime's when there isn't one available to handle a client request? Correct? Any input to this thread pertaining to this would be appreciated.
Thanks.

