运行 Blazor WASM 作为 Blazor 服务器端

Run Blazor WASM as Blazor Server-Side

问题

如果没有开发方面的缺点,Blazor WASM 很容易成为 Blazor 服务器端的首选。目前,Blazor WASM 不支持全功能调试体验,启动速度非常慢。这比使用 Blazor 服务器端更能减慢开发速度。虽然老实说,我个人认为调试体验比缓慢的启动更能减慢开发速度。

建议的解决方案

NOTE: I included the "proposed" word in there because I'm not sure about the downsides that this solution can cause, so feel free to comment on my answer below.

解决方案是简单地创建一个额外的 Blazor 服务器端项目,然后将 Blazor WASM 项目引用到 Blazor 服务器端项目。然后,对 Blazor 服务器端的 Startup_Host.cshtml 添加一些调整,以正确使用 Blazor WASM 剃刀文件和 wwwroot 文件。有关此解决方案的分步说明,请参阅下面我建议的答案。

简单来说,此解决方案只是添加和配置 Blazor 服务器端项目而无需进行任何更改与 Blazor WASM 项目的任何重要代码重复

NOTE: In this example, I'm using Visual Studio 2019 16.7.2 and the version of the templates are currently at 3.1.8

  1. 创建一个 Blazor WASM 项目。 ASP.NET Core Hosted 或 Standalone 选项都可以正常工作,但稍后将讨论它们的不同配置。其余选项不会有任何影响。在此示例中,我将使用 ASP.NET Core Hosted 稍后解释有关 API 控制器的信息。之后还要创建 Blazor Server-Side 项目。


  1. 此时,您的项目结构应该类似于下面的第一个屏幕截图。

    删除下面第二个屏幕截图中显示的 Blazor Server-Side 项目中突出显示的项目。


  1. 将 Blazor WASM 项目引用到 Blazor Server-Side 项目。

    • ASP.NET Core Hosted - 引用 BlazorWasm.ClientBlazorWasm.Server 项目。
    • 独立 - 按原样引用单个 Blazor WASM 项目。

  1. 转到 Blazor Server-Side 项目的 Startup class。在 ConfigureServices() 中,删除 WeatherForecastServiceBlazorServer.Data 命名空间,然后为 HttpClient 添加一个服务,供来自 Blazor WASM 项目的 razor 文件使用。

    services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(sp.GetRequiredService<NavigationManager>().BaseUri) });
    

    NOTE In production, I don't suggest creating an instance of the HttpClient. Use the IHttpClientFactory instead. Visit this article Use IHttpClientFactory to implement resilient HTTP requests.

    对于 ASP.NET 核心 WASM 项目

    Configure() 中,映射控制器的端点。这将使用 X.Server/BlazorWasm.Server 项目中的控制器。

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        ...
    });
    

  1. 转到 Blazor Server-Side 项目的 /Pages 文件夹中的 _Host.cshtml。将 css/site.css 的引用更改为 css/app.css,因为 Blazor WASM 项目的 css 主文件的文件名不同。

    <link href="css/site.css" rel="stylesheet" /> <!-- Previous -->
    <link href="css/app.css" rel="stylesheet" /> <!-- New -->
    

  1. 最后把component标签的type属性中的App改成App,参考App剃须刀class Blazor WASM 项目中的文件。在此示例中,App class 在 BlazorWasm.Client 项目中找到:

    <component type="typeof(App)" render-mode="ServerPrerendered" /> <!-- Previous -->
    <component type="typeof(BlazorWasm.Client.App)" render-mode="ServerPrerendered" /> <!-- New -->
    

就是这样!当您 运行 Blazor Server-Side 项目时,它应该在没有“正在加载...”文本的情况下加载。

  • 未对 Blazor WASM 项目进行任何更改,也未进行重大代码重复。
  • 唯一需要更改的是引用和 launchSettings.json & appsettings.json
  • 至于 Startup 中针对 Blazor Server-Side 的配置,您只需在 Blazor WASM 项目中创建扩展方法并在 Blazor Server-Side 中使用它们项目。

NOTE: I honestly think this is ideally(?) only for debugging during development since the WASM razor files won't fully utilize the capability of a true Blazor Server-Side because it would still use HTTP Requests.


希望在下面得到反馈! :DD

我会建议另一种方法。从服务器项目引用 WASM 项目还有其他缺点,但我个人认为这是一种架构上不优雅的解决方案。

Blazor 服务器和 WASM 在一些关键领域有所不同:

  1. 身份验证:Blazor 服务器允许您在运行时自定义对特定区域的访问。在 WASM 中,授权是一次性完成的,应用程序代码是完整发送的。
  2. 正在访问数据库:Blazor 服务器允许直接访问 EF 核心实体(因为代码仅在服务器上执行)。在 Blazor 中,实际上不可能直接访问任何数据库。这也是非常不鼓励的,因为您将向客户端发送连接字符串。因此,您需要编写一个单独的 web API 来访问数据。 3.Settings 个文件:您可以在服务器端 blazor 中拥有尽可能多的设置文件。默认情况下,客户端 blazor 仅加载 appsettings.json。需要一种特殊机制来包含多个 .json 文件。

因此,对于大多数应用程序(当然还有那些需要访问数据库的应用程序),您将无法在 WASM 和服务器端之间共享 100% 的代码库。

以下是您应该做的:

  1. 针对上面提到的几点,(auth,但主要是db access),创建数据访问服务依赖(比如IDataAccessLayer)。 一种实现将直接访问数据库(用于服务器端) 另一个实现将通过 HttpClient 访问数据库(用于 blazor WASM)。

  2. 现在,将您的整个应用放入 RCL。将其称为“BlazorAppRCL”。这个RCL显然没有Startup.cs和Program.cs

  3. 为服务器和客户端特定的数据库访问实现创建一个项目

  4. 现在,您有以下一组项目:

对于服务器端: BlazorServer(只有设置 + Program.cs + Startup.cs)。指IDataAccessLayer

的RCL+Server具体实现

对于托管 WASM: BlazorWebAPI : 对于数据库访问,它有 API 来访问数据库 BlazorClientDAL :IDataAccessLayer 的 WASM 特定实现 BlazorWASM : Blazor WASM 项目 这三个都引用您的 BlazorAppRCL。

关键是使用DI/控制反转模式来解决WASM和Server之间的分歧。 这样,您可以同时拥有 WASM 实例和服务器实例,并且代码差异最小。请注意,WASM WebAPI 可以简单地按原样使用服务器端 blazor 的实现 od IDataAccessLayer。因此,除了 API 相关的开销之外,不需要额外的编码。