本文介紹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 框架的例項原始碼。