使用 Blazor 加载外部 .NET Standard 2.0 程序集

Loading an external .NET Standard 2.0 assembly with blazor

在 Blazor 应用中,我想加载一个外部程序集并执行一个方法。为此,我使用 Blazor 模板创建了一个新的 ASP.Net 核心网络应用程序。

然后,在 Razor 页面(将由 browser/wasm 编译和执行)中,我使用反射加载程序集和 运行 方法(基于代码 found here

// download external assembly from server
HttpClient client = new HttpClient();
var bytes = await client.GetByteArrayAsync("http://localhost:62633/_framework/MyCustomLib.dll");

//load assembly
var assembly = System.Reflection.Assembly.Load(bytes);

// get type/method info
var type = assembly.GetType("MyCustomLib.MyCustomClass");
var method = type.GetMethod("WriteSomething");

// instantiate object and run method
object classInstance = Activator.CreateInstance(type, null);
method.Invoke(classInstance, null);

方法 WriteSomething 包含一个 Console.WriteLine() ,它在浏览器的控制台中打印一些东西,感谢 blazor/mono.wasm 的善良。这个库中的完整代码是:

namespace MyCustomLib
{
    public class MyCustomClass
    {
        public void WriteSomething()
        {
            System.Console.WriteLine("This is printed from a loaded dll 3 !");
        }
    }
}

结果:

如您所见,当 MyCustomLib.dll 构建为 .NET Framework Class 库时效果很好。但是,我想使用 .NET Standard Class 库。

当我将 MyCustomLib.dll 构建为 .NET Standard 2.0 库并执行相同的 blazor 应用程序时,我在浏览器的控制台中收到以下错误:

Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies.

我预计 mono.wasm 会加载必要的依赖项以支持 .NET Standard 程序集。

var assembly = AppDomain.CurrentDomain.Load(bytes); 

如何使用 Blazor 将 .NET Standard 2.0 加载到浏览器环境中?

经过进一步调查,我得出结论,我的问题是我的外部库没有正确链接到 mono.net 依赖项。这就是为什么当您构建 Blazor 应用程序时,它会被第二次编译为 /dist/_framework/_bin.

我找到了解决此问题的三种可能方法:

1. 将外部 class 库变成 Blazor Web 应用程序

这样,您的应用程序将在构建时自动转换为单声道兼容程序集。简单查看 Blazor .csproj 即可显示实现此目的所需的依赖项。为了让它工作,我必须更改外部程序集的 .csproj:

来自默认的网络标准库:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
</Project>

进入网络应用程序:

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <RunCommand>dotnet</RunCommand>
        <LangVersion>7.3</LangVersion>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.7.0" PrivateAssets="all" />
    </ItemGroup>
</Project>

这些是唯一需要的依赖项。在构建时,兼容的程序集将在 /dist/_framework/_bin 文件夹中找到。然后可以使用问题中描述的方法加载它。

有效 ,但感觉有点老套,因为我们将库变成 Web 应用程序的唯一原因是它可以将自身编译成正确链接的程序集。

2.加载netstandard2.0 mono facade

另一个解决方案是从 Microsoft.AspNetCore.Blazor.Build 解压 Nuget 包并获取 netstandard.dll。它位于 tools\mono\bcl\Facades 文件夹中。现在,在主 Blazor 应用程序中执行以下操作时:

var netstandard = await client.GetByteArrayAsync("http://localhost:62633/_framework/netstandard.dll");
var externallib = await client.GetByteArrayAsync("http://localhost:62633/_framework/MyCustomLib.dll");
AppDomain.CurrentDomain.Load(netstandard);
var assembly = AppDomain.CurrentDomain.Load(externallib);

然后 未修改 netstandard 2.0 库 MyCustomLib 将被正确加载。

  • 无需将其更改为网络应用程序
  • 这个有效,但感觉比第一个解决方案更难,不确定这是否会在以后的过程中失败...

3. 使用 Blazor 构建工具

The Blazor Build tools, currently found here, 它们有一个用于 CLI 的 ResolveRuntimeDependenciesCommand 命令,当它把输出输出到 /_framework/ 时,它似乎做的正是 blazor web 应用程序正在做的事情_垃圾桶。 我仍在研究如何使用它来将 "non blazor-webapp" 程序集转换为单声道兼容程序集。

请随时发表评论或回答更多信息。在找到 "cleaner" 解决方案之前,我将保留此问题。

这是由于 blazor 链接器剥离了对 netstandard 的依赖,因为它没有在主 WebAssemblyHost 项目中明确使用。

当动态加载使用 netstandard 的 DLL 时,它会假定它已经加载并崩溃。

如果您计划动态加载程序集,我建议使用

<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>

确保不删除任何基础依赖项。