ASP.NET MVC ambiguous action methods

Another approach is to rename one of the methods so there is no conflict. For example

// GET: /Movies/Delete/5
public ActionResult Delete(int id = 0)

// POST: /Movies/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id = 0)

See http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part9-cs


The parameters in your routes {roleId}, {applicationName} and {roleName} don't match the parameter names in your action methods. I don't know if that matters, but it makes it tougher to figure out what your intention is.

Do your itemId's conform to a pattern that could be matched via regex? If so, then you can add a restraint to your route so that only url's that match the pattern are identified as containing an itemId.

If your itemId only contained digits, then this would work:

routes.MapRoute("AssignRemove",
                "Items/{action}/{itemId}",
                new { controller = "Items" },
                new { itemId = "\d+" }
                );

Edit: You could also add a constraint to the AssignRemovePretty route so that both {parentName} and {itemName} are required.

Edit 2: Also, since your first action is just redirecting to your 2nd action, you could remove some ambiguity by renaming the first one.

// Method #1
public ActionResult AssignRemovePretty(string parentName, string itemName) { 
    // Logic to retrieve item's ID here...
    string itemId = ...;
    return RedirectToAction("Assign", itemId);
}

// Method #2
public ActionResult Assign(string itemId, string searchTerm, int? page) { ... }

Then specify the Action names in your routes to force the proper method to be called:

routes.MapRoute("AssignRemove",
                "Items/Assign/{itemId}",
                new { controller = "Items", action = "Assign" },
                new { itemId = "\d+" }
                );

routes.MapRoute("AssignRemovePretty",
                "Items/Assign/{parentName}/{itemName}",
                new { controller = "Items", action = "AssignRemovePretty" },
                new { parentName = "\w+", itemName = "\w+" }
                );

MVC doesn't support method overloading based solely on signature, so this will fail:

public ActionResult MyMethod(int someInt) { /* ... */ }
public ActionResult MyMethod(string someString) { /* ... */ }

However, it does support method overloading based on attribute:

[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }

[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }

public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
    public RequireRequestValueAttribute(string valueName) {
        ValueName = valueName;
    }
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
        return (controllerContext.HttpContext.Request[ValueName] != null);
    }
    public string ValueName { get; private set; }
}

In the above example, the attribute simply says "this method matches if the key xxx was present in the request." You can also filter by information contained within the route (controllerContext.RequestContext) if that better suits your purposes.