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

Posted

技术标签:

【中文标题】使用 blazor 加载外部 .NET Standard 2.0 程序集【英文标题】:Loading an external .NET Standard 2.0 assembly with blazor 【发布时间】:2019-06-13 19:51:54 【问题描述】:

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

然后,在 Razor 页面(将由浏览器/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 类库时,这非常有用。但是,我想使用 .NET Standard 类库。

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

无法加载文件或程序集 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' 或其依赖项之一。

我希望 mono.wasm 会加载必要的依赖项来支持 .NET Standard 程序集。

将程序集加载到 AppDomain 会产生相同的结果。
var assembly = AppDomain.CurrentDomain.Load(bytes); 

切换到 netstandard 1.6 给了我一个类似的错误,这次是关于 System.Runtime(因为我假设 mono.wasm 期望 Mono.Runtime)。

也许有一种方法可以对 netstandard2.0 包引用的程序集执行 LoadAssembly,但我不知道如何。

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

【问题讨论】:

【参考方案1】:

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

我已经找到了三种可能的解决方案:

1. 将外部类库变成 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 文件夹中找到兼容的程序集。然后可以使用问题中描述的方法加载它。

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

2. 加载 netstandard2.0 单门面

另一种解决方案是从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 将被正确加载。

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

3. 使用 Blazor 构建工具

Blazor 构建工具,目前找到 here,它们有一个用于 CLI 的 ResolveRuntimeDependenciesCommand 命令,这似乎与 Blazor Web 应用程序在将输出吐出到 /_framework/_bin 时所做的完全一样。 我仍在研究如何使用它来将“非 blazor-webapp”程序集转换为单声道兼容程序集。

随时评论或回答其他信息。在找到“更清洁”的解决方案之前,我将保留这个问题。

【讨论】:

【参考方案2】:

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

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

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

<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>

确保没有基本依赖被剥离。

【讨论】:

以上是关于使用 blazor 加载外部 .NET Standard 2.0 程序集的主要内容,如果未能解决你的问题,请参考以下文章

使用 .NET 5.0 的 Blazor WebAssembly 应用程序 - Google 搜索 - 正在加载...发生未处理的错误。重新加载

Blazor - 提交表单而不重新加载(没有 JS)

没有 Web 程序集的 blazor

Azure 静态 Web 应用 Blazor WASM .Net Core API 和标识 - 无法从“_configuration”加载设置

.NET 8新预览版本使用 Blazor 组件进行服务器端呈现

.NET上海社区线下Meetup - 5.22 Blazor Day