I am trying to host a WF4 (RC) Service dynamically. I have a test solution with two projects. The first is a declarative workflow service library with one root Flowchart activity in it, and a simple custom code activity. The workflow service library does not depend on any other custom assemblies or references. The second is my host app, which in my test solution is just a console application.
In my host app, I am attempting to the use ActivityXamlServices to load the Xaml for the workflow service into an activity, and then use the WorkflowServiceHost to fire up a workflow instance using that activity.
As soon as I try to new up the WorkflowServiceHost object, I get this exception...
Cannot create unknown type '{clr-namespace:DeclarativeServiceLibrary1}CodeActivity1'.
If I remove CodeActivity1 from my Flowchart designer, everything runs fine. If I add a direct reference to the workflow service project from my host project and then create a WorkflowServiceHost using an instance of my Flowchart activity instead of the activity created from the Xaml, it also works fine.
It seems to not like using my CodeActivity for some reason when loaded dynamically.
Anyone have any ideas as to why I can't dynamically create my workflow service?
My code is as follows...
DeclarativeServiceLibrary1.Activity1.xaml...
<Activity mc:Ignorable="sap" x:Class="DeclarativeServiceLibrary1.Activity1" sap:VirtualizedContainerService.HintSize="654,676" mva:VisualBasic.Settings="Assembly references and imported namespaces for internal implementation" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:DeclarativeServiceLibrary1" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Flowchart sad:XamlDebuggerXmlReader.FileName="C:\dev\test\MyWorkflow\DeclarativeServiceLibrary1\Activity1.xaml" sap:VirtualizedContainerService.HintSize="614,636">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">False</x:Boolean>
<av:Point x:Key="ShapeLocation">270,2.5</av:Point>
<av:Size x:Key="ShapeSize">60,75</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,77.5 300,107.5 300,165</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Flowchart.StartNode>
<FlowStep x:Name="__ReferenceID0">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">172.5,165</av:Point>
<av:Size x:Key="ShapeSize">255,90</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,255 300,285 300,299.5</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<p:Receive CanCreateInstance="True" sap:VirtualizedContainerService.HintSize="255,90" OperationName="MyOperation" ServiceContractName="MyContractName" />
<FlowStep.Next>
<FlowStep x:Name="__ReferenceID1">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">194.5,299.5</av:Point>
<av:Size x:Key="ShapeSize">211,61</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,360.5 300,390.5 300,399</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<WriteLine sap:VirtualizedContainerService.HintSize="211,61" Text="Workflow started" />
<FlowStep.Next>
<FlowStep x:Name="__ReferenceID3">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">200,399</av:Point>
<av:Size x:Key="ShapeSize">200,22</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,421 300,451 300,479.5</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<local:CodeActivity1 sap:VirtualizedContainerService.HintSize="200,22" />
<FlowStep.Next>
<FlowStep x:Name="__ReferenceID2">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">194.5,479.5</av:Point>
<av:Size x:Key="ShapeSize">211,61</av:Size>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<WriteLine sap:VirtualizedContainerService.HintSize="211,61" Text="The code activity worked!" />
</FlowStep>
</FlowStep.Next>
</FlowStep>
</FlowStep.Next>
</FlowStep>
</FlowStep.Next>
</FlowStep>
</Flowchart.StartNode>
<x:Reference>__ReferenceID0</x:Reference>
<x:Reference>__ReferenceID1</x:Reference>
<x:Reference>__ReferenceID2</x:Reference>
<x:Reference>__ReferenceID3</x:Reference>
</Flowchart>
</Activity>
DeclarativeServiceLibrary1.CodeActivity1.cs ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
namespace DeclarativeServiceLibrary1
{
public sealed class CodeActivity1 : CodeActivity
{
// Define an activity input argument of type string
//public InArgument<string> Text { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override void Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
//string text = context.GetValue(this.Text);
}
}
}
DeclarativeServiceLibrary1.Web.Config ...
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
ConsoleApplication1.Program.cs ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Activities.XamlIntegration;
using System.ServiceModel;
using System.ServiceModel.Activities;
using System.ServiceModel.Description;
using System.Xaml;
using System.Reflection;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string baseAddress = @"http://localhost:8081/MyContractName";
string curDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string wfDefPath = Path.Combine(curDir, "Activity1.xaml");
Activity workflowActivity = (Activity)ActivityXamlServices.Load(wfDefPath);
WorkflowService service = new WorkflowService { Body = workflowActivity };
Uri serviceUri = new Uri(baseAddress, UriKind.Absolute);
WorkflowServiceHost host = new WorkflowServiceHost(service, new Uri[] { serviceUri });
host.Open();
//Display that we are listening on the console window
Console.WriteLine("Workflow '{0}' is listening at '{1}'", host.Activity.DisplayName, baseAddress);
Console.ReadLine();
}
}
}
I have a post-build event in the delarative workflow service library that copies the Assembly and Xaml file into the bin\debug\ folder of the host console app.
Short answer - Xaml load can't infer the local (default) assembly, so you need to specify it on XamlReaderSettings.LocalAssembly.