作为 Blazor 服务器端运行 Blazor WASM
问题
Blazor WASM 本来可以比 Blazor Server-Side 更容易被接受,并且不存在其在开发方面的缺点。目前,Blazor WASM 不支持功能齐全的调试体验,并且启动速度非常慢。这比使用 Blazor Server-Side 更能减慢开发速度。不过我个人认为,调试体验比启动速度慢更能减慢开发速度。
建议的解决方案
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 Server-Side 项目,然后将 Blazor WASM 项目引用到 Blazor Server-Side 项目。之后,对 Blazor Server-Side 的
Startup
和
_Host.cshtml
进行一些调整,以正确使用 Blazor WASM razor 文件和 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
-
创建一个 Blazor WASM 项目。ASP.NET Core Hosted 或 Standalone 选项都可以正常工作,但它们将具有不同的配置,稍后将进行讨论。其余选项不会产生任何影响。在此示例中,我将使用 ASP.NET Core Hosted 来解释有关 API 控制器的信息。之后还要创建 Blazor 服务器端项目。
-
截至目前,您的项目结构应类似于下面的第一个屏幕截图。
删除下面第二个屏幕截图中显示的 Blazor 服务器端项目中突出显示的项目。
-
将 Blazor WASM 项目引用到 Blazor 服务器端项目。
-
ASP.NET Core Hosted
- 引用
BlazorWasm.Client
和BlazorWasm.Server
项目。 - Standalone - 按原样引用单个 Blazor WASM 项目。
-
ASP.NET Core Hosted
- 引用
-
转到 Blazor 服务器端项目的
Startup
类。在ConfigureServices()
中,删除WeatherForecastService
以及BlazorServer.Data
命名空间,然后为HttpClient
添加服务,供 Blazor WASM 项目中的 razor 文件使用。services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(sp.GetRequiredService<NavigationManager>().BaseUri) });
注意 在生产中,我不建议创建
HttpClient
的实例。请改用IHttpClientFactory
。访问此文章 使用 IHttpClientFactory 实现弹性 HTTP 请求 。对于 ASP.NET Core WASM 项目
在
Configure()
中,映射控制器的端点。这将使用X.Server
/BlazorWasm.Server
项目中的控制器。app.UseEndpoints(endpoints => { endpoints.MapControllers(); ... });
-
转到 Blazor 服务器端项目的 /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 -->
-
最后,在
component
标记的type
属性中更改App
,并引用 Blazor WASM 项目中的App
razor 类文件。在此示例中,在BlazorWasm.Client
项目中找到App
类:<component type="typeof(App)" render-mode="ServerPrerendered" /> <!-- Previous --> <component type="typeof(BlazorWasm.Client.App)" render-mode="ServerPrerendered" /> <!-- New -->
就是这样!当您运行 Blazor 服务器端项目时,它应该会加载,而不会出现“正在加载...”文本。
- 未对 Blazor WASM 项目进行任何更改,并且未进行任何重大代码重复。
-
唯一需要更改的是引用和
launchSettings.json
&appsettings.json
。 -
至于
Startup
中 Blazor 服务器端的配置,您只需在 Blazor WASM 项目中创建扩展方法并在 Blazor 服务器端项目中使用它们即可。
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 Server 和 WASM 在一些关键领域有所不同:
- 身份验证:Blazor 服务器允许您在运行时自定义对特定区域的访问。在 WASM 中,授权一次性完成,应用程序代码将完整发送。
- 数据库访问:Blazor 服务器允许直接访问 EF 核心实体(因为代码仅在服务器上执行)。在 Blazor 中,实际上不可能直接访问任何数据库。这也是非常不鼓励的,因为您会将连接字符串发送到客户端。因此,您需要编写一个单独的 Web API 来访问数据。 3. 设置文件:您可以在服务器端 Blazor 中拥有任意数量的设置文件。客户端 Blazor 默认仅加载 appsettings.json。需要一种特殊机制来包含多个 .json 文件。
因此,对于大多数应用程序(当然是需要数据库访问的应用程序),您将无法在 WASM 和服务器端之间共享 100% 的代码库。
您应该这样做:
-
对于上面提到的要点(身份验证,但主要是数据库访问),创建数据访问服务依赖项(例如 IDataAccessLayer)。 一个实现将直接访问数据库(用于服务器端) 另一个实现将通过 HttpClient 访问数据库(用于 blazor WASM)。
-
现在,将您的整个应用程序放入 RCL 中。将其称为“BlazorAppRCL”。此 RCL 显然没有 Startup.cs 和 Program.cs
-
为服务器和客户端特定数据库访问实现创建一个项目
-
现在,您有以下一组项目:
对于服务器端: BlazorServer(仅具有设置 + Program.cs + Startup.cs)。它指的是 RCL + 服务器特定的 IDataAccessLayer 实现
对于托管 WASM: BlazorWebAPI:对于数据库访问,它具有访问数据库的 API BlazorClientDAL:WASM 特定的 IDataAccessLayer 实现 BlazorWASM:Blazor WASM 项目 所有这三个都引用您的 BlazorAppRCL。
关键是使用 DI/控制反转模式来解决 WASM 和服务器之间的分歧。 这样,您就可以同时拥有 WASM 实例和服务器实例,并且代码差异最小。请注意,WASM WebAPI 可以简单地使用服务器端 Blazor 的 IDataAccessLayer 实现。因此,除了 API 相关开销之外,不需要额外的编码。