本文介绍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="..SampleSample.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.ClientSample.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 框架的实例源码。