Differentiate recommendations and string parameters in MVC 3

Using local method locators in ASP.NET MVC (3 or 4DP), there is a way for the MVC structure to distinguish between a string and a Guid without having to parse a parameter in a controller action

Usage examples will be for URL

http: // [domain] / customer / details / F325A917-04F4-4562-B104-AF193C41FA78

execute

public ActionResult Details(Guid guid) 

and

http: // [domain] / customer / details / bill-gates

execute

 public ActionResult Details(string id) 

method.

Without changes, the methods are obviously ambiguous:

 public ActionResult Details(Guid id) { var model = Context.GetData(id); return View(model); } public ActionResult Details(string id) { var model = Context.GetData(id); return View(model); } 

leads to an error:

 The current request for action 'Details' on controller type 'DataController' is ambiguous between the following action methods: System.Web.Mvc.ActionResult Details(System.Guid) on type Example.Web.Controllers.DataController System.Web.Mvc.ActionResult Details(System.String) on type Example.Web.Controllers.DataController 

I tried to use a custom constraint (based on How to create a route constraint of type System.Guid? ) To try to execute it through routing:

 routes.MapRoute( "Guid", "{controller}/{action}/{guid}", new { controller = "Home", action = "Index" }, new { guid = new GuidConstraint() } ); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

And switched the action signatures to:

 public ActionResult Details(Guid guid) { var model = Context.GetData(guid); return View(model); } public ActionResult Details(string id) { var model = Context.GetData(id); return View(model); } 

The restriction is fulfilled and passes, so the argument is sent to the action, but, apparently, still as a string and, therefore, ambiguous for the two method signatures. I expect that there is something about how the action methods are ambiguous, and therefore can be overridden by connecting a user module to search for methods.

The same result can be achieved by parsing a string parameter, but for brevity it would be very useful to avoid this logic in action (not to mention reusing it later).

+7
source share
3 answers

First, you must break down your methods by giving them two different names:

 public ActionResult DetailsGuid(Guid guid) { var model = Context.GetData(guid); return View(model); } public ActionResult DetailsString(string id) { var model = Context.GetData(id); return View(model); } 

Then you need a special route handler to check the request and change the method name accordingly:

 using System.Web.Mvc; using System.Web.Routing; public class MyRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { var routeData = requestContext.RouteData; var stringValue = routeData.Values["id"].ToString(); Guid guidValue; var action = routeData.Values["action"]; if (Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty); routeData.Values["action"] = action + "Guid"; else routeData.Values["action"] = action + "String"; var handler = new MvcHandler(requestContext); return handler; } } 

Finally, add the Details route at the top of your routes, as shown below:

 routes.Add("Details", new Route("{controller}/Details/{id}", new RouteValueDictionary( new { controller = "Home", action = "Details" }), new MyRouteHandler() ) ); ); 

When a request arrives for details, the Details route will use your own route handler to verify the id token. The route handler adds the name of the action based on the id form, so the request will be directed to the corresponding action.

+11
source

My opinion is that using an action action selector is more convenient and less encoded.

 public class GuidMethodSelectorAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) { var idStr = controllerContext.RouteData.Values["id"]; if (idStr == null) return false; Guid a; var result = Guid.TryParse(idStr.ToString(), out a); return result; } } 

This selector checks for an ID parameter request. If it is guid, it returns true. So, to use it:

 public class HomeController : Controller { [GuidMethodSelector] public ActionResult Index(Guid id) { return View(); } public ActionResult Index(string id) { return View(); } } 
+8
source

If you are still registering routes this way, the GuidRouteConstraint () class has been added to a newer version of MVC and should be used instead of a custom implementation:

 public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Guid", "{controller}/{action}/{guid}", new { controller = "Home", action = "Index" }, new { guid = new GuidRouteConstraint() } ); } 

Then you can simply create the result of the action as:

 public class HomeController : Controller { public ActionResult Index(Guid guid) { } } 
+5
source

All Articles