本文介绍Blazor Web应用Auto交互呈现模式的实现方案,如下示例是基于 Known 框架来实现的,该解决方案共有3个项目,具体实现步骤如下:
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();
}
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代理生成器创建的代理类的实例
}
}
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();
本文示例代码仅作Auto模式实现方案的参考,具体功能实现,可查看 Known 框架的实例源码。