You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ASP.NET Boilerplate项目按模块生成独立NSwag服务代理的问询

按模块生成NSwag服务代理的解决方案

我之前在基于ASP.NET Boilerplate v2.0.1 + .NET Core + Angular 2的项目里,遇到过完全一样的问题——共用API端点导致生成的代理包含所有模块的服务,既臃肿又不利于模块解耦。这里分享几个亲测有效的方案:

方案一:基于路由前缀的NSwag过滤(最快捷)

这是最简单的实现方式,核心思路是给每个模块的API设置统一的路由前缀,然后在NSwag配置里过滤出对应前缀的接口生成代理:

  1. 后端配置路由前缀:给每个模块的控制器添加专属路由前缀,比如模块1的控制器都用/api/module1/开头:
[Route("api/module1/[controller]")]
public class Module1Controller : AbpController
{
    // 模块1的接口方法
}
  1. 创建模块专属NSwag配置文件:在Angular项目根目录下,复制原有的nswag.json,命名为nswag-module1.json,修改其中的operationProcessors节点,添加路由过滤规则:
"operationProcessors": [
  {
    "type": "OperationFilterProcessor",
    "excludeParametersWithoutDescription": false,
    "filter": "operation => operation.path.startsWith('/api/module1/')"
  }
]

同时记得修改output节点,把生成的代理文件输出到对应模块的目录,比如src/app/module1/services/module1-proxy.ts

  1. 执行模块代理生成命令:在终端运行对应模块的生成命令:
nswag run nswag-module1.json

同理,为其他模块创建对应的配置文件和生成命令即可。

方案二:基于自定义特性的接口过滤(更灵活)

如果你的模块路由没有统一前缀,或者希望更精准地控制哪些接口属于哪个模块,可以用自定义特性标记控制器,再通过NSwag过滤:

  1. 后端定义模块特性:创建一个自定义特性,用来标记接口所属的模块:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ModuleApiAttribute : Attribute
{
    public string ModuleName { get; }
    public ModuleApiAttribute(string moduleName) => ModuleName = moduleName;
}
  1. 给控制器打标记:在对应模块的控制器上添加这个特性:
[ModuleApi("Module1")]
[Route("api/some-custom-path/[controller]")]
public class Module1Controller : AbpController
{
    // ...
}
  1. NSwag配置特性过滤:修改模块专属的NSwag配置文件,添加基于特性的过滤规则:
"operationProcessors": [
  {
    "type": "OperationFilterProcessor",
    "filter": "operation => operation.operationDescription?.methodInfo?.DeclaringType?.GetCustomAttributes(true).Any(a => a is YourProjectNamespace.ModuleApiAttribute attr && attr.ModuleName == 'Module1') == true"
  }
]

这里需要替换YourProjectNamespace为你后端项目的实际命名空间。

方案三:提前铺垫独立API端点(适配未来规划)

既然你未来计划给单个模块配置独立API端点,现在可以提前按模块拆分路由,为后续的端点独立做铺垫:

在后端Startup.csUseEndpoints方法里,为每个模块配置独立的路由组:

app.UseEndpoints(endpoints =>
{
    // 模块1的路由组
    endpoints.MapControllers()
             .RequireAuthorization()
             .AddApplicationPart(typeof(Module1Controller).Assembly)
             .MapAreaControllerRoute(
                 name: "module1",
                 areaName: "Module1",
                 pattern: "api/module1/{controller=Home}/{action=Index}/{id?}");

    // 模块2的路由组
    endpoints.MapControllers()
             .RequireAuthorization()
             .AddApplicationPart(typeof(Module2Controller).Assembly)
             .MapAreaControllerRoute(
                 name: "module2",
                 areaName: "Module2",
                 pattern: "api/module2/{controller=Home}/{action=Index}/{id?}");
});

之后同样用方案一的路由前缀过滤方式生成模块代理,等未来要切换独立端点时,只需要修改NSwag配置里的swaggerGeneratorurl为对应模块的独立API地址即可,几乎不需要改动代理使用的代码。

额外注意事项

  • 生成的代理文件要放在对应模块的目录下,配合Angular的懒加载模块,能更好地实现模块的独立打包和部署;
  • 可以在package.json里添加模块代理生成的脚本,比如"generate:module1": "nswag run nswag-module1.json",方便快速执行;
  • 每次后端API更新后,记得重新生成对应模块的代理文件,避免前端调用出错。

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

火山引擎 最新活动