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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions