I'm trying to run an activity but I get this error at run time:
Expression Activity type 'CSharpValue`1' requires compilation in order to run. Please ensure that the workflow has been compiled.
looking in the unit test output I see:
30: WorkflowInstance "PatriarchActivity" Unhandled Exception Source "Assign<SortedList<IntContainer,SimpleData>>" Exception <System.NotSupportedException: Expression Activity type 'CSharpValue`1' requires compilation in order to run. Please ensure that the workflow has been compiled.
the compilation seems to run ok.
I used the code in this page to compile the workflow: http://msdn.microsoft.com/en-us/library/jj591618%28v=vs.110%29.aspx#CodeWorkflows
I have no clue what the problem is, and the message is not helpful as where the error lies imho. yeah, got it, something hasn't been compiled, then how do I compile it?
would be very grateful for an explanation.
I'm using visual 2013 update 4 with .net 4.5.1
Here is a small test case which I hope highlights correctly the problem.
namespace WFCS
{
public sealed class ActivityCompiler
{
private static readonly ActivityCompiler instance_ = new ActivityCompiler();
public static ActivityCompiler Instance
{
get
{
return instance_;
}
}
public SimpleActivity GetSimpleActivity()
{
SimpleActivity act = new SimpleActivity();
AttachableMemberIdentifier impl = new AttachableMemberIdentifier(typeof(TextExpression), "Namespaces");
AttachablePropertyServices.SetProperty(act, impl, ActivityCompiler.Instance.GetSimpleActivityNameSpaceList());
TextExpression.SetReferencesForImplementation(act, ActivityCompiler.Instance.GetSimpleActivityAssemblyReferenceList().ToList());
ActivityCompiler.Instance.Compile(act);
return act;
}
public Boolean Compile(Activity aActivity)
{
try
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions.
string activityName = aActivity.GetType().ToString();
// Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
// to represent the new type that represents the compiled expressions.
// Take everything after the last . for the type name.
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = aActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = "CSharpExpression",
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = false
};
// Compile the C# expression.
TextExpressionCompilerResults results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
// Create an instance of the new compiled expression type.
ICompiledExpressionRoot compiledExpressionRoot =
Activator.CreateInstance(results.ResultType,
new object[] { aActivity }) as ICompiledExpressionRoot;
// Attach it to the activity.
CompiledExpressionInvoker.SetCompiledExpressionRoot(
aActivity, compiledExpressionRoot);
}
catch (Exception e)
{
string err = e.ToString();
return false;
}
return true;
}
public Boolean CompileDynamicActivity(Activity aDynamicActivity)
{
try
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions.
string activityName = aDynamicActivity.GetType().ToString();
// Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
// to represent the new type that represents the compiled expressions.
// Take everything after the last . for the type name.
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = aDynamicActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = "CSharpExpression",
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = true
};
// Compile the C# expression.
TextExpressionCompilerResults results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new Exception("Compilation failed in ActivityCompiler");
}
// Create an instance of the new compiled expression type.
ICompiledExpressionRoot compiledExpressionRoot =
Activator.CreateInstance(results.ResultType,
new object[] { aDynamicActivity }) as ICompiledExpressionRoot;
// Attach it to the activity.
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
aDynamicActivity, compiledExpressionRoot);
}
catch (Exception e)
{
string err = e.ToString();
throw e ;
}
return true;
}
private HashSet<AssemblyReference> GetSimpleActivityAssemblyReferenceList()
{
HashSet<AssemblyReference> ass = new HashSet<AssemblyReference>();
ass.Add(new AssemblyReference { Assembly = typeof(StringContainer).Assembly, AssemblyName = typeof(StringContainer).Assembly.GetName() });
ass.Add(new AssemblyReference { Assembly = typeof(IntContainer).Assembly, AssemblyName = typeof(IntContainer).Assembly.GetName() });
ass.Add(new AssemblyReference { Assembly = typeof(System.Runtime.Serialization.IExtensibleDataObject).Assembly, AssemblyName = typeof(IExtensibleDataObject).Assembly.GetName() });
return ass;
}
private HashSet<String> GetSimpleActivityNameSpaceList()
{
HashSet<String> ns = new HashSet<String>();
ns.Add(typeof(StringContainer).Namespace);
ns.Add(typeof(IntContainer).Namespace);
return ns;
}
public MotherActivity GetMotherActivity()
{
MotherActivity act = new MotherActivity();
AttachableMemberIdentifier impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
AttachablePropertyServices.SetProperty(act, impl, ActivityCompiler.Instance.GetMotherActivityNameSpaceList());
TextExpression.SetReferencesForImplementation(act, ActivityCompiler.Instance.GetMotherActivityAssemblyReferenceList().ToList());
ActivityCompiler.Instance.CompileDynamicActivity(act);
return act;
}
private HashSet<AssemblyReference> GetMotherActivityAssemblyReferenceList()
{
HashSet<AssemblyReference> ass = new HashSet<AssemblyReference>();
ass.UnionWith(ActivityCompiler.Instance.GetSimpleActivityAssemblyReferenceList());
ass.Add(new AssemblyReference { Assembly = typeof(System.Runtime.Serialization.IExtensibleDataObject).Assembly, AssemblyName = typeof(IExtensibleDataObject).Assembly.GetName() });
return ass;
}
private HashSet<String> GetMotherActivityNameSpaceList()
{
HashSet<String> ns = new HashSet<String>();
ns.UnionWith(ActivityCompiler.Instance.GetSimpleActivityNameSpaceList());
return ns;
}
public PatriarchActivity GetPatriarchActivity()
{
PatriarchActivity act = new PatriarchActivity();
AttachableMemberIdentifier impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
AttachablePropertyServices.SetProperty(act, impl, ActivityCompiler.Instance.GetPatriarchActivityNameSpaceList());
TextExpression.SetReferencesForImplementation(act, ActivityCompiler.Instance.GetPatriarchActivityAssemblyReferenceList().ToList());
ActivityCompiler.Instance.CompileDynamicActivity(act);
return act;
}
private HashSet<AssemblyReference> GetPatriarchActivityAssemblyReferenceList()
{
HashSet<AssemblyReference> ass = new HashSet<AssemblyReference>();
ass.UnionWith(ActivityCompiler.Instance.GetMotherActivityAssemblyReferenceList());
return ass;
}
private HashSet<String> GetPatriarchActivityNameSpaceList()
{
HashSet<String> ns = new HashSet<String>();
ns.UnionWith(ActivityCompiler.Instance.GetMotherActivityNameSpaceList());
return ns;
}
}
}
namespace WFCS
{
[DataContract]
public class IntContainer : IComparable
{
[DataMember]
public Int32 Value;
public IntContainer(int aInt32)
{
this.Value = aInt32;
}
public int CompareTo(object obj)
{
return this.Value.CompareTo(((IntContainer)obj).Value);
}
}
}
namespace WFCS
{
public class MotherActivity : Activity
{
[RequiredArgument]
public InArgument<IntContainer> IntToAdd { get; set; }
[RequiredArgument]
public InArgument<SortedList<IntContainer, SimpleData>> DataToProcess { get; set; }
[RequiredArgument]
public OutArgument<SortedList<IntContainer, SimpleData>> ProcessedData { get; set; }
private DelegateInArgument<SimpleData> simpleDataIterator;
private Variable<SimpleData> wfvar_tmpsimpledata;
private SimpleData native_tmpsimpledata;
protected override Func<Activity> Implementation
{
get
{
return () =>
{
Sequence seq = new Sequence
{
Variables =
{
},
Activities =
{
new WriteLine
{
Text = new InArgument<String>((env) => "I'm entering the mother activity processing nb = " + DataToProcess.Get(env).Count)
},
new Assign<SortedList<IntContainer, SimpleData>>
{
To = new CSharpReference<SortedList<IntContainer, SimpleData>>("ProcessedData"),
Value = new CSharpValue<SortedList<IntContainer, SimpleData>>("new SortedList<IntContainer, SimpleData>()"),
},
new ForEach<SimpleData>
{
Values = new InArgument<IEnumerable<SimpleData>>((env) => (IList<SimpleData>)DataToProcess.Get(env).Values),
Body = new ActivityAction<SimpleData>()
{
Argument = simpleDataIterator,
Handler = new Sequence()
{
Variables =
{
wfvar_tmpsimpledata
},
Activities =
{
new Assign<SimpleData>
{
To = new CSharpReference<SimpleData>("WFVAR_tmpsimpledata"),
Value = new InArgument<SimpleData>((env) => simpleDataIterator.Get(env))
},
new SimpleActivity
{
IntContainer = new CSharpValue<IntContainer>("new WFCS.IntContainer(IntToAdd.Value + WFVAR_tmpsimpledata.ID.Value);"),
StringContainer = new CSharpValue<StringContainer>("new WFCS.StringContainer(\"toto\");"),
Result = new CSharpReference<SimpleData>("WFVAR_tmpsimpledata")
},
new AddToCollection<KeyValuePair<IntContainer, SimpleData>>
{
Collection = new InArgument<ICollection<KeyValuePair<IntContainer,SimpleData>>>((env) => ProcessedData.Get(env)),
Item = new InArgument<KeyValuePair<IntContainer, SimpleData>>( (env) => (new KeyValuePair<IntContainer, SimpleData>(wfvar_tmpsimpledata.Get(env).ID,
wfvar_tmpsimpledata.Get(env))))
}
}
}
}
}
}
};
return seq;
};
}
set
{
base.Implementation = value;
}
}
public MotherActivity()
{
simpleDataIterator = new DelegateInArgument<SimpleData>();
native_tmpsimpledata = new SimpleData(0, "notset");
wfvar_tmpsimpledata = new Variable<SimpleData>("WFVAR_tmpsimpledata", ctx => native_tmpsimpledata);
}
}
}
namespace WFCS
{
public class PatriarchActivity : Activity
{
// remove this "fake" input
//[RequiredArgument]
//public InArgument<SortedList<IntContainer, SimpleData>> DataToProcess { get; set; }
[RequiredArgument]
public OutArgument<SortedList<IntContainer, SimpleData>> ProcessedData { get; set; }
IntContainer native_intcontainer;
Variable<IntContainer> wfvar_intcontainer;
SortedList<IntContainer, SimpleData> native_dataToProcess;
Variable<SortedList<IntContainer, SimpleData>> wfvar_dataToProcess;
protected override Func<Activity> Implementation
{
get
{
return () =>
{
Sequence seq = new Sequence
{
Variables =
{
wfvar_intcontainer, wfvar_dataToProcess
},
Activities =
{
new Assign<SortedList<IntContainer, SimpleData>>
{
To = new CSharpReference<SortedList<IntContainer, SimpleData>>("WFVAR_dataToProcess"),
Value = new CSharpValue<SortedList<IntContainer, SimpleData>>("new SortedList<IntContainer, SimpleData>()"),
},
new Assign<SortedList<IntContainer, SimpleData>>
{
To = new CSharpReference<SortedList<IntContainer, SimpleData>>("ProcessedData"),
Value = new CSharpValue<SortedList<IntContainer, SimpleData>>("new SortedList<IntContainer, SimpleData>()"),
},
new AddToCollection<KeyValuePair<IntContainer, SimpleData>>
{
Collection = wfvar_dataToProcess,
Item = new InArgument<KeyValuePair<IntContainer, SimpleData>>( (env) => (new KeyValuePair<IntContainer, SimpleData>(new IntContainer(1),
new SimpleData(1, "toto"))))
},
new AddToCollection<KeyValuePair<IntContainer, SimpleData>>
{
Collection = wfvar_dataToProcess,
Item = new InArgument<KeyValuePair<IntContainer, SimpleData>>( (env) => (new KeyValuePair<IntContainer, SimpleData>(new IntContainer(2),
new SimpleData(2, "titi"))))
},
new WriteLine
{
Text = new InArgument<String>((env) => "I'm in the patriarch activity processing nb = " + wfvar_dataToProcess.Get(env).Count)
},
new MotherActivity
{
IntToAdd = new CSharpValue<IntContainer>("WFVAR_intcontainer"),
DataToProcess = new CSharpValue<SortedList<IntContainer, SimpleData>>("WFVAR_dataToProcess"),
ProcessedData = new CSharpReference<SortedList<IntContainer,SimpleData>>("ProcessedData")
}
}
};
return seq;
};
}
set
{
base.Implementation = value;
}
}
public PatriarchActivity()
{
native_intcontainer = new IntContainer(42);
wfvar_intcontainer = new Variable<IntContainer>("WFVAR_intcontainer", ctx => native_intcontainer);
//native_dataToProcess = new SortedList<IntContainer, SimpleData>();
//wfvar_dataToProcess = new Variable<SortedList<IntContainer, SimpleData>>("WFVAR_dataToProcess", ctx => native_dataToProcess);
wfvar_dataToProcess = new Variable<SortedList<IntContainer, SimpleData>>("WFVAR_dataToProcess");
}
}
}
namespace WFCS
{
public class SimpleActivity : NativeActivity<SimpleData>
{
[RequiredArgument]
public InArgument<StringContainer> StringContainer { get; set; }
[RequiredArgument]
public InArgument<IntContainer> IntContainer { get; set; }
protected override void Execute(NativeActivityContext context)
{
this.Result.Set(context, new SimpleData(context.GetValue(IntContainer).Value,
context.GetValue(StringContainer).Value));
}
}
}
namespace WFCS
{
[DataContract]
public class SimpleData
{
[DataMember]
public IntContainer ID;
[DataMember]
public StringContainer Str;
public SimpleData(Int32 aInt32, String aString)
{
ID = new IntContainer(aInt32);
Str = new StringContainer(aString);
}
}
}
namespace WFCS
{
[DataContract]
public class StringContainer
{
[DataMember]
public String Value;
public StringContainer(string aString)
{
this.Value = aString;
}
}
}
and the unit tests that coresponds to these three activities: (requires Microsoft..Activities.UnitTesting NuGet package)
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WFCS;
using Microsoft.Activities.UnitTesting;
namespace WFCSTest
{
[TestClass]
public class SimpleActivityTest
{
[TestMethod]
public void TestSimpleActivity1()
{
SimpleActivity activity = ActivityCompiler.Instance.GetSimpleActivity();
WorkflowInvokerTest host = WorkflowInvokerTest.Create(activity);
host.InArguments.StringContainer = new StringContainer("Jesus");
host.InArguments.IntContainer = new IntContainer(42);
try
{
host.TestActivity();
SimpleData res = host.OutArguments.Result;
Assert.AreEqual(res.ID.Value, 42);
}
finally
{
host.Tracking.Trace();
}
}
}
}
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WFCS;
using Microsoft.Activities.UnitTesting;
using System.Collections.Generic;
namespace WFCSTest
{
[TestClass]
public class MotherActivityTest
{
[TestMethod]
public void TestMotherActivity1()
{
SortedList<IntContainer, SimpleData> input = new SortedList<IntContainer, SimpleData>();
input.Add(new IntContainer(42), new SimpleData(42, "toto"));
input.Add(new IntContainer(84), new SimpleData(84, "titi"));
MotherActivity activity = ActivityCompiler.Instance.GetMotherActivity();
WorkflowInvokerTest host = WorkflowInvokerTest.Create(activity);
host.InArguments.IntToAdd = new IntContainer(21);
host.InArguments.DataToProcess = input;
try
{
host.TestActivity();
SortedList<IntContainer, SimpleData> res = host.OutArguments.ProcessedData;
Assert.AreEqual(res.Count, input.Count);
}
finally
{
host.Tracking.Trace();
}
}
}
}
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using WFCS;
using Microsoft.Activities.UnitTesting;
namespace WFCSTest
{
[TestClass]
public class PatriarchActivityTest
{
[TestMethod]
public void TestPatriarchActivity1()
{
PatriarchActivity activity = ActivityCompiler.Instance.GetPatriarchActivity();
WorkflowInvokerTest host = WorkflowInvokerTest.Create(activity);
//host.InArguments.IntToAdd = new IntContainer(21);
//host.InArguments.DataToProcess = new SortedList<IntContainer, SimpleData>();
//host.InArguments.ProcessedData = new SortedList<IntContainer, SimpleData>();
try
{
host.TestActivity();
SortedList<IntContainer, SimpleData> res = host.OutArguments.ProcessedData;
Assert.AreEqual(res.Count, 2);
}
finally
{
host.Tracking.Trace();
}
}
}
}
Please follow the below steps to resolve the issue --
Create a class that inherits from WorkflowServiceHostFactory Add ServiceActivation in web.config
Workflow Services don’t have an SVC file, so you can use the ‘Configuration Based Activation’ feature to activate the services. You would need to edit your web.config to add support for a factory. In the ServiceHostingEnvironmentSection section, provide the activation details about the service under the tag.