ASP.NET MVC - Route Check

My ASP.NET MVC application has a scenario in which user input can directly affect the purpose of calling RedirectToAction () (via a string), and there is a chance that the user may create a runtime error if incorrect input causes them to request an action that does not exist. I would like to prevent this problem, but I would like to do it in the least degree of taxation, since this should be done on a large number of requests. In this case, reflection would be a viable solution to confirm that / Controller / ActionName actually exists, but reflection is a rather difficult operation.

What would be the best way to confirm that a given Url in an ASP.NET MVC application is actually connected to a controller action?

+1
source share
3 answers

The route I received here was a reflection and a Dictionary containing all valid actions in the corresponding Controller, which is stored in Appendix []. The actual action is determined by checking the ReturnType method and verifying that it (or comes from) the ActionResult and that it is not private. I could do a few more checks, but for now there are enough of them.

public static bool MethodIsAction(MethodInfo method) { if (method == null) throw new ArgumentNullException("Invalid Parameter: method cannot be null."); if (method.ReturnType != typeof(ActionResult) && method.ReturnType.BaseType != typeof(ActionResult)) return false; if (method.IsPrivate) return false; return true; } 

The action dictionary is built with the following method inside Application_Start:

 public static Dictionary<string, MethodInfo> GetActionDictionary(Type controller) { Dictionary<string, MethodInfo> dict = null; var methods = controller.GetMethods().Where(MethodIsAction); if (methods.Any()) { dict = new Dictionary<string, MethodInfo>(StringComparer.OrdinalIgnoreCase); foreach (var action in methods) dict.Add(action.Name, action); } return dict; } 

When a user requests a qualifying action, I simply specify the name of the action in the dictionary, and if for this action name I call the MethodInfo method, I call it. Although it still requires reflection, it is at least optimized so that it only ever happens while the application is running.

0
source

One way to do this is to have a list of valid values ​​for user input. For example, if a user entered their favorite color:

 // userColour = the user set colour var allowableColours = new [] { "Red", "Blue", "Green" }; if (!allowableColours.Contains(userColour)) { // Set to a default colour. userColour = "Red"; } return RedirectToAction(userColour, "Colour"); 

Although it is not as dynamic as looking at a routing table, it would be quick, and you could be sure that the user is not entering any malicious information that hangs with your routing.

+2
source

A quicker and rougher option is to simply click on the URL, the following code can help you quickly check something,

Note: you are actually clicking on your site and are aware of what this means in your application.

This helped us diagnose some environmental issues in some integration tests.

 var urlToExec = "http://yoursite.com/" + controllerAndAction; var wr = (HttpWebRequest) WebRequest.Create(urlToExec); try { var resp = (HttpWebResponse)wr.GetResponse(); if (resp.StatusCode != HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.NotFound) //it was found } catch (Exception ex) { //404 or other http error //404 and the like result in GetResponse() throwing an exception //this was verified by having actions return via: //'return new HttpNotFoundResult("This doesn't exist");' } 
+1
source

All Articles