MVC Route Attribute error on two different routes

泪湿孤枕 提交于 2020-01-05 03:10:29

问题


I'm getting an attribute routing error with MVC 5.2. The error is

Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.

The routes in question are

[Route("{classname}/{id:int}")]
[Route("Edit/{id:int}")]

The url /Edit/123 throws the error, while the url /someword/123 does not throw the error

Given that Edit/123 is more specific than someword/123 why would it throw an error on /Edit/123?

Thanks,

john


回答1:


The routing framework doesn't make judgments about what route you probably intended (there's actually a route with Edit in it, so obviously I want that one). All it sees is that it has two routes which match the URL it has, and it throws its hands up.

Something like the following should fix the ambiguity, as long as you never need "Edit" as a value for classname:

[Route("{classname:regex(^(?!Edit)$)}/{id:int}")]



回答2:


There are two ways to fix this:

A regex constraint, as Chris pointed out.

Or a custom route constraint, like here: https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/

You can create custom route constraints by implementing the IRouteConstraint interface. For example, the following constraint restricts a parameter to set of valid values:

public class ValuesConstraint : IRouteConstraint
{
    private readonly string[] validOptions;
    public ValuesConstraint(string options)
    {
        validOptions = options.Split('|');
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
        }
        return false;
    }
}

The following code shows how to register the constraint:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        var constraintsResolver = new DefaultInlineConstraintResolver();

        constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));

        routes.MapMvcAttributeRoutes(constraintsResolver);
    }
}

Now you can apply the constraint in your routes:

public class TemperatureController : Controller
{
    // eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin
    [Route("temp/{scale:values(celsius|fahrenheit)}")]
    public ActionResult Show(string scale)
    {
        return Content("scale is " + scale);
    }
}

In my opinion, this isn't great design. There are no judgments about what URL you intended and no specificity rules when matching unless you explicitly set them yourself. But at least you can get your URLs looking the way you want. Hopefully your constraint list isn't too long. If it is, or you don't want to hard-code the route string parameter and its constraints, you could build it programmatically outside the action method and feed it to the Route attribute as a variable.



来源:https://stackoverflow.com/questions/26806395/mvc-route-attribute-error-on-two-different-routes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!