Skip to content

Compilation leaving some expressions uncompiled #397

@jimitndiaye

Description

@jimitndiaye

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions