The default Route class does not interact with the query string. But, you can inherit it to add additional functionality.
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
public class NumericCheckingQueryStringValueRoute : Route
{
private readonly string queryStringKey;
private readonly RouteValueDictionary defaultsIfNumeric;
private readonly RouteValueDictionary defaultsIfNonNumeric;
public NumericCheckingQueryStringValueRoute(
string url,
string queryStringKey,
object defaultsIfNumeric,
object defaultsIfNonNumeric)
: base(url, new MvcRouteHandler())
{
this.queryStringKey = queryStringKey;
this.defaultsIfNumeric = new RouteValueDictionary(defaultsIfNumeric);
this.defaultsIfNonNumeric = new RouteValueDictionary(defaultsIfNonNumeric);
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var result = base.GetRouteData(httpContext);
// If it matches, the result will be non-null
if (result != null)
{
var newResult = new RouteData(this, new MvcRouteHandler());
// Copy the route values from the base class
foreach (var value in result.Values)
{
newResult.Values[value.Key] = value.Value;
}
// Copy the data tokens from the base class
foreach (var token in result.DataTokens)
{
newResult.DataTokens[token.Key] = token.Value;
}
var requestQueryString = httpContext.Request.QueryString;
var queryStringValue = requestQueryString[this.queryStringKey];
if (string.IsNullOrEmpty(queryStringValue))
{
return null;
}
RouteValueDictionary defaultsToUse;
if (ContainsDigits(queryStringValue))
{
defaultsToUse = this.defaultsIfNumeric;
}
else
{
defaultsToUse = this.defaultsIfNonNumeric;
}
// Copy the numeric defaults to route values
foreach (var value in defaultsToUse)
{
newResult.Values[value.Key] = value.Value;
}
// We matched, return the result
return newResult;
}
// Return null if no match
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
// We just pass this through. If you add the value as a route value
// when building ActionLink or RouteLink, it will automatically make
// it into a query string value because it is not part of the url argument.
return base.GetVirtualPath(requestContext, values);
}
// Fastest way to check for digits
// http://stackoverflow.com/questions/7461080/fastest-way-to-check-if-string-contains-only-digits
private bool ContainsDigits(string str)
{
foreach (char c in str)
{
if (c >= '0' && c <= '9')
return true;
}
return false;
}
}
Usage
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
name: "CheckNumericName",
item: new NumericCheckingQueryStringValueRoute(
url: "Home",
queryStringKey: "name",
defaultsIfNumeric: new { controller = "Home", action = "HasNumber" },
defaultsIfNonNumeric: new { controller = "Home", action = "DoesntHaveNumer" }
)
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
And to build links to the page, you will need to add the query string value to the route values collection. You should use RouteLink since you have it going to 2 different action methods.
@Html.RouteLink("Link with number", "CheckNumericName", new { name = "q2e" })
@Html.RouteLink("Link with no number", "CheckNumericName", new { name = "qwe" })