Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC AttributeRoute appears to be ignoring RoutePrefix and causing matching action in mutiple Controllers error

I am using the MVC Attribute Routing (MVC 5.1.2) and am running into the error:

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

The request has found the following matching controller types: FFInfo.WebUI.Areas.Admin.Controllers.HomeController FFInfo.WebUI.Areas.Admin.Controllers.SectionController

This only happens when I go to /Admin/Sections/ and I am not really sure why since there is only one route that can match that URL, can anyone help me figure out what is wrong? Please note this problem is unique to 5.1.2, MVC 5.0 it works fine.

Base Controller:

[RouteArea("Admin")]
public class BaseController : Controller
{
}

Home Controller:

[RoutePrefix("")]
[Route("{action}")]
public class HomeController : BaseController
{
    
    public ActionResult Index()
    {
    }

    public ActionResult Updates()
    {
    }

    [ChildActionOnly]
    public PartialViewResult GetUpdatesGrid()
    {
    }

    
    public ActionResult GetUpdates(JqGridRequest Request)
    {
    }
}

Section Controller:

[RoutePrefix("Sections")]
[Route("{action}")]
public class SectionController : BaseController
{
    [Route]
    public ActionResult Sections()
    {
    }

    [ChildActionOnly]
    public PartialViewResult GetSectionsGrid()
    {
    }

    public ActionResult GetSections(JqGridRequest Request)
    {
    }

    public ActionResult AddSection()
    {
    }

    [HttpPost, ValidateAntiForgeryToken]
    public ActionResult AddSection(AddEditSectionVM model, HttpPostedFileBase LogoFile)
    {
    }

    public ActionResult EditSection(Int16? ID)
    {
    }

    [HttpPost, ValidateAntiForgeryToken]
    public ActionResult EditSection(AddEditSectionVM model, HttpPostedFileBase Logo)
    {
    }

    public ActionResult Releases()
    {
    }

    [ChildActionOnly]
    public PartialViewResult GetReleasesGrid()
    {
    }

    public ActionResult GetReleases(JqGridRequest Request)
    {
    }

    public ActionResult AddRelease()
    {
    }

    [HttpPost, ValidateAntiForgeryToken]
    public ActionResult AddRelease(AddEditReleaseVM model)
    {
    }
}

My understanding of the RouteArea RoutePrefix, and Route attributes tells me that /Admin/Index will call the Index ActionResult of the Home Controller and the URL Admin/Sections should call the Index ActionResult of the Sections Controller. All the other routes work perfectly fine in each controller and when you go to /Admin/Index that works fine. I only get this error when I go to /Admin/Sections. What is wrong?

like image 776
Matthew Verstraete Avatar asked May 21 '14 00:05

Matthew Verstraete


1 Answers

This appears to be a side-effect of a breaking change in ASP.Net MVC 5.1 related to how Attribute Routing handles potential ambiguous matches: http://www.asp.net/mvc/overview/releases/mvc51-release-notes

We ran into similar issues when updating from 5.0 to the current 5.1.2. It seems like nested routes like this just happened to be working based on the old logic, and now they fail due to the strict breaking change.

In your example, /Admin/Index could technically match on the HomeController since it could be interpreted as /{area=Admin}/{action=Index}. It doesn't seem like there is any special logic (or at least, there doesn't seem to be anymore) that looks to see if the {action} segment happens to match a defined RoutePrefix on an alternate controller in the same Area.

This seems to make nested routes like this no longer possible, as you would have to add a defined RoutePrefix such as "Home" to HomeController differentiate between the controller route matches. Perhaps this is solvable via a RouteConstraint or another mechanism, but I haven't been able to find a solution yet.

like image 63
Ian Avatar answered Sep 23 '22 22:09

Ian