diff --git a/src/Test/TestCases.Workflows/TestCases.Workflows.csproj b/src/Test/TestCases.Workflows/TestCases.Workflows.csproj
index 8b1704b8..621b8ce7 100644
--- a/src/Test/TestCases.Workflows/TestCases.Workflows.csproj
+++ b/src/Test/TestCases.Workflows/TestCases.Workflows.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Test/TestCases.Workflows/TestUtils/Project.cs b/src/Test/TestCases.Workflows/TestUtils/Project.cs
index 961aeacc..0b7de450 100644
--- a/src/Test/TestCases.Workflows/TestUtils/Project.cs
+++ b/src/Test/TestCases.Workflows/TestUtils/Project.cs
@@ -2,34 +2,54 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
+using Microsoft.CodeAnalysis.VisualBasic;
using System;
using System.Activities;
using System.Activities.ExpressionParser;
+using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
+using TestCases.Workflows.WF4Samples;
namespace TestCases.Workflows.TestUtils
{
internal class Project
{
- static readonly MefHostServices HostServices = MefHostServices.Create(new[]{ "Microsoft.CodeAnalysis.Workspaces",
+ static readonly MefHostServices HostServicesCS = MefHostServices.Create(new[]{ "Microsoft.CodeAnalysis.Workspaces",
"Microsoft.CodeAnalysis.CSharp.Workspaces", "Microsoft.CodeAnalysis.Features", "Microsoft.CodeAnalysis.CSharp.Features" }
.Select(Assembly.Load));
- private readonly AdhocWorkspace _workspace = new(HostServices);
+ static readonly MefHostServices HostServicesVB = MefHostServices.Create(new[]{ "Microsoft.CodeAnalysis.Workspaces",
+ "Microsoft.CodeAnalysis.VisualBasic.Workspaces", "Microsoft.CodeAnalysis.Features", "Microsoft.CodeAnalysis.VisualBasic.Features" }
+ .Select(Assembly.Load));
+ private readonly Dictionary _workspaces = new()
+ {
+ { Language.CSharp, new AdhocWorkspace(HostServicesCS) },
+ { Language.VisualBasic, new AdhocWorkspace(HostServicesVB) }
+ };
private readonly MetadataReference[] _references;
public Project(MetadataReference[] references) => _references = references;
- public async Task Compile(string classCode, string className)
+ public async Task Compile(string classCode, string className, Language language)
{
- _workspace.ClearSolution();
- CSharpCompilationOptions compilationOptions = new(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release);
- var scriptProjectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), className, className, LanguageNames.CSharp)
+ if (_workspaces.TryGetValue(language, out var workspace) == false)
+ {
+ throw new NotSupportedException(nameof(language));
+ }
+ workspace.ClearSolution();
+
+ CompilationOptions compilationOptions = language == Language.CSharp
+ ? new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release)
+ : new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release);
+
+ var scriptProjectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), className, className,
+ language == Language.CSharp ? LanguageNames.CSharp : LanguageNames.VisualBasic)
.WithMetadataReferences(_references)
.WithCompilationOptions(compilationOptions);
- var scriptProject = _workspace.AddProject(scriptProjectInfo);
- _workspace.AddDocument(scriptProject.Id, className, SourceText.From(classCode));
- var compilation = await _workspace.CurrentSolution.Projects.First().GetCompilationAsync();
+
+ var scriptProject = workspace.AddProject(scriptProjectInfo);
+ workspace.AddDocument(scriptProject.Id, className, SourceText.From(classCode));
+ var compilation = await workspace.CurrentSolution.Projects.First().GetCompilationAsync();
//using var output = File.OpenWrite("Output.dll");
var results = ScriptingAotCompiler.BuildAssembly(compilation, className, AssemblyLoadContext.Default/*, output*/);
if (results.HasErrors)
diff --git a/src/Test/TestCases.Workflows/TestXamls/AssignWithExpressionNothing.xaml b/src/Test/TestCases.Workflows/TestXamls/AssignWithExpressionNothing.xaml
new file mode 100644
index 00000000..232fc7e3
--- /dev/null
+++ b/src/Test/TestCases.Workflows/TestXamls/AssignWithExpressionNothing.xaml
@@ -0,0 +1,75 @@
+
+
+
+ Microsoft.VisualBasic
+ System
+ System.Activities
+ System.Activities.Statements
+ System.Collections
+ System.Collections.Generic
+ System.Collections.ObjectModel
+ System.Linq
+
+
+
+
+ Microsoft.VisualBasic
+ mscorlib
+ System
+ System.Activities
+ System.ComponentModel.TypeConverter
+ System.Core
+ System.Data
+ System.Data.Common
+ System.Data.DataSetExtensions
+ System.Drawing
+ System.Drawing.Common
+ System.Drawing.Primitives
+ System.Linq
+ System.ObjectModel
+ System.Private.CoreLib
+ System.Xaml
+ System.Xml
+ System.Xml.Linq
+ System.Reflection.DispatchProxy
+ System.Reflection.TypeExtensions
+ System.Reflection.Metadata
+ System.Security.Permissions
+ System.Configuration.ConfigurationManager
+ System.ComponentModel
+ System.Memory
+ System.Private.Uri
+ System.Private.ServiceModel
+ System.Collections
+ System.Collections.NonGeneric
+ System.Linq.Expressions
+ System.Private.DataContractSerialization
+ System.Runtime.Serialization.Formatters
+ System.Runtime.Serialization.Primitives
+
+
+
+
+
+
+
+
+
+ [myVar]
+
+
+
+ [Nothing]
+
+
+
+
\ No newline at end of file
diff --git a/src/Test/TestCases.Workflows/TestXamls/AssignWithLiteral.xaml b/src/Test/TestCases.Workflows/TestXamls/AssignWithLiteral.xaml
new file mode 100644
index 00000000..18344bbe
--- /dev/null
+++ b/src/Test/TestCases.Workflows/TestXamls/AssignWithLiteral.xaml
@@ -0,0 +1,77 @@
+
+
+
+ Microsoft.VisualBasic
+ System
+ System.Activities
+ System.Activities.Statements
+ System.Collections
+ System.Collections.Generic
+ System.Collections.ObjectModel
+ System.Linq
+
+
+
+
+ Microsoft.VisualBasic
+ mscorlib
+ System
+ System.Activities
+ System.ComponentModel.TypeConverter
+ System.Core
+ System.Data
+ System.Data.Common
+ System.Data.DataSetExtensions
+ System.Drawing
+ System.Drawing.Common
+ System.Drawing.Primitives
+ System.Linq
+ System.ObjectModel
+ System.Private.CoreLib
+ System.Xaml
+ System.Xml
+ System.Xml.Linq
+ System.Reflection.DispatchProxy
+ System.Reflection.TypeExtensions
+ System.Reflection.Metadata
+ System.Security.Permissions
+ System.Configuration.ConfigurationManager
+ System.ComponentModel
+ System.Memory
+ System.Private.Uri
+ System.Private.ServiceModel
+ System.Collections
+ System.Collections.NonGeneric
+ System.Linq.Expressions
+ System.Private.DataContractSerialization
+ System.Runtime.Serialization.Formatters
+ System.Runtime.Serialization.Primitives
+
+
+
+
+
+
+
+
+
+ [myVar]
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Test/TestCases.Workflows/TestXamls/TestHelper.cs b/src/Test/TestCases.Workflows/TestXamls/TestHelper.cs
index 7d1a8098..813e130b 100644
--- a/src/Test/TestCases.Workflows/TestXamls/TestHelper.cs
+++ b/src/Test/TestCases.Workflows/TestXamls/TestHelper.cs
@@ -46,6 +46,8 @@ public enum TestXamls
SpecialCharacters,
ValueSpecialCharacterCSharp,
ValueSpecialCharacterVb,
- ImproveAssignabilityOutArgumentActivity
+ ImproveAssignabilityOutArgumentActivity,
+ AssignWithLiteral,
+ AssignWithExpressionNothing
}
}
diff --git a/src/Test/TestCases.Workflows/WF4Samples/Expressions.cs b/src/Test/TestCases.Workflows/WF4Samples/Expressions.cs
index 6899bf16..6e23ffe1 100644
--- a/src/Test/TestCases.Workflows/WF4Samples/Expressions.cs
+++ b/src/Test/TestCases.Workflows/WF4Samples/Expressions.cs
@@ -21,6 +21,12 @@ namespace TestCases.Workflows.WF4Samples
{
using StringDictionary = Dictionary;
+ internal enum Language
+ {
+ VisualBasic,
+ CSharp
+ };
+
public abstract class ExpressionsBaseCommon
{
protected abstract bool CompileExpressions { get; }
@@ -171,19 +177,32 @@ public void CSharpCalculationGenerated()
public async Task WorkflowWithReadonlyValueTypeVar()
{
var activity = TestHelper.GetActivityFromXamlResource(TestXamls.WorkflowWithReadonlyValueTypeVar);
- var compiledExpressionRoot = await GenerateAndLoadCompiledExpressionRoot(activity);
+ var compiledExpressionRoot = await GenerateAndLoadCompiledExpressionRoot(activity, "TestXamls_WorkflowWithReadonlyValueTypeVar", Language.CSharp);
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(activity, compiledExpressionRoot);
TestHelper.InvokeWorkflow(activity).ShouldBe(string.Empty);
}
- private static async Task GenerateAndLoadCompiledExpressionRoot(Activity activity)
+ [Fact]
+ public async Task Assign_Value_RequiresCompilation()
+ {
+ var assignWithLiteral = TestHelper.GetActivityFromXamlResource(TestXamls.AssignWithLiteral);
+ var compiledExpressionRoot = await GenerateAndLoadCompiledExpressionRoot(assignWithLiteral, "TestXamls_Assign", Language.VisualBasic);
+
+ var assignWithExpressionNothing = TestHelper.GetActivityFromXamlResource(TestXamls.AssignWithExpressionNothing);
+ CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(assignWithExpressionNothing, compiledExpressionRoot);
+
+ var ex = Assert.Throws(() => TestHelper.InvokeWorkflow(assignWithExpressionNothing));
+ ex.Message.ShouldBe(@"My Fancy Assign: Value Expression Activity type 'VisualBasicValue`1 (Nothing)' requires compilation in order to run. Please ensure that the workflow has been compiled.");
+ }
+ private static async Task GenerateAndLoadCompiledExpressionRoot(Activity activity, string className,
+ Language language)
{
using var expressionsStringWriter = new StringWriter();
- var activityName = $"{TestXamls.WorkflowWithReadonlyValueTypeVar}_CompiledExpressionRoot";
+ var activityName = $"{className}_CompiledExpressionRoot";
TextExpressionCompilerSettings settings = new()
{
Activity = activity,
- Language = "C#",
+ Language = language == Language.VisualBasic ? "VB" : "C#",
ActivityName = activityName,
RootNamespace = null,
GenerateAsPartialClass = false,
@@ -194,7 +213,7 @@ private static async Task GenerateAndLoadCompiledExpres
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).Select(References.GetReference).ToArray();
var project = new Project(assemblies);
- var compiledExpressionsClassType = await project.Compile(expressionsStringWriter.ToString(), activityName);
+ var compiledExpressionsClassType = await project.Compile(expressionsStringWriter.ToString(), activityName, language);
return (ICompiledExpressionRoot)Activator.CreateInstance(compiledExpressionsClassType, activity);
}
[Fact]
diff --git a/src/UiPath.Workflow.Runtime/ActivityInstance.cs b/src/UiPath.Workflow.Runtime/ActivityInstance.cs
index cfed354f..e7b5e039 100644
--- a/src/UiPath.Workflow.Runtime/ActivityInstance.cs
+++ b/src/UiPath.Workflow.Runtime/ActivityInstance.cs
@@ -8,6 +8,8 @@
namespace System.Activities;
using Internals;
using Runtime;
+using System.Activities.Expressions;
+using System.Text;
using Tracking;
#if DYNAMICUPDATE
@@ -857,10 +859,19 @@ internal bool ResolveArguments(ActivityExecutor executor, IDictionary dynamicUpdateVariableIndexes, bool forImplementation)
diff --git a/src/UiPath.Workflow.Runtime/Expressions/CompiledExpressionInvoker.cs b/src/UiPath.Workflow.Runtime/Expressions/CompiledExpressionInvoker.cs
index 873b7168..83ae0d57 100644
--- a/src/UiPath.Workflow.Runtime/Expressions/CompiledExpressionInvoker.cs
+++ b/src/UiPath.Workflow.Runtime/Expressions/CompiledExpressionInvoker.cs
@@ -9,6 +9,8 @@ namespace System.Activities.Expressions;
public class CompiledExpressionInvoker
{
+ internal static readonly string TextExpressionMetadataRequiresCompilationKey = nameof(TextExpressionMetadataRequiresCompilationKey);
+
private static readonly AttachableMemberIdentifier compiledExpressionRootProperty =
new(typeof(CompiledExpressionInvoker), "CompiledExpressionRoot");
private static readonly AttachableMemberIdentifier compiledExpressionRootForImplementationProperty =
@@ -57,7 +59,9 @@ public object InvokeExpression(ActivityContext activityContext)
{
if (!TryGetCurrentCompiledExpressionRoot(activityContext, out _compiledRoot, out _expressionId))
{
- throw FxTrace.Exception.AsError(new NotSupportedException(SR.TextExpressionMetadataRequiresCompilation(_expressionActivity.GetType().Name)));
+ var exception = new NotSupportedException(SR.TextExpressionMetadataRequiresCompilation($"{_expressionActivity.GetType().Name} ({_textExpression.ExpressionText ?? string.Empty})"));
+ exception.Data[TextExpressionMetadataRequiresCompilationKey] = true;
+ throw FxTrace.Exception.AsError(exception);
}
}
}