Reputation: 1441
I am trying to compile Dynamic activity using the new WF 4.5 features - C# expression. It works until I add an external class in the expression.
If the expression contains basic objects it's complied. If I add a reference to an external class it's generates an error "The type or namespace name 'xxxxx' could not be found (are you missing a using directive or an assembly reference?)"
So, the question is how can I reference external classes for C# expressions?
P.S. It works fine with VisualBasic expression type
Thanks
//Compiled without errors
var errorCodeWorkflow = new DynamicActivity
{
Name = "DynamicActivity",
Implementation = () => new WriteLine
{
Text = new CSharpValue<String>
{
ExpressionText = "new Random().Next(1, 101).ToString()"
}
}
};
CompileExpressions(errorCodeWorkflow);
WorkflowInvoker.Invoke(errorCodeWorkflow);
//Error
using System;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Statements;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp.Activities;
namespace CSharpExpression
{
class Program
{
static void Main()
{
var errorCodeWorkflow = new DynamicActivity
{
Name = "MyScenario.MyDynamicActivity3",
Properties =
{
new DynamicActivityProperty
{
Name = "Address",
Type = typeof(InArgument<MailAddress>),
},
},
Implementation = () => new WriteLine
{
Text = new CSharpValue<String>
{
ExpressionText = "\"MyDynamicActivity \" + Address.DisplayName"
}
}
};
CompileExpressions(errorCodeWorkflow);
WorkflowInvoker.Invoke(errorCodeWorkflow, new Dictionary<String, Object> { { "Address", new MailAddress { DisplayName = "TestDisplayName" } } });
}
static void CompileExpressions(DynamicActivity dynamicActivity)
{
var activityName = dynamicActivity.Name;
var activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
var activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
var settings = new TextExpressionCompilerSettings
{
Activity = dynamicActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = "CSharpExpression",
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = true
};
var results = new TextExpressionCompiler(settings).Compile();
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
var compiledExpressionRoot = Activator.CreateInstance(results.ResultType, new object[] { dynamicActivity }) as ICompiledExpressionRoot;
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(dynamicActivity, compiledExpressionRoot);
}
}
public class MailAddress
{
public String Address { get; set; }
public String DisplayName { get; set; }
}
}
Upvotes: 3
Views: 3595
Reputation: 463
I ran into an identical issue working with non-dynamic activities and have now checked what is required to get this to work:
Add a reference to System.Xaml
Move MailAddress
to a different namespace.
Add some information to the Dynamic Activity
about where your classes are coming from:
var impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
var namespaces = new List<string> { typeof(MailAddress).Namespace };
TextExpression.SetReferencesForImplementation(dynamicActivity, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
AttachablePropertyServices.SetProperty(dynamicActivity, impl, namespaces);
To get at this answer I needed to dig around in the TextExpressionCompiler
source so there might be something a lot more elegant.
If you are not using dynamic activities the call to CompileExpressions
would change as described here: http://msdn.microsoft.com/en-us/library/jj591618.aspx.
Adding information to the activity would be modified by removing the "ForImplementation" parts:
var impl = new AttachableMemberIdentifier(typeof(TextExpression), "Namespaces");
var namespaces = new List<string> { typeof(MailAddress).Namespace };
TextExpression.SetReferences(nonDynamicActivity, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
AttachablePropertyServices.SetProperty(nonDynamicActivity, impl, namespaces);
using System;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Statements;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq;
using System.Xaml;
using ExternalNamespace;
using Microsoft.CSharp.Activities;
namespace CSharpExpression
{
class Program
{
static void Main()
{
var errorCodeWorkflow = new DynamicActivity
{
Name = "MyScenario.MyDynamicActivity3",
Properties =
{
new DynamicActivityProperty
{
Name = "Address",
Type = typeof(InArgument<MailAddress>),
},
},
Implementation = () => new WriteLine
{
Text = new CSharpValue<String>
{
ExpressionText = "\"MyDynamicActivity \" + Address.DisplayName"
}
}
};
var impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
var namespaces = new List<string> { typeof(MailAddress).Namespace };
TextExpression.SetReferencesForImplementation(errorCodeWorkflow, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
AttachablePropertyServices.SetProperty(errorCodeWorkflow, impl, namespaces);
CompileExpressions(errorCodeWorkflow);
WorkflowInvoker.Invoke(errorCodeWorkflow, new Dictionary<String, Object> { { "Address", new MailAddress { DisplayName = "TestDisplayName" } } });
}
static void CompileExpressions(DynamicActivity dynamicActivity)
{
var activityName = dynamicActivity.Name;
var activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
var activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
var settings = new TextExpressionCompilerSettings
{
Activity = dynamicActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = "CSharpExpression",
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = true
};
var results = new TextExpressionCompiler(settings).Compile();
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
var compiledExpressionRoot = Activator.CreateInstance(results.ResultType, new object[] { dynamicActivity }) as ICompiledExpressionRoot;
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(dynamicActivity, compiledExpressionRoot);
}
}
}
namespace ExternalNamespace
{
public class MailAddress
{
public String Address { get; set; }
public String DisplayName { get; set; }
}
}
Upvotes: 10
Reputation: 722
Sounds like you need a using statement that specifies the namespace where the external class is located.
For instance:
using myNamespace;
Upvotes: 0