无法将路线与正确的动作相匹配

问题描述

我有一个正在旧ASP.NET MVC上运行的应用程序,我正尝试将其移植到ASP.NET Core 3.1。旧版本可以正常工作,但是在.NET Core版本中,我无法将相同的URL匹配到等效的操作。我在禁用EndpointRouting的情况下使用MVC(AddMvc / UseMvc)。这是所有配置(无显式路由):

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(o =>
        {
            o.EnableEndpointRouting = false;
        });
    }

    public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
    {
        app.UseMvc();
    }
}

控制器动作如下:

[ApiController]
[Route("[controller]")]
public class SomeController : ControllerBase
{
    [HttpPost]
    public ActionResult DoSomething(bool real)
    {
        return Content("Something Done");
    }
        
    [HttpPost]
    public ActionResult DoSomethingElse(bool unreal)
    {
        return Content("Something else done");
    }
}

URL(同样可以在.NET MVC中使用)如下:/Some?real=true解决了.NET MVC中的DoSomething操作,没有问题。在ASP.NET Core上,它引发异常:

Microsoft.AspNetCore.Mvc.Infrastructure.AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:

netcore.Controllers.someController.DoSomething (netcore)
netcore.Controllers.someController.DoSomethingElse (netcore)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionSelector.SelectBestCandidate(RouteContext context,IReadOnlyList`1 candidates)
   at Microsoft.AspNetCore.Mvc.Routing.MvcAttributeRouteHandler.RouteAsync(RouteContext context)
   at Microsoft.AspNetCore.Routing.Tree.TreeRouter.RouteAsync(RouteContext context)
   at Microsoft.AspNetCore.Routing.RouteCollection.RouteAsync(RouteContext context)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

但是为什么呢?这怎么会模棱两可?布尔变量的命名方式显然不同,不应有任何混淆。我知道可以通过更改路由或方法名称来修复它,但是我需要在不更改任何底层功能/ route / etc的情况下移植应用程序。

更新:将操作方法​​简化为具有一个布尔变量(具有不同的变量名称),并且歧义异常仍然发生。

解决方法

但是为什么呢?这怎么会模棱两可?布尔变量的命名方式明显不同,不应有任何混淆。

this doc中,您将找到:

在Asp.Net Core中,Controller和ApiController类被统一为一个Controller类。 Microsoft决定不再提供一种机制来尝试根据查询字符串查找正确的方法。

要达到ASP.NET Core的要求,您可以尝试实现自定义ActionMethodSelectorAttribute并将其应用于您的操作,如下所示。

[AttributeUsage(AttributeTargets.Method,AllowMultiple = true)]
public class CheckQueryStingAttribute : ActionMethodSelectorAttribute
{
    public string QueryStingName { get; set; }
    public bool CanPass { get; set; }
    public CheckQueryStingAttribute(string qname,bool canpass)
    {
        QueryStingName = qname;
        CanPass = canpass;
    }

    public override bool IsValidForRequest(RouteContext routeContext,ActionDescriptor action)
    {
        StringValues value;

        routeContext.HttpContext.Request.Query.TryGetValue(QueryStingName,out value);

        if (CanPass)
        {
            return !StringValues.IsNullOrEmpty(value);
        }

        return StringValues.IsNullOrEmpty(value);
    }
}

应用于操作

[ApiController]
[Route("[controller]")]
public class SomeController : ControllerBase
{
    [HttpPost]
    [CheckQuerySting("real",true)]
    [CheckQuerySting("unreal",false)]
    public ActionResult DoSomething(bool real)
    {
        return Content("Something Done");
    }

    [HttpPost]
    [CheckQuerySting("unreal",true)]
    [CheckQuerySting("real",false)]
    public ActionResult DoSomethingElse(bool unreal)
    {
        return Content("Something else done");
    }
}

测试结果

enter image description here