仅更改路由中具有继承的 .NET 7 中基控制器类的控制器名称

Change only the controller name in the route having an inherited Base Controller class in .NET 7

提问人:Matteo Pietro Peru 提问时间:10/24/2023 最后编辑:Matteo Pietro Peru 更新时间:10/24/2023 访问量:56

问:

我正在实现一个 ASP.NET Core 7 MVC Web 应用程序。

控制器部分由基类管理(该基类实际上具有我将通过在各个操作方法上添加模板来完成的属性),并且其他类从中继承。Route

BaseController类:

[Route("api/v1/[controller]")]
[ApiController]
public abstract class BaseApiController<TController> : ControllerBase
     where TController : ControllerBase
{
    // some code
}

继承自 的控制器类的示例:BaseController

public class AuthApiController : BaseApiController<AuthApiController>
{
    public AuthApiController(ILogger<AuthApiController> logger, IHttpContextAccessor httpContextAccessor, IUserService? userService)
        : base(logger, httpContextAccessor, userService: userService) { }

   [HttpGet("new")]
   public async Task<IActionResult> CreateNewUser()
   {
       // some code
   }
}

这样,动作的路线是:。CreateNewUser/api/v1/authapi/new

我的目标是只制作 (),所以我想知道是否有一种或另一种方法可以“合并”基本控制器的路由规则和操作上的各种模板,并且各个控制器的名称也可以自定义。authapiauth/api/v1/auth/newattribute

C# 路由 asp.net-core-mvc 属性 net-7.0

评论

0赞 SBFrancies 10/24/2023
为什么不将控制器重命名为 AuthController?
0赞 Matteo Pietro Peru 10/24/2023
@SBFrancies我想在 mvc 控制器和 api 控制器之间进行分离,但如果没有其他方法,最终我会这样做

答:

0赞 Qiang Fu 10/24/2023 #1

您可以覆盖特定操作的路由,不同于控制器使用
尝试以下操作
~

    [Route("api/v1/[controller]")]
    [ApiController]
    public class AuthApiController : ControllerBase
    {
        [HttpGet("new")]
        public void test()
        {

        }
        [HttpPost("~/api/v1/auth/new")]
        public void test2()
        {
        }
    }

enter image description here

或者也许改变整个控制器的路径使用

    [Route("api/v1/auth")]
    [ApiController]

评论

0赞 Matteo Pietro Peru 10/24/2023
它当然是这样的,但我想避免在所有操作上重复相同的路线
0赞 Matteo Pietro Peru 10/24/2023 #2

解决

正如这个问题的答案中所建议的,我实现了一个将路由组合在一起的路由,连接两个类的模板:custom attribute

 [AttributeUsage(AttributeTargets.Class)]
 public class ControllerNestedRouteAttribute : Attribute, IRouteTemplateProvider
 {
     private readonly Type _controllerType;

     public ControllerNestedRouteAttribute(string template, Type controllerType)
     {
         Name = template;
         _controllerType = controllerType;
     }

    public string Template
    {
        get
        {
            // Look up the route from the parent type. This only goes up one level, but if the parent class also has a `NestedRouteAttribute`, then it should work recursively.
            Type? baseType = _controllerType.BaseType;

            IRouteTemplateProvider? baseTypeRouteAttr = baseType?.GetCustomAttributes().FirstOrDefault(a => a is IRouteTemplateProvider) as IRouteTemplateProvider;
            string? baseTypeRouteAttrTemplate = baseTypeRouteAttr?.Template;

            if (!string.IsNullOrEmpty(baseTypeRouteAttrTemplate))
            {
                if (baseTypeRouteAttrTemplate.EndsWith('/'))
                    return Path.Join(baseTypeRouteAttrTemplate, Name);
                else
                    return Path.Join(baseTypeRouteAttrTemplate, "/", Name);
            }

            return Name;
        }
    }

     public int? Order => null;

     public string Name { get; }
 }

在继承的类中:

[ControllerNestedRoute("auth", typeof(AuthApiController))]
public class AuthApiController : BaseApiController<AuthApiController>
{
    public AuthApiController(ILogger<AuthApiController> logger, IHttpContextAccessor httpContextAccessor, IUserService? userService)
        : base(logger, httpContextAccessor, userService: userService) { }

   [HttpGet("new")]
   public async Task<IActionResult> CreateNewUser()
   {
       // some code
   }
}

在基本控制器中:

 [Route("api/v1")]
 [ApiController]
 public abstract class BaseApiController<TController> : ControllerBase
     where TController : ControllerBase
 {
   // ...
 }

现在我可以使用我想要的路由调用操作。/api/v1/auth/new