2

Is it possible to define a standard ServiceHostFactory foreach 'workflow' service (xamlx)

Our customers can make there own workflows (xamlx) using a custom workflow designer. We force the workflowservices into having a WS2007FederationHttpBinding with TransportSecurity. We turn of ServiceMetadataBehavior of for the WorkflowService and finally add a DataContractResolver that does some type resolving.

The ServiceHostFactory

    public class MyServiceHostFactory : WorkflowServiceHostFactory
{
    protected override WorkflowServiceHost CreateWorkflowServiceHost(
        System.ServiceModel.Activities.WorkflowService service,
        Uri[] baseAddresses)
    {
        WorkflowServiceHost host = base.CreateWorkflowServiceHost(service, baseAddresses);

        foreach (Uri adres in baseAddresses)
        {
            if (adres.Scheme == "https")
            {
                WorkflowCreationEndpoint endpoint = new WorkflowCreationEndpoint(
                    new WS2007FederationHttpBinding("IWorkflowService_ws2007FederationHttpBinding"),
                    new EndpointAddress(adres));

                host.AddServiceEndpoint(endpoint);

                PageflowDataContractResolver.AttachDataContractResolver(endpoint);
            }
        }

        var metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        metadataBehavior.HttpGetEnabled = false;

        host.WorkflowExtensions.Add(new WorkflowInstanceTracking());

        return host;
    }

    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        return base.CreateServiceHost(constructorString, baseAddresses);
    }

    protected override WorkflowServiceHost CreateWorkflowServiceHost(System.Activities.Activity activity, Uri[] baseAddresses)
    {            
        return base.CreateWorkflowServiceHost(activity, baseAddresses);
    }
}

The workflows exist in a database as Ron Jacob wrote in this blog. 'Consultants' and/or end users can create workflows using a custom tool, but each time they do they must not forget to add a serviceActivation element in the web.config which is not wanted.

<system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="false">
      <baseAddressPrefixFilters>
        <add prefix="http://localhost" />
      </baseAddressPrefixFilters>
      <serviceActivations>
        <add relativeAddress="~/Workflows/test.xamlx" service="Workflows/test.xamlx" factory="Foo.Bar.MyServiceHostFactory" />
      </serviceActivations>
    </serviceHostingEnvironment>
    <protocolMapping>
        <add scheme="https" binding="ws2007FederationHttpBinding" />
    </protocolMapping>
..
rfcdejong
  • 2,219
  • 1
  • 25
  • 51
  • I think I can help you out here, but can you expand on your solution a little so I can better understand the need and problem? Thanks! – Mike Perrenoud Feb 21 '12 at 18:08
  • i tryed to explain a bit more by showing the ServiceHostFactory – rfcdejong Feb 22 '12 at 09:04
  • What mechanism are they using to add the workflows to the database? – Mike Perrenoud Feb 22 '12 at 13:05
  • The idea is to build some tooling in which our customers can create the workflows, but that's the future. The tooling won't be able to alter the web.config either since the web.config is on the server and the tooling is a client on another computer. A customer writes a workflow and says publish, then the workflow is uploaded using to the server (using wcf or so) and inserted into the database. Changing the web.config meanwhile won't even be possible so we need to find a way around and assign each workflow to have ServiceHostFactory. For now it works doing it by hand but in the future it won't. – rfcdejong Feb 22 '12 at 13:24
  • I want you to take a look at a couple of things. First, take a look at this [article](http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/14/wcf-extensibility-servicehostfactory.aspx) -- it explains two other ways to achieve the same thing. Also look at this [article](http://stackoverflow.com/questions/9283576/invoke-child-workflow-activity-asynchronously) -- it breaks down the WCF integration with WF and may provide the flexibility you need. If it helps let me know and I'll post an answer. I personally think the second link is exactly what you need. – Mike Perrenoud Feb 22 '12 at 13:43
  • Sorry, but that second article showing a single workflow invoking child workflow's. That is what we started with and it evolved months later to seperate workflowservices. It all just works fine, dynamicly, the only exception is that we've to configure the ServiceHostFactory over and over again foreach workflow. The first article is pure WCF where a ServiceHostFactory can be set in the svc file thus not in the xamlx file :( – rfcdejong Feb 22 '12 at 15:41
  • OK - so let's start over - the goal here is to get it so when they upload the workflow via your custom tool to configure the Web.config so that the new workflow loads with your custom ServiceHostFactory right? – Mike Perrenoud Feb 24 '12 at 16:35
  • Its called file less configuration yes, new in c# 4. I think going back to a svc foreach workflow is even better because it doesb't require a web.config change. I could alter the stream in the open method inside a virtualfile returned by the virtualpathprovider – rfcdejong Feb 24 '12 at 21:49
  • Can I safely assume that each of these workflows that get created has some kind of unique identifier (name, guid) that you can use to resolve them from the DB? If so I think I can show you something using routes. – Drew Marsh Feb 27 '12 at 06:33
  • They have a unique identifier in the form of a GUID, but each one has a name as well which is unique. Anyway i've been using routes which also required web.config changes. The new WCF 4.0 route service don't fit the requirements we have, but go ahead :) – rfcdejong Feb 27 '12 at 07:07

1 Answers1

2

I think it would be correct to rephrase your question as:

Is there a way to change the default WorkflowServiceHostFactory for a web application so that config-less xamlx activation will use my WSHF instead.

If I have understood your question correctly then I don't think there is a way to do this. I had a quick look to see if there is a place you can override it but couldn't see any. Another way to achieve this is to modify the web.config as necessary when a user uploads a new workflow. Editing the web.config in-flight should result in any currently running pulses of execution being serviced by the existing AppDomain while a new AppDomain is created to service new requests to the web application. Thus no loss of workflow processing should occur. This of course would require some testing and verification.

UPDATE It looks like this might be possible. If you add the following to your web.config (which is from the default config for workflow activation).

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.xaml.hosting"
                  type="System.Xaml.Hosting.Configuration.XamlHostingSectionGroup,     System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <section name="httpHandlers"
               type="System.Xaml.Hosting.Configuration.XamlHostingSection, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </sectionGroup>
  </configSections>

  <system.xaml.hosting>
    <httpHandlers>
      <add xamlRootElementType="System.ServiceModel.Activities.WorkflowService, System.ServiceModel.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           httpHandlerType="System.ServiceModel.Activities.Activation.ServiceModelActivitiesActivationHandlerAsync, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add xamlRootElementType="System.Activities.Activity, System.Activities,     Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           httpHandlerType="System.ServiceModel.Activities.Activation.ServiceModelActivitiesActivationHandlerAsync, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpHandlers>
  </system.xaml.hosting>

</configuration>

The class ServiceModelActivitiesActivationHandlerAsync that this default config uses is implemented as follows:

internal class ServiceModelActivitiesActivationHandlerAsync : ServiceHttpHandlerFactory, IServiceModelActivationHandler
{
    // Methods
    public ServiceHostFactoryBase GetFactory()
    {
        return new WorkflowServiceHostFactory();
    }
}

Then instead of using the ServiceModelActivitiesActivationHandlerAsync, provide an implementation yourself which instantiates your own WorkflowServiceHostFactory in the GetFactory method. Update the web.config above to point to your new httpHandlerType and you should be done.

I haven't tested this at all. It's possible IIS will not like the web.config overriding the system.xaml.hosting section.

Peter Goodman
  • 404
  • 2
  • 5
  • Are u sure there is no way to change the default WorkflowServiceHostFactory? Maybe some code between IIS requesting the VirtualFiles and the VirtualPathProvider providing them where i alter the Stream being returned with the custom WorkflowServiceHostFactory assigned. This seems only possible for svc files so i'll have to drop the 'file less' configuration idea and foreach workflow return 2 files (1 svc with the factory defined and 1 xamlx) – rfcdejong Feb 27 '12 at 10:14
  • 1
    I've updated my answer with a possible solution. Give it a shot and let me know if it works. – Peter Goodman Feb 27 '12 at 22:59
  • It seems good enough to me, i'll try of IIS will accept it. If not i'll post it on connect or something, maybe Ron Jacobs knows hehe. I will mark your answer as answer and will reply here later If it worked. – rfcdejong Feb 27 '12 at 23:18
  • It almost was possible, but i run into a problem with a non-public interface being used in ServiceHostingEnvironment.cs PathInfo called IServiceModelActivationHandler, thru i posted another question on the msdn forums – rfcdejong Feb 28 '12 at 14:19
  • The link to it http://social.msdn.microsoft.com/Forums/is/wcf/thread/1d35c049-2122-4133-a177-b11e955c6b75 – rfcdejong Feb 28 '12 at 14:19
  • 1
    Sorry, missed that base class. As much as I understand the internal/public vs testing overhead problem for microsoft, it really does become a roadblock so many times. – Peter Goodman Feb 28 '12 at 19:20
  • Looks like a cool solution. Too bad MS is hiding the Interface from us. :( – Matt Ruwe Feb 25 '15 at 20:50