我正在尝试创建这样的通用控制器:
[Route("api/[controller]")]
public class OrdersController<T> : Controller where T : IOrder
{
[HttpPost("{orderType}")]
public async Task<IActionResult> Create(
[FromBody] Order<T> order)
{
//....
}
}
Run Code Online (Sandbox Code Playgroud)
我打算使用{orderType} URI段变量来控制控制器的泛型类型.我正在尝试自定义IControllerFactory和IControllerActivator,但没有任何工作.每次我尝试发送请求时,都会收到404响应.我的自定义控制器工厂(和激活器)的代码永远不会执行.
显然问题是ASP.NET Core期望有效的控制器以后缀"Controller"结束,但我的通用控制器却具有(基于反射的)后缀"Controller`1".因此,它声明的基于属性的路线将被忽视.
在ASP.NET MVC中,至少在早期,它DefaultControllerFactory负责发现所有可用的控制器.它测试了"Controller"后缀:
MVC框架提供了一个默认的控制器工厂(恰当地命名为DefaultControllerFactory),它将搜索appdomain中的所有程序集,查找实现IController的所有类型,其名称以"Controller"结尾.
显然,在ASP.NET Core中,控制器工厂不再负有此责任.正如我之前所说,我的自定义控制器工厂为"普通"控制器执行,但从不为通用控制器调用.因此,在评估过程的早期还有其他一些东西可以控制控制器的发现.
有谁知道什么"服务"界面负责该发现?我不知道自定义界面或"钩子"点.
有没有人知道如何让ASP.NET Core"转储"它发现的所有控制器的名称?编写单元测试可以很好地验证我期望的任何自定义控制器发现确实有效.
顺便提一下,如果存在允许发现通用控制器名称的"钩子",则意味着还必须规范路由替换:
[Route("api/[controller]")]
public class OrdersController<T> : Controller { }
Run Code Online (Sandbox Code Playgroud)
无论给出什么值T,[controller]名称必须保持简单的基本通用名称.使用上面的代码作为示例,[controller]值将是"Orders".它不会是"Orders`1"或"OrdersOfSomething".
这个问题也可以通过显式声明封闭泛型类型来解决,而不是在运行时生成它们:
public class VanityOrdersController : OrdersController<Vanity> { }
public class ExistingOrdersController : OrdersController<Existing> { }
Run Code Online (Sandbox Code Playgroud)
上面的工作,但它产生我不喜欢的URI路径:
~/api/VanityOrders
~/api/ExistingOrders
Run Code Online (Sandbox Code Playgroud)
我真正想要的是这个:
~/api/Orders/Vanity
~/api/Orders/Existing
Run Code Online (Sandbox Code Playgroud)
另一个调整让我得到我正在寻找的URI:
[Route("api/Orders/Vanity", …Run Code Online (Sandbox Code Playgroud) 我们有标准的 ASP.NET Core 解决方案,Microsoft.Extensions.DependencyInjection需要根据配置设置注册某些控件。
某些ApiController继承自的示例ControllerBase及其所有相关操作仅应在某些bool为真时注册。
这可能吗?我看了看,services.AddMvc()但没有看到任何可以轻松让我执行以下操作的选项:
ExampleController被注册ExampleController及其所有相关操作IServiceCollection