Blazor Web 應用如何實現Auto模式

known發表於2024-08-03

本文介紹Blazor Web應用Auto互動呈現模式的實現方案,如下示例是基於 Known 框架來實現的,該解決方案共有3個專案,具體實現步驟如下:

1. 前後端共用專案

  • 建立前後端共用類庫專案Sample,定義系統的實體類、資料模型、服務介面、常量、列舉等,專案工程檔案內容如下:
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>
</Project>
  • 在該專案中新增示例服務介面,繼承框架IService
//IService為框架定義的Api服務介面,用於標識該介面為前後端互動介面
//程式啟動時,框架自動查詢Assembly中的介面,根據介面定義WebApi路由
//該示例路由為:/Test/GetMessage
public interface ITestService : IService {
    Task<string> GetMessageAsync();
}

2. 客戶端專案

  • 建立客戶端專案Sample.Client,引用WebAssembly所需依賴,引用Castle依賴動態代理Http請求後端WebApi,專案工程檔案內容如下:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
        <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.6" />
        <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
        <PackageReference Include="Castle.Core" Version="5.1.1" />
        <PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
        <ProjectReference Include="..\Sample\Sample.csproj" />
    </ItemGroup>
</Project>
  • 新增攔截器HttpClientInterceptor.cs類檔案,繼承Castle.DynamicProxy.IAsyncInterceptor,實現Http動態代理
using Castle.DynamicProxy;

namespace Sample.Client;

// HttpInterceptor為框架封裝的攔截器
public class HttpClientInterceptor<T>(IServiceScopeFactory provider) : HttpInterceptor<T>(provider), IAsyncInterceptor where T : class {
    protected override async Task<HttpClient> CreateClientAsync() {
        var type = typeof(T);
        var factory = await ServiceFactory.CreateAsync<IHttpClientFactory>();
        var client = factory.CreateClient(type.Name);
        client.BaseAddress = new Uri(Config.HostUrl);
        return client;
    }

    public void InterceptAsynchronous(IInvocation invocation) {
        invocation.ReturnValue = SendAsync(invocation.Method, invocation.Arguments);
    }

    public void InterceptAsynchronous<TResult>(IInvocation invocation) {
        invocation.ReturnValue = SendAsync<TResult>(invocation.Method, invocation.Arguments);
    }

    public void InterceptSynchronous(IInvocation invocation) { }
}
  • Program.cs檔案中新增客戶端配置
//使用Castle代理生成器建立Http代理型別
private static readonly ProxyGenerator Generator = new();

services.AddHttpClient();
//新增KnownClient,注入攔截器提供者
services.AddKnownClient(info =>
{
    info.InterceptorType = type => typeof(HttpClientInterceptor<>).MakeGenericType(type);
    info.InterceptorProvider = (type, interceptor) =>
    {
        return Generator.CreateInterfaceProxyWithoutTarget(type, ((IAsyncInterceptor)interceptor).ToInterceptor());
    };
});
  • 新增測試頁面元件Test.razor
@page "/test"

<h1>@message</h1>

@code {
    //注入服務與Server模式注入沒有區別
    [Inject] private ITestService Service { get; set; }
    private string message;
    
    protected override async Task OnAfterRenderAsync(bool firstRender) {
        await base.OnAfterRenderAsync(firstRender);
        if (firstRender)
            message = await Service.GetMessageAsync();
        //這裡的Service例項,會根據渲染模式自動切換
        //SSR時,就是後端實現ITestService的實現類的例項
        //CSR時,就是Castle代理生成器建立的代理類的例項
    }
}

3. 服務端專案

  • 建立服務端專案Sample.Web,專案工程檔案內容如下:
<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.6" />
        <ProjectReference Include="..\Sample.Client\Sample.Client.csproj" />
    </ItemGroup>
</Project>
  • 修改App.razor檔案中的呈現模式
<Routes @rendermode="InteractiveMode" />

@code {
    private InteractiveAutoRenderMode InteractiveMode => new(false);
}
  • 新增TestService.cs實現服務介面
class  TestService : ITestService {
    public Task<string> GetMessageAsync() => Task.FromResult("test");
}
  • Program.cs檔案中新增服務端配置
//新增Known框架後端Core
services.AddKnownCore();
//新增Known框架自動生成WebApi
services.AddKnownWebApi();
//注入服務介面
services.AddScoped<ITestService, TestService>();

//使用Known框架靜態檔案和WebApi
app.UseKnown();

4. 結語

本文示例程式碼僅作Auto模式實現方案的參考,具體功能實現,可檢視 Known 框架的例項原始碼。

相關文章