源生成器简化 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 @   农民小工程师  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
jiwenlaw.com
点击右上角即可分享
微信分享提示