通用控制器的.Net核心替代控制器路由 [英] .Net Core Override Controller Route for Generic Controller

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

问题描述

我正在编写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核心替代控制器路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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