-
Notifications
You must be signed in to change notification settings - Fork 232
Description
I developing a workflow using a CoreWF and some custom activities. Things are generally fine as long as I don't use too many expressions (CSharpReference and CSharpValue). Once I do I often get an error message saying something like
Expression Activity type 'CSharpReference`1' requires compilation in order to run. Please ensure that the workflow has been compiled.
I have tried explicitly compiling the activity using ActivityXamlServices:
Activity? activity;
try
{
using var stream = new StringReader(instance.WorkflowDefinitionXaml);
activity = ActivityXamlServices.Load(stream, new()
{
CompileExpressions = true,
CSharpCompiler = new CSharpAotCompiler()
});
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to compile expressions for workflow activity");
throw;
}
I have tried using imperative code:
public static void CompileExpressions(this Activity activity, bool forImplementation = false)
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions.
var type = activity.GetType();
var activityName = activity is IDynamicActivity dynamicActivity
? dynamicActivity.Name
: type.IsGenericType
? $"{type.Namespace}.{type.Name.Split('`')[0]}_{string.Join('_', type.GenericTypeArguments.Select(GetTypeName))}"
: type.FullName!;
// 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.
var activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
var activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
var settings = new TextExpressionCompilerSettings
{
Activity = activity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = null,
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = activity is IDynamicActivity or Dialog || forImplementation,
Compiler = new CSharpAotCompiler()
};
// Compile the C# expression.
var results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new TextExpressionCompilerException(results);
}
// Create an instance of the new compiled expression type.
var compiledExpressionRoot =
(ICompiledExpressionRoot) Activator.CreateInstance(results.ResultType, activity)!;
// Attach it to the activity.
if (settings.ForImplementation)
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
activity, compiledExpressionRoot);
else
CompiledExpressionInvoker.SetCompiledExpressionRoot(
activity, compiledExpressionRoot);
string GetTypeName(Type t) => t.IsGenericType
? $"{t.Name.Split('`')[0]}_{string.Join('_', t.GenericTypeArguments.Select(GetTypeName))}"
: t.FullName!;
}
In both cases I get the same error message as long the workflow contains expressions in certain places (not others). I don't get any compilation errors. It only fails when the workflow is actually run.
Can anyone point me in the right direction? @dmetzgar? Help?
I have been been banging my head against the wall for a week. I would expect the ActivityXamlServices