Have you ever written a very usable Route-constraint in ASP.NET MVC or in WebAPI than you wanted to share between them both? For example a constraint that supports nullable Guids (Guid?
) as route-parameter.
This can be done by implementing both System.Web.Routing.IRouteConstraint
and System.Web.Http.Routing.IHttpRouteConstraint
.
Hopefully this article will be obsolete with the release of ASP.NET 5, but until then, here's how you solve this problem:
public class NullableGuidConstraint : IRouteConstraint, IHttpRouteConstraint
{
// ASP.NET MVC-signature
public bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection)
{
return MatchInternal(parameterName, values);
}
// WebAPI-signature
public bool Match(
HttpRequestMessage request,
IHttpRoute route,
string parameterName,
IDictionary values,
HttpRouteDirection routeDirection)
{
return MatchInternal(parameterName, values);
}
private static bool MatchInternal(string parameterName, IDictionary values)
{
object value;
if (!values.TryGetValue(parameterName, out value))
{
return false;
}
if (value is Guid)
{
return true;
}
string stringValue = Convert.ToString(value, CultureInfo.InvariantCulture);
Guid guid;
bool isMatch = string.IsNullOrWhiteSpace(stringValue) || Guid.TryParse(stringValue, out guid);
return isMatch;
}
}
Then you register this constraint through, for example, DefaultInlineConstraintResolver
in System.Web.Mvc.Routing
for ASP.NET MVC and System.Web.Http.Routing
for WebAPI.
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("guid?", typeof(NullableGuidConstraint));
// ASP.NET MVC
routes.MapMvcAttributeRoutes(constraintResolver);
// WebAPI
routes.MapHttpAttributeRoutes(constraintResolver);
Now you can write attribute-routes like this:
[Route("{controller}/{action}/{id=guid?}")]