System.IO.FileNotFoundException 在 Blazor wasm 中使用 CSharpScript 时
System.IO.FileNotFoundException when using CSharpScript in Blazor wasm
我正在尝试在 Blazor wasm 应用程序中使用 CSharpScript,使用简单的 EvaluateAsync
进行测试:
var result = await CSharpScript.EvaluateAsync<int>("1 + 1");
投掷:System.IO.FileNotFoundException: Could not find file "/mscorlib.dll"
我正在使用 Blazor wasm 3.2.0-preview3.20168.3
编辑:
这是 index.razor
中的完整代码:
@code{
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Console.WriteLine("Initializing...");
var result = await CSharpScript.EvaluateAsync<int>("1 + 1");
}
}
这是控制台输出:
Initializing...
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not find file "/mscorlib.dll"
System.IO.FileNotFoundException: Could not find file "/mscorlib.dll"
File name: '/mscorlib.dll'
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) <0x3ba83f8 + 0x002b4> in <filename unknown>:0
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) <0x3b987a0 + 0x0001c> in <filename unknown>:0
at System.IO.File.OpenRead (System.String path) <0x3b986d0 + 0x0000a> in <filename unknown>:0
at Roslyn.Utilities.FileUtilities.OpenFileStream (System.String path) [0x0001c] in /_/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs:416
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal (System.Reflection.Assembly assembly, Microsoft.CodeAnalysis.MetadataReferenceProperties properties, Microsoft.CodeAnalysis.DocumentationProvider documentation) [0x0005a] in /_/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs:329
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal (System.Reflection.Assembly assembly) [0x00000] in /_/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs:271
at Microsoft.CodeAnalysis.Scripting.Script.GetReferencesForCompilation (Microsoft.CodeAnalysis.CommonMessageProvider messageProvider, Microsoft.CodeAnalysis.DiagnosticBag diagnostics, Microsoft.CodeAnalysis.MetadataReference languageRuntimeReferenceOpt) [0x0001a] in /_/src/Scripting/Core/Script.cs:252
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScriptCompiler.CreateSubmission (Microsoft.CodeAnalysis.Scripting.Script script) [0x00021] in /_/src/Scripting/CSharp/CSharpScriptCompiler.cs:40
at Microsoft.CodeAnalysis.Scripting.Script.GetCompilation () [0x00008] in /_/src/Scripting/Core/Script.cs:144
at Microsoft.CodeAnalysis.Scripting.Script`1[T].GetExecutor (System.Threading.CancellationToken cancellationToken) [0x00008] in /_/src/Scripting/Core/Script.cs:361
at Microsoft.CodeAnalysis.Scripting.Script`1[T].RunAsync (System.Object globals, System.Func`2[T,TResult] catchException, System.Threading.CancellationToken cancellationToken) [0x0001b] in /_/src/Scripting/Core/Script.cs:465
at Microsoft.CodeAnalysis.Scripting.Script`1[T].RunAsync (System.Object globals, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/Core/Script.cs:439
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync[T] (System.String code, Microsoft.CodeAnalysis.Scripting.ScriptOptions options, System.Object globals, System.Type globalsType, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/CSharp/CSharpScript.cs:93
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync[T] (System.String code, Microsoft.CodeAnalysis.Scripting.ScriptOptions options, System.Object globals, System.Type globalsType, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/CSharp/CSharpScript.cs:123
at ScriptPlayground.Pages.Index.OnInitializedAsync () [0x0008a] in C:\Users\sarma\source\repos\ScriptPlayground\Pages\Index.razor:17
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x36de968 + 0x0013a> in <filename unknown>:0
编辑 2:
在深入研究该问题后,我们将其追溯到 Script.cs
:
中的这些行
/// <summary>
/// Gets the references that need to be assigned to the compilation.
/// This can be different than the list of references defined by the <see cref="ScriptOptions"/> instance.
/// </summary>
internal ImmutableArray<MetadataReference> GetReferencesForCompilation(
CommonMessageProvider messageProvider,
DiagnosticBag diagnostics,
MetadataReference languageRuntimeReferenceOpt = null)
{
var resolver = Options.MetadataResolver;
var references = ArrayBuilder<MetadataReference>.GetInstance();
try
{
if (Previous == null)
{
var corLib = MetadataReference.CreateFromAssemblyInternal(typeof(object).GetTypeInfo().Assembly);
references.Add(corLib);
无论我们传递什么选项,编译时都会调用它,MetadataReference.CreateFromAssemblyInternal
尝试从磁盘加载文件。因此,从磁盘加载程序集似乎已硬编码到该过程中。我们正在寻找一种干净的方法来覆盖它。
我们已经成功地使用 HttpClient 从流中加载程序集:
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var name = assembly.GetName().Name + ".dll";
references.Add(
MetadataReference.CreateFromStream(
await this.HttpClient.GetStreamAsync("/_framework/_bin/" + name)));
}
但这并不重要,只要 CSharpScript 在从磁盘编译期间加载另一组程序集
不幸的是,CsharpScript
API 的构建依赖于在本地文件系统上查找程序集。如果你在 MetadataReference.CreateFromStream
源代码中挖掘得足够深,你会发现罪魁祸首是对 File.OpenRead()
的调用
我自己花了一些时间研究 API 的任何可能的可扩展性,其中可以提供替代的程序集解析策略。在 ScriptOptions
中有一个自定义 MetaDataReferenceResolver
的路径,但是你找到的行的烘烤
var corLib = MetadataReference.CreateFromAssemblyInternal(typeof(object).GetTypeInfo().Assembly);
有效地创建了对文件系统的硬依赖,从而扼杀了这个想法。
mscorlib
的解析是通过上面的方式完成的,但是所有其他程序集都使用 Options.MetaDataReferences
列表。为什么我不知道....
作为一个纯粹的 hack,我什至在捕获对 File.OpenRead()
的调用并从 HttpClient
返回我自己的 stream
方面遇到了困难。注入在桌面进程中有效,但在 wasm 中出现了问题。最后我也放弃了支持滚动替代方案,例如 this approach or this one.
这是供感兴趣的人使用的试用版。
//Using the Pose library https://github.com/tonerdo/pose
var client = new HttpClient() { BaseAddress = new Uri(navigationManager.BaseUri) };
Shim fileShim = Shim.Replace(() => System.IO.File.OpenRead(Is.A<string>())).With(delegate (string assembly)
{
var fs = new System.IO.FileStream(assembly, System.IO.FileMode.Open);
client.GetStreamAsync($"_framework/_bin/{assembly}").Result.CopyTo(fs);
return fs;
});
PoseContext.Isolate(() => Text = CSharpScript.EvaluateAsync<string>("hello").Result, fileShim);
HTH
我正在尝试在 Blazor wasm 应用程序中使用 CSharpScript,使用简单的 EvaluateAsync
进行测试:
var result = await CSharpScript.EvaluateAsync<int>("1 + 1");
投掷:System.IO.FileNotFoundException: Could not find file "/mscorlib.dll"
我正在使用 Blazor wasm 3.2.0-preview3.20168.3
编辑:
这是 index.razor
中的完整代码:
@code{
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Console.WriteLine("Initializing...");
var result = await CSharpScript.EvaluateAsync<int>("1 + 1");
}
}
这是控制台输出:
Initializing...
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not find file "/mscorlib.dll"
System.IO.FileNotFoundException: Could not find file "/mscorlib.dll"
File name: '/mscorlib.dll'
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) <0x3ba83f8 + 0x002b4> in <filename unknown>:0
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) <0x3b987a0 + 0x0001c> in <filename unknown>:0
at System.IO.File.OpenRead (System.String path) <0x3b986d0 + 0x0000a> in <filename unknown>:0
at Roslyn.Utilities.FileUtilities.OpenFileStream (System.String path) [0x0001c] in /_/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs:416
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal (System.Reflection.Assembly assembly, Microsoft.CodeAnalysis.MetadataReferenceProperties properties, Microsoft.CodeAnalysis.DocumentationProvider documentation) [0x0005a] in /_/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs:329
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal (System.Reflection.Assembly assembly) [0x00000] in /_/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs:271
at Microsoft.CodeAnalysis.Scripting.Script.GetReferencesForCompilation (Microsoft.CodeAnalysis.CommonMessageProvider messageProvider, Microsoft.CodeAnalysis.DiagnosticBag diagnostics, Microsoft.CodeAnalysis.MetadataReference languageRuntimeReferenceOpt) [0x0001a] in /_/src/Scripting/Core/Script.cs:252
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScriptCompiler.CreateSubmission (Microsoft.CodeAnalysis.Scripting.Script script) [0x00021] in /_/src/Scripting/CSharp/CSharpScriptCompiler.cs:40
at Microsoft.CodeAnalysis.Scripting.Script.GetCompilation () [0x00008] in /_/src/Scripting/Core/Script.cs:144
at Microsoft.CodeAnalysis.Scripting.Script`1[T].GetExecutor (System.Threading.CancellationToken cancellationToken) [0x00008] in /_/src/Scripting/Core/Script.cs:361
at Microsoft.CodeAnalysis.Scripting.Script`1[T].RunAsync (System.Object globals, System.Func`2[T,TResult] catchException, System.Threading.CancellationToken cancellationToken) [0x0001b] in /_/src/Scripting/Core/Script.cs:465
at Microsoft.CodeAnalysis.Scripting.Script`1[T].RunAsync (System.Object globals, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/Core/Script.cs:439
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync[T] (System.String code, Microsoft.CodeAnalysis.Scripting.ScriptOptions options, System.Object globals, System.Type globalsType, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/CSharp/CSharpScript.cs:93
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync[T] (System.String code, Microsoft.CodeAnalysis.Scripting.ScriptOptions options, System.Object globals, System.Type globalsType, System.Threading.CancellationToken cancellationToken) [0x00000] in /_/src/Scripting/CSharp/CSharpScript.cs:123
at ScriptPlayground.Pages.Index.OnInitializedAsync () [0x0008a] in C:\Users\sarma\source\repos\ScriptPlayground\Pages\Index.razor:17
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x36de968 + 0x0013a> in <filename unknown>:0
编辑 2:
在深入研究该问题后,我们将其追溯到 Script.cs
:
/// <summary>
/// Gets the references that need to be assigned to the compilation.
/// This can be different than the list of references defined by the <see cref="ScriptOptions"/> instance.
/// </summary>
internal ImmutableArray<MetadataReference> GetReferencesForCompilation(
CommonMessageProvider messageProvider,
DiagnosticBag diagnostics,
MetadataReference languageRuntimeReferenceOpt = null)
{
var resolver = Options.MetadataResolver;
var references = ArrayBuilder<MetadataReference>.GetInstance();
try
{
if (Previous == null)
{
var corLib = MetadataReference.CreateFromAssemblyInternal(typeof(object).GetTypeInfo().Assembly);
references.Add(corLib);
无论我们传递什么选项,编译时都会调用它,MetadataReference.CreateFromAssemblyInternal
尝试从磁盘加载文件。因此,从磁盘加载程序集似乎已硬编码到该过程中。我们正在寻找一种干净的方法来覆盖它。
我们已经成功地使用 HttpClient 从流中加载程序集:
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var name = assembly.GetName().Name + ".dll";
references.Add(
MetadataReference.CreateFromStream(
await this.HttpClient.GetStreamAsync("/_framework/_bin/" + name)));
}
但这并不重要,只要 CSharpScript 在从磁盘编译期间加载另一组程序集
不幸的是,CsharpScript
API 的构建依赖于在本地文件系统上查找程序集。如果你在 MetadataReference.CreateFromStream
源代码中挖掘得足够深,你会发现罪魁祸首是对 File.OpenRead()
我自己花了一些时间研究 API 的任何可能的可扩展性,其中可以提供替代的程序集解析策略。在 ScriptOptions
中有一个自定义 MetaDataReferenceResolver
的路径,但是你找到的行的烘烤
var corLib = MetadataReference.CreateFromAssemblyInternal(typeof(object).GetTypeInfo().Assembly);
有效地创建了对文件系统的硬依赖,从而扼杀了这个想法。
mscorlib
的解析是通过上面的方式完成的,但是所有其他程序集都使用 Options.MetaDataReferences
列表。为什么我不知道....
作为一个纯粹的 hack,我什至在捕获对 File.OpenRead()
的调用并从 HttpClient
返回我自己的 stream
方面遇到了困难。注入在桌面进程中有效,但在 wasm 中出现了问题。最后我也放弃了支持滚动替代方案,例如 this approach or this one.
这是供感兴趣的人使用的试用版。
//Using the Pose library https://github.com/tonerdo/pose
var client = new HttpClient() { BaseAddress = new Uri(navigationManager.BaseUri) };
Shim fileShim = Shim.Replace(() => System.IO.File.OpenRead(Is.A<string>())).With(delegate (string assembly)
{
var fs = new System.IO.FileStream(assembly, System.IO.FileMode.Open);
client.GetStreamAsync($"_framework/_bin/{assembly}").Result.CopyTo(fs);
return fs;
});
PoseContext.Isolate(() => Text = CSharpScript.EvaluateAsync<string>("hello").Result, fileShim);
HTH