Reputation: 165
I have built a MAUI application that targets Android. In it, I need to execute code that is given as a string (Yes, I know about the security concerns). I use roslyn's EvaluateAsync for executing the given expression. This worked great during development, but when I switched to the Release-mode build, it suddenly threw an exception as soon as the expression is evaluated. This is the stacktrace of the thrown Exception:
System.IO.FileNotFoundException: Could not find file '/System.Private.CoreLib.dll'.
File name: '/System.Private.CoreLib.dll'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
at Interop.CheckIo(Error error, String path, Boolean isDirError)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode, Func`4 createOpenException)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.UnixFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at Roslyn.Utilities.StandardFileSystem.OpenFile(String filePath, FileMode mode, FileAccess access, FileShare share)
at Roslyn.Utilities.CommonCompilerFileSystemExtensions.OpenFileWithNormalizedException(ICommonCompilerFileSystem fileSystem, String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal(Assembly assembly, MetadataReferenceProperties properties, DocumentationProvider documentation)
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal(Assembly assembly)
at Microsoft.CodeAnalysis.Scripting.Script.GetReferencesForCompilation(CommonMessageProvider messageProvider, DiagnosticBag diagnostics, MetadataReference languageRuntimeReferenceOpt)
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScriptCompiler.CreateSubmission(Script script)
at Microsoft.CodeAnalysis.Scripting.Script.GetCompilation()
at Microsoft.CodeAnalysis.Scripting.Script`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetExecutor(CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.Scripting.Script`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].RunAsync(Object globals, Func`2 catchException, CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.Scripting.Script`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].RunAsync(Object globals, CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync[Object](String code, ScriptOptions options, Object globals, Type globalsType, CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync[Object](String code, ScriptOptions options, Object globals, Type globalsType, CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync(String code, ScriptOptions options, Object globals, Type globalsType, CancellationToken cancellationToken)
at MauiScriptingTest.MainPage.EvaluateScript()
public MainPage()
{
InitializeComponent();
this.BindingContext = this;
}
private string? evaluationResult = "Not evaluated yet";
public string? EvaluationResult
{
get => evaluationResult;
set
{
evaluationResult = value;
OnPropertyChanged();
}
}
private async void OnCounterClicked(object sender, EventArgs e)
{
await EvaluateScript();
}
private async Task EvaluateScript()
{
try
{
var result = await CSharpScript.EvaluateAsync("return 1+2;");
EvaluationResult = result.ToString();
}
catch (Exception ex)
{
EvaluationResult = ex.ToString();
}
}
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
<Label Text="{Binding EvaluationResult}"></Label>
This should return the result of the calculation "1+2". However, it throws an exception.
I have tried adding references to various assemblies in various different ways that I found online, but nothing worked. I tried disabling trimming and AOT for the project as advised online, but that also didn't work.
Upvotes: 0
Views: 809
Reputation: 165
According to an answer on the issue I opened:
File.OpenRead("/System.Private.CoreLib.dll")
cannot possibly work on Android, as apps remain compressed on disk after they are installed. The only reason it works in Debug mode, is the way the "fast deployment" feature works: we sideload assemblies and manually copy them to a location. This is not something that would work on app stores/Release mode.I don't see how
Microsoft.CodeAnalysis.CSharp.Scripting
can easily work on Android, unless you have a way to redirect theStream
it opens for files? Perhaps you could try bundlingSystem.Private.CoreLib.dll
yourself and extracting it toEnvironment.SpecialFolder.UserProfile
? Not sure if that would work either, though, if it is looking only in/
as that is not writeable.You might be better off to take a difference approach, in general.
I ended up using Jint, a Javascript interpreter for .NET.
Upvotes: 1