ASP.NET Core API:添加自定义路由令牌解析器
Posted
技术标签:
【中文标题】ASP.NET Core API:添加自定义路由令牌解析器【英文标题】:ASP.NET Core API: Add custom route token resolver 【发布时间】:2021-10-24 22:36:41 【问题描述】:我在我的项目中使用https://github.com/ardalis/ApiEndpoints(每个控制器一个操作),我遇到了[Route("[controller]")]
并不适合我的问题,因为控制器看起来像这样:
我需要类似 [Route("[namespace]")]
的东西,但 ASP.NET Core 不支持。
有没有办法在Startup.cs
中添加自定义路由令牌解析?
我目前的解决方案:
硬编码路线 创建包含自定义标记的路由的自定义属性,以及解析自定义标记并生成Route
属性的源生成器。
【问题讨论】:
【参考方案1】:非常感谢@Kahbazi 为我指明了正确的方向!
这是我想出的:
private class CustomRouteToken : IApplicationModelConvention
private readonly string _tokenRegex;
private readonly Func<ControllerModel, string?> _valueGenerator;
public CustomRouteToken(string tokenName, Func<ControllerModel, string?> valueGenerator)
_tokenRegex = $@"(\[tokenName])(?<!\[\1(?=]))";
_valueGenerator = valueGenerator;
public void Apply(ApplicationModel application)
foreach (var controller in application.Controllers)
string? tokenValue = _valueGenerator(controller);
UpdateSelectors(controller.Selectors, tokenValue);
UpdateSelectors(controller.Actions.SelectMany(a => a.Selectors), tokenValue);
private void UpdateSelectors(IEnumerable<SelectorModel> selectors, string? tokenValue)
foreach (var selector in selectors.Where(s => s.AttributeRouteModel != null))
selector.AttributeRouteModel.Template = InsertTokenValue(selector.AttributeRouteModel.Template, tokenValue);
selector.AttributeRouteModel.Name = InsertTokenValue(selector.AttributeRouteModel.Name, tokenValue);
private string? InsertTokenValue(string? template, string? tokenValue)
if (template is null)
return template;
return Regex.Replace(template, _tokenRegex, tokenValue);
在Startup.cs
中配置令牌(这可以包装在扩展方法中):
services.AddControllers(options => options.Conventions.Add(
new CustomRouteToken(
"namespace",
c => c.ControllerType.Namespace?.Split('.').Last()
));
之后,自定义令牌可用于路由:
[ApiController]
[Route("api/[namespace]")]
public class Create : ControllerBase
[ApiController]
public class Get : ControllerBase
[HttpGet("api/[namespace]/id", Name = "[namespace]_[controller]")]
public ActionResult Handle(int id)
【讨论】:
【参考方案2】:您可以通过实现IApplicationModelConvention
来实现这一点。更多信息在这里:Custom routing convention
public class NamespaceRoutingConvention : IApplicationModelConvention
public void Apply(ApplicationModel application)
foreach (var controller in application.Controllers)
controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel()
Template = controller.ControllerType.Namespace.Replace('.', '/') + "/[controller]"
;
然后在startup.cs中添加
public void ConfigureServices(IServiceCollection services)
services.AddMvc(options =>
options.Conventions.Add(new NamespaceRoutingConvention());
);
【讨论】:
【参考方案3】:区域正是您所需要的。如 .net 核心文档中所述:
区域是用于组织相关功能的 ASP.NET 功能 作为一个单独的组:
路由命名空间。 视图和 Razor 页面的文件夹结构。
要使用区域路线,您只需将它们添加到启动中。
像这样:
app.UseEndpoints(endpoints =>
endpoints.MapControllerRoute(
name: "MyArea",
pattern: "area:exists/controller=Home/action=Index/id?");
endpoints.MapControllerRoute(
name: "default",
pattern: "controller=Home/action=Index/id?");
);
之后,路线将遵循您在 Areas 文件夹中的文件夹结构。 如需更多信息,请访问Areas in ASP.NET Core 文档。
【讨论】:
您能否阐明为 Api 控制器启用区域路由所需的步骤? ASP.NET Core 要求 Api 控制器具有[Route]
属性,而 [Route("[area]")]
不起作用,因为它无法识别 area
令牌(即使在像您显示的那样映射路由之后)。
@МаксимКошевой 主要步骤是从您的项目中删除 APIEndPoints。在此之后一切都会正常工作
我的项目是一个 API,因此从控制器中删除 [ApiController] 标记只是为了更容易路由不是一种选择。 ASP.NET 需要 [Route] 是有原因的,我同意。我需要的是一种扩展此属性以解析自定义令牌的方法,而不是摆脱它。以上是关于ASP.NET Core API:添加自定义路由令牌解析器的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口