You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从TypeScript生成的DTO获取ServiceStack原始路由?

问题背景

生产环境中出现了一个问题:接口返回的JSON响应与生成的TypeScript DTO定义的预期模型不匹配,但HTTP状态码却返回成功。我们计划借助ServiceStack OpenApiFeature提供的OpenAPI文档(/openapi端点)中的JSON Schema元数据,对JSON响应进行验证。验证需要获取三个关键变量:

  • HTTP方法:已明确指定
  • HTTP响应状态码:可通过client.responseFilter获取
  • 路由路径:这是当前的核心难题

以示例DTO为例:

[Route("/api20/data", "GET")]
public class GetData20 : IReturns<Data>
{
    public string Id { get; set; }
}

常规请求方式:

const data = await client.get(new GetData20({ id }));

我们需要获取该请求对应的RouteAttribute中定义的原始路由,但JsonServiceClient本身没有提供获取路由的API,它默认使用/json/reply/{DTO构造函数名}的路由,且生成的TypeScript DTO仅以注释形式包含路由信息。

最佳实践方案

1. 利用TypeScriptGenerator自动注入路由元数据(推荐)

通过配置ServiceStack的TypeScriptGenerator,在生成DTO时自动为每个类添加静态属性,存储路由和HTTP方法信息,无需手动维护。

.NET端配置示例

var generator = new TypeScriptGenerator(new MetadataTypesConfig {
    AddTypeScriptCode = (type, code) => {
        var routeAttr = type.FirstAttribute<RouteAttribute>();
        if (routeAttr != null) {
            code.AddLine($"static route = \"{routeAttr.Path}\";");
            code.AddLine($"static method = \"{routeAttr.Verb}\";");
        }
        return code;
    }
});

生成的TypeScript DTO示例

export class GetData20 {
    static route = "/api20/data";
    static method = "GET";
    public id?: string;
    // ...其他属性
}

客户端使用方式

发起请求时直接通过类的静态属性获取路由:

const dto = new GetData20({ id });
const route = GetData20.route;
const method = GetData20.method;
const data = await client.get(dto);

// 后续验证时直接使用route和method

2. 启用真实TypeScript装饰器生成

配置TypeScriptGenerator生成真实的@Route装饰器(而非注释),通过装饰器元数据提取路由信息。

.NET端配置示例

var generator = new TypeScriptGenerator(new MetadataTypesConfig {
    GenerateDecorators = true,
    DecoratorsNamespace = "ServiceStack"
});

生成的TypeScript DTO示例

import { Route } from 'ServiceStack';

@Route("/api20/data", "GET")
export class GetData20 {
    public id?: string;
    // ...其他属性
}

客户端提取路由信息

可以通过装饰器的元数据存储(需自行实现或借助装饰器库)来获取路由和方法:

// 假设装饰器会将元数据存储在类的__route__属性上
const routeInfo = (GetData20 as any).__route__;
const { route, method } = routeInfo;

3. 扩展JsonServiceClient实现路由自动关联

自定义扩展JsonServiceClient,提前维护DTO类型与路由的映射表,在请求发送前自动关联路由,并将路由信息传递给responseFilter。

步骤1:创建路由映射表

const dtoRouteMap: Record<string, { route: string; method: string }> = {
    GetData20: { route: "/api20/data", method: "GET" },
    // 其他DTO的路由映射
};

步骤2:扩展JsonServiceClient

class ExtendedJsonServiceClient extends JsonServiceClient {
    lastRouteInfo?: { route: string; method: string };

    async get<T>(dto: any): Promise<T> {
        const dtoName = dto.constructor.name;
        const routeInfo = dtoRouteMap[dtoName];
        if (routeInfo) {
            this.lastRouteInfo = routeInfo;
            return super.get(routeInfo.route, dto);
        }
        return super.get(dto);
    }

    // 同理扩展post、put等方法
}

步骤3:在responseFilter中使用路由信息

const client = new ExtendedJsonServiceClient(baseUrl);
client.responseFilter = (res) => {
    const { route, method } = client.lastRouteInfo!;
    const statusCode = res.status;
    // 利用route、method、statusCode从OpenAPI获取Schema并验证响应
};

4. 手动指定路由(备选方案)

如果上述方案暂时无法实施,可以在发起请求时手动指定路由,直接使用原始路由而非默认的/json/reply路径:

const data = await client.get("/api20/data", new GetData20({ id }));
// 同时保存路由信息用于后续验证
const route = "/api20/data";
const method = "GET";

内容的提问来源于stack exchange,提问作者donotcodeit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:37:03