通用控制器的.Net核心替代控制器路由 [英] .Net Core Override Controller Route for Generic Controller
问题描述
我正在编写RestFramework,并且试图弄清楚如何允许用户为通用控制器创建自定义名称。我正在像这样注册我的通用控制器:
I'm writing a RestFramework and I'm trying to figure out how I can allow the users to create a custom name for a generic controller. I'm registering my generic controllers like so:
public class GenericControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
foreach (var entityConfig in _entityConfigurations)
{
var entityType = entityConfig.Type;
var typeName = entityType.Name + "Controller";
if (!feature.Controllers.Any(t => t.Name == typeName))
{
var controllerType = typeof(GenericController<>)
.MakeGenericType(entityType.AsType())
.GetTypeInfo();
//Normally I would expect there to be an overload to configure the controller name
//feature.Controllers.Add(controllerType, entityConfig.ControllerName);
}
}
}
}
如何我是否需要找出一种方法可以覆盖控制器的路由。文档中有关此内容的唯一信息显示了如何创建像这样的控制器约定:
How ever I need to figure out a way that I can override the route for the controllers. The only information about this in the documentation shows how to create a controller convention like so:
public class GenericControllerNameConvention : Attribute, IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.GetGenericTypeDefinition() !=
typeof(GenericController<>))
{
return;
}
var entityType = controller.ControllerType.GenericTypeArguments[0];
controller.ControllerName = entityType.Name;
}
}
由于在编译时已完成,因此无法使用。我需要用户能够在启动时覆盖控制器名称,该如何实现?
This will not work since it is done at compile time. I need user to be able to override the controller name on Startup, How can I Achieve this?
推荐答案
根据您的评论和代码,您几乎可以实现此目标。注意,我已经将示例简化了很多,因此可以设置测试。
Based on your comment and code you were pretty much on par with how you would achieve this. Note I have cut down the example quite a bit so I could setup a test.
说我有一个基本的通用控制器,例如:
Say I have a basic generic controller as:
public class GenericController<T> : Controller
where T: class
{
public IActionResult Get()
{
return Content(typeof(T).FullName);
}
}
我现在有一个带有Get操作的类型化控制器。现在,您的大多数代码都可以赚到钱。因此,我的功能提供者为(请注意,我有一个静态的类型数组):
I now have a typed controller with Get action. Now most of your code was right on the money. So my Feature Provider as (note i have a static array of types):
public class GenericControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
foreach (var entityConfig in ControllerEntity.EntityTypes)
{
var entityType = entityConfig;
var typeName = entityType.Name + "Controller";
if (!feature.Controllers.Any(t => t.Name == typeName))
{
var controllerType = typeof(GenericController<>)
.MakeGenericType(entityType)
.GetTypeInfo();
feature.Controllers.Add(controllerType);
}
}
}
}
下一步 IControllerModelConvention
实现。
public class GenericControllerModelConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
if (!controller.ControllerType.IsGenericType || controller.ControllerType.GetGenericTypeDefinition() != typeof(GenericController<>))
{
return;
}
var entityType = controller.ControllerType.GenericTypeArguments[0];
controller.ControllerName = entityType.Name + "Controller";
controller.RouteValues["Controller"] = entityType.Name;
}
}
最后,启动是发生所有魔术的地方。基本上,我们将 IControllerModelConvention
注册到MVC约定选项中,然后注册 FeatureProvider
。
And finally the startup is where all the magic happens. Basically we register the IControllerModelConvention
into the MVC convention options, and then register the FeatureProvider
.
public void ConfigureServices(IServiceCollection services)
{
var mvcBuilder = services.AddMvc();
mvcBuilder.AddMvcOptions(o => o.Conventions.Add(new GenericControllerModelConvention()));
mvcBuilder.ConfigureApplicationPartManager(c =>
{
c.FeatureProviders.Add(new GenericControllerFeatureProvider());
});
}
从我的评论中有两件事使我震惊。
From my review two things struck me.
- 我不确定您为什么将
GenericControllerNameConvention
作为属性? - 您应该将
Controller
路由值隐式设置为您的实体类型(而不是类型+名称)。
- I am not sure why you have your
GenericControllerNameConvention
as an attribute? - You should implicitly set the
Controller
Route Value to your entity type (not the type + name).
给定两个实体(EntityA和EntityB),控制器的结果为
Given two entities (EntityA and EntityB) the result of the controllers is
/ Entitya / get /
打印 WebApplication11.Infrastructure.EntityA
/ Entityb / get /
打印 WebApplication11.Infrastructure.EntityB
这篇关于通用控制器的.Net核心替代控制器路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!