.Net Core 覆盖通用控制器的控制器路由 [英] .Net Core Override Controller Route for Generic Controller

查看:43
本文介绍了.Net Core 覆盖通用控制器的控制器路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个 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.

  1. 我不知道您为什么将 GenericControllerNameConvention 作为属性?
  2. 您应该将 Controller 路由值隐式设置为您的实体类型(而不是类型 + 名称).
  1. I am not sure why you have your GenericControllerNameConvention as an attribute?
  2. 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 Core 覆盖通用控制器的控制器路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆