源生成器简化 Blazor WebApp 模式开发

序:当去年.NET8 Blazor auto模式原型发布后,好多朋友都以为Blazor auto渲染模式需要写两套代码,或者全部用HttpClient请求,其实都不是正确姿势。本文介绍作者利用源生成器,只需实现服务端的service层,即可让Blazor的后端请求平滑地从server切换到wasm。

原文:

本文简略介绍一下如何使用增量生成器(Incremental Generator)简化BlazorServer兼容Auto模式

比如现在有一个BlazorServer项目的Razor页面

// UserIndex.razor
@code {
[Inject, NotNull] IUserService? Service { get; set; }
}

如果IUserService的实现不支持运行在WebAssembly,比如连接数据库,或者访问服务器文件等等,那么这种情况下,需要Server端提供接口,并且在Client端提供IUserService的接口调用实现

本文的目的就是通过增量生成器,完成Server端接口生成和Client端的接口调用

[WebController(Route = "user", Authorize = true)]
[ApiInvokerGenerate]
public interface IUserService
{
Task<User?> GetUserAsync(string id);
}

nuget地址

dotnet add package AutoWasmApiGenerator --version 0.0.2

在Server端生成Controller

// <auto-generated/>
#pragma warning disable
namespace Project.Constraints.Services
{
[global::Microsoft.AspNetCore.Mvc.ApiController]
[global::Microsoft.AspNetCore.Mvc.Route("api/user")]
[global::Microsoft.AspNetCore.Authorization.Authorize]
[global::System.CodeDom.Compiler.GeneratedCode("AutoWasmApiGenerator.ControllerGenerator", "1.0.0.0")]
/// <inheritdoc/>
public class UserServiceController : global::Microsoft.AspNetCore.Mvc.ControllerBase
{
private readonly Project.Constraints.Services.IUserService proxyService;

public UserServiceController(Project.Constraints.Services.IUserService service)
{
proxyService = service;
}

[global::Microsoft.AspNetCore.Mvc.HttpPost("GetUser")]
[global::Microsoft.AspNetCore.Authorization.Authorize]
[global::System.CodeDom.Compiler.GeneratedCode("AutoWasmApiGenerator.ControllerGenerator", "1.0.0.0")]
public System.Threading.Tasks.Task<Project.Constraints.Models.Permissions.User?> GetUserAsync([global::Microsoft.AspNetCore.Mvc.FromBody]string id)
=> proxyService.GetUserAsync(id);
}
}

在Client端生成调用类

// <auto-generated/>
#pragma warning disable
namespace Project.Constraints.Services
{
[global::System.CodeDom.Compiler.GeneratedCode("AutoWasmApiGenerator.HttpServiceInvokerGenerator", "1.0.0.0")]
[AutoInjectGenerator.AutoInjectAttribute(Group = "WASM")]
/// <inheritdoc/>
public partial class UserServiceApiInvoker : Project.Constraints.Services.IUserService
{
private readonly global::System.Text.Json.JsonSerializerOptions jsonOptions;

private readonly global::System.Net.Http.IHttpClientFactory clientFactory;

private readonly global::AutoWasmApiGenerator.IHttpClientHeaderHandler headerHandler;

public UserServiceApiInvoker(global::System.Net.Http.IHttpClientFactory factory, global::AutoWasmApiGenerator.IHttpClientHeaderHandler hander)
{
clientFactory = factory;
headerHandler = hander;https://www.jiwenlaw.com/
jsonOptions = new global::System.Text.Json.JsonSerializerOptions() { PropertyNameCaseInsensitive = true };
}

[global::System.CodeDom.Compiler.GeneratedCode("AutoWasmApiGenerator.HttpServiceInvokerGenerator", "1.0.0.0")]
public async System.Threading.Tasks.Task<Project.Constraints.Models.Permissions.User?> GetUserAsync(string id)
{
var url = "api/user/GetUser";
var client = clientFactory.CreateClient("UserService");
var request = new global::System.Net.Http.HttpRequestMessage();
request.Method = global::System.Net.Http.HttpMethod.Post;
headerHandler.SetRequestHeader(request);
var jsonContent = global::System.Text.Json.JsonSerializer.Serialize(id);
request.Content = new StringContent(jsonContent, global::System.Text.Encoding.Default, "application/json");
request.RequestUri = new Uri(url, UriKind.Relative);
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var jsonStream = await response.Content.ReadAsStreamAsync();
return global::System.Text.Json.JsonSerializer.Deserialize<Project.Constraints.Models.Permissions.User?>(jsonStream, jsonOptions);
}
}
}

好的,现在Controller有了,Controller的调用类也有了

项目结构如下,项目的nuget包和引用项目根据Blazor Web App的项目模板进行修改即可

  • BlazorAdminServer端项目

  • BlazorAdmin.ClientClient法律时刻端项目

  • Shared双端共用的项目,一般是共用的页面、实体模型、等等

BlazorAdmin Program.cs

......
......
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();

builder.Services.AutoInject();
builder.Services.AddControllers();
......
......
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies([.. AppConst.Pages]);
app.MapControllers();
......

BlazorAdmin.Client Program.cs

......
......
builder.Services.ConfigureHttpClientDefaults(c =>
{
c.ConfigureHttpClient(h => { h.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); });
});
builder.Services.AutoInjectWasm();
builder.Services.AddScoped<IUserService, UserServiceApiInvoker>();

当运行在Server端的时候,获取的IUserService实例是自己实现的接口,当运行在WebAssembly中时,获取的IUserService实例是UserServiceApiInvoker

posted @ 2024-08-19 22:09  农民小工程师  阅读(17)  评论(0编辑  收藏  举报
jiwenlaw.com