首页 > 解决方案 > ASP NET Core 在类中定义 API 控制器

问题描述

我目前正在从 .net 框架切换到 .net core 3.1。

在命名空间内定义 Api 控制器一切正常且有效。

现在我有一个案例,我需要在另一个类中声明 Api 控制器,如下所示:

namespace Api.Controllers
{
    public class MainClass : BaseClass
    {
        public MainClass()
        {
        }

        [ApiController]
        [Route("Test")]
        public class TestController : ControllerBase
        {
            [HttpGet]
            public int GetResult()
            {
                return 0;
            }
        }
    }
}

结果是,在启动类的“ConfigureServices”方法中调用“AddControllers”方法后找不到Api Controller。

MainClass 在调用 Startup 类之前被实例化。

我尝试更改全局路由并定义类似“{area=Test}/{controller=Test}”的区域,或者在 MainClass 上方设置 ApiController 属性,但它们都不起作用。

有没有办法让这个工作?

标签: asp.net-coreasp.net-apicontroller

解决方案


看起来默认ControllerFeatureProvider不将嵌套控制器类型视为控制器。您可以添加(不需要替换)您的自定义提供程序来更改该行为,如下所示:

public class NestedControllerFeatureProvider : ControllerFeatureProvider
{
    protected override bool IsController(TypeInfo typeInfo)
    {
        if(!typeInfo.IsClass) return false;
        if(typeInfo.IsAbstract) return false;
        var isNestedType = typeInfo.DeclaringType != null;
        var isPublic = true;
        var parentType = typeInfo.DeclaringType;
        while(parentType != null){
            isPublic = parentType.IsPublic;
            parentType = parentType.DeclaringType;                 ​
       ​ }
       ​ return isNestedType && isPublic;                  ​
     }
}

然后将该提供程序添加到ApplicationPartManagerin 中,Startup.ConfigureServices如下所示:

​​services
    .AddMvc()
  ​​  .ConfigureApplicationPartManager(appPart => {
        ​​appPart.FeatureProviders.Add(new NestedControllerFeatureProvider());
    });

如果要替换默认值ControllerFeatureProvider,只需在 中找到FeatureProviders并删除即可。当然,您需要确保您的自定义项应该像默认逻辑一样处理所有内容,如下所示:

​​//for IsController
return base.IsController(typeInfo) || <...your-custom-logic...>;

注意:您可以参考ControllerFeatureProvider的默认实现来学习一些标准逻辑来正确实现自己的逻辑。上面的代码只是一个基本示例。对我来说,只要类继承自ControllerBase而不是abstract,它们就可以作为控制器正常工作以服务请求。除了一些奇怪的约定(例如:不以结尾的类名Controller仍然是控制器或应用于控制器类的某些标准属性不起作用......)之外,不会有严重的麻烦。

我们不应该使用嵌套的控制器类。每个控制器类都应该放在一个单独的文件中(作为一个好习惯)。然而这个答案的重点(我很确定不是很多人知道的最有趣的部分是使用ControllerFeatureProvider它可以帮助您自定义其他场景中设置的功能)。真的,如果你真的必须以某种方式坚持你的设计,你当然必须使用这个解决方案,别无他法。


推荐阅读