如何在 Asp.Net Core 的控制器操作和区域中限制参数类型

Posted

技术标签:

【中文标题】如何在 Asp.Net Core 的控制器操作和区域中限制参数类型【英文标题】:How to restrict parameter type in controller action and area in Asp.Net Core 【发布时间】:2021-05-24 15:26:55 【问题描述】:

我有 Asp.Net Core MVC Web 应用程序,其中有一个名为 AdminUI 的区域。

我的控制器如下所示:

[Area("AdminUI")]
public class ConfigurationController : BaseController

    public async Task<IActionResult> Client(int? id)
    
        if (id == default)
        
            var clientDto = _clientService.BuildClientViewModel();
            return View(clientDto);
        

        var client = await _clientService.GetClientAsync(id.Value);
        client = _clientService.BuildClientViewModel(client);

        return View(client);
    

而且我也有以下方法来添加该功能以使用特定名称为整个区域添加前缀:

public static IEndpointConventionBuilder MapIdentityServer4AdminUI(
    this IEndpointRouteBuilder endpoint, string patternPrefix = "/")

    return endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", 
        patternPrefix + "controller=Home/action=Index/id?");

如果我使用这个:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    ILoggerFactory loggerFactory)

    app.UseRouting();
    
    app.UseEndpoints(endpoint =>
    
        endpoint.MapIdentityServer4AdminUI("/myPrefix/");
    );

我可以通过以下链接访问 AdminUI 区域:

https://localhost:43000/myPrefix/Configuration/Client
https://localhost:43000/myPrefix/Configuration/Client/2

它运作良好,但现在我需要限制上面的 URL,这可以只访问带有 id 的方法 Client 是数字或在 URL 中没有 id 参数。我不知道如何实现,如果我想在上面的 URL 中保留前缀。

我试过这个办法,还是不行:

[Route("[area]/[controller]/[action]")]
[Route("[area]/[controller]/[action]/id:int")]
public async Task<IActionResult> Client(int id)

    ...

这很有效,我只能使用像数字这样的 ID 而没有 ID,但这会破坏 URL,因为它忽略了我上面的前缀。

网址现在是:

https://localhost:43000/AdminUI/Configuration/Client

不是:

https://localhost:43000/myPrefix/Configuration/Client

如何实现以下行为?

【问题讨论】:

【参考方案1】:
[Route("[area]/[controller]/[action]")]
[Route("[area]/[controller]/[action]/id:int")]
public async Task<IActionResult> Client(int id)

    ...

问题与上述 Route 属性有关。

众所周知,动作要么是传统路由,要么是属性路由。在控制器或操作上放置路由使其属性路由。定义属性路由的动作不能通过常规路由到达,反之亦然。控制器上的任何路由属性都会使控制器属性中的所有动作都被路由。

所以,通过使用上面的代码,它将使用属性路由。尝试更改您的代码如下:

[Route("myPrefix/[controller]/[action]")]
[Route("myPrefix/[controller]/[action]/id:int")]
public async Task<IActionResult> Client(int id)

    ...

参考:Mixed routing: Attribute routing vs conventional routing。

更新

此外,您还可以更改路线模板如下:

    public static IEndpointConventionBuilder MapIdentityServer4AdminUI(this IEndpointRouteBuilder endpoint, string patternPrefix = "/")
    
        return endpoint.MapAreaControllerRoute("AdminUI", "AdminUI",
            patternPrefix + "controller=Home/action=Index/id:int?");
    

然后,在控制器中,删除 Route 属性。

[Area("AdminUI")]
public class ConfigurationController : BaseController

    public async Task<IActionResult> Client(int? id)
    
        ...             
    

编辑

我想说的是:供整个AdminUI区域使用

endpoint.MapAreaControllerRoute("AdminUI", "AdminUI",
      patternPrefix + "controller=Home/action=Index/id?") 

对于 ConfigurationController 和 action Client 使用这个:

endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", patternPrefix + "controller=Home/action=Index/id:int?"); 

任何想法,如何结合这两个设置?

恐怕我们做不到(添加两个路由模板:一个用于整个 AdminUI 区域,一个用于 AdminUI 区域操作方法)。因为,如果我们同时添加它们,如果 url 与 action 方法的路由模板不匹配,它将使用区域路由模板。我能想到的唯一方法是为每个操作方法添加多个路由模板,而不为整个区域添加路由模板。像这样:

endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", patternPrefix + "Home/Index2/id:int");

[注意]以上路由只针对Home控制器Index2动作方法。

或者使用Route属性。

【讨论】:

我想在这里定义前缀:endpoint.MapIdentityServer4AdminUI("/myPrefix/"); - 这直接在控制器中,对我的场景没有用处。 您知道是否可以在此处的路线定义中以某种方式定义您建议的解决方案? endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", patternPrefix + "controller=Home/action=Index/id?"); - 以某种方式将此行与客户端方法的新行结合起来?谢谢! 嗨@Jenan,请检查我的更新,尝试更改路由模板如下:endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", patternPrefix + "controller=Home/action=Index/id:int?"); 并删除路由属性。 感谢您的更新,是否可以以某种方式说 - 对于某些操作使用这个新路由 endpoint.MapAreaControllerRoute("AdminUI", "AdminUI", patternPrefix + "controller=Home/action=Index/id:int?"); 而对于其余操作使用默认值?谢谢! 嗨@Jenan,我已经更新了,请检查一下。祝你有美好的一天!

以上是关于如何在 Asp.Net Core 的控制器操作和区域中限制参数类型的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 ASP.NET Core API 中的默认控制器和操作?

如何使 ASP.NET Core Web API 操作异步执行?

如何在asp.net core中获取当前用户

在 ASP.NET Core MVC 中将自定义查询参数添加到操作 URL

如何将 ASP.NET Core 5 Web API 控制器操作的失败模型验证结果包装到另一个类中并将响应返回为 OK

如何在 Asp Net Core Web App(不是 WebAPI)中存储令牌