ServiceProxy<T> 是 Known "前后端一体"的核心机制:客户端不写 HttpClient、不拼 URL、不做反序列化样板代码,
只注入 T(比如 IOrderService),运行时自动生成一个把方法调用转成 HTTP 请求的代理。
契约 = 接口 + [WebApi]
[WebApi]
public interface IOrderService
{
Task<PagingResult<Order>> QueryOrdersAsync(PagingCriteria criteria);
Task<Order> GetOrderAsync(string id);
Task<Result> SaveOrderAsync(Order order);
Task<Result> DeleteOrdersAsync(List<string> ids);
}
接口与它的 [Service] 默认实现同处一个文件(框架约定),这个文件放在服务端与客户端共同引用的模块程序集里——客户端只用到接口那一半。
服务端:AddKnownWeb 把接口暴露成路由
AddKnownWeb 在 Config.AddModule 的扫描结果里挑出带 [WebApi] 的接口与对应 [Service] 实现,
在 ASP.NET Core 上以最小 API 端点方式注册路由:
- HTTP 方法约定:Known 只用 GET / POST 两个动词——方法名以
Get开头且所有参数都是基元或string才走 GET,其余一律 POST(PagingCriteria、实体、List<>都算复杂参数 → POST)。 - 路径:
/api/{接口名去 I 去 Service}/{方法名去 Async},如IOrderService.QueryOrdersAsync→/api/Order/QueryOrders;可用[Route("...")]覆写。 - 参数绑定:单个复杂类型 → body;多个基元 /
string→ 查询串。 - 返回:
Task<T>、Task<Result>、Task<PagingResult<T>>都直接序列化为 JSON。Result在 Known 里非泛型(IsValid+Message),分页结果用PagingResult<T>(Total+Data),没有Result<T>这种包装。
客户端:AddKnownClient 把接口变成可用服务
客户端调用 AddKnownClient(option => option.BaseAddress = ...) 后,IOrderService 直接 @inject:
@inject IOrderService Orders
@code {
private List<Order> orders = [];
protected override async Task OnInitializedAsync()
{
// 分页查询:criteria 承载页码/排序/过滤,框架拼 SQL
var page = await Orders.QueryOrdersAsync(new PagingCriteria { PageIndex = 1, PageSize = 20 });
orders = page.Data;
// 按主键取单条:直接返回实体本身,无数据时为 null
var one = await Orders.GetOrderAsync("…id…");
}
}
ServiceProxy<T> 用 DispatchProxy 生成运行时类,Invoke 里根据方法名与参数拼出 URL、
序列化 body、发送请求、反序列化 Result<T>——所有 HttpClient 细节被完全屏蔽。
为什么值得这么做
- 一份类型定义三处用:编译期客户端、服务端路由契约、DTO 结构都指向同一份接口。
- 改造成本低:重命名方法 = 前后端同步失效(编译期就报错),不会出现"改了服务端忘了客户端"。
- 测试友好:单测里替换成假实现(
FakeOrderService),无需 mock HTTP。
边界
- 目前只覆盖同步方法调用 → HTTP 请求/响应;SSE / WebSocket / 长轮询走另外的通道(IN 侧规划)。
- 分页查询返回
PagingResult<T>、写操作返回非泛型Result(带IsValid/Message);直接返回Task<T>也支持,但会丢掉业务错误信息。 - 文件上传下载:走独立的
/api/upload端点,代理不自动处理Stream/IFormFile语义。 - API 版本管理(v1/v2)目前由路由段决定,接口本身不带版本;跨版本兼容性需在应用侧演进时自行保证。
未来
前后端一体能力属规划中的 Path C(不锁死、按 Batch 推进):IAuthProvider / ISyncApi 等新契约
落地时同样沿用 ServiceProxy<T> 代理机制,客户端零改造。
扫码关注公众号
扫码加入 QQ 群