Reputation: 1173
I have an MVC controller action with one parameter that should only be called with certain values for that parameter (null/empty and some specific strings), in other cases it should not be hit (404 mostly). I've tried using a RegexRouteConstraint like below. But that doesn't filter the specific strings.
var route = new Route("{soortAanbod}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Homepage", action = "Index", soortAanbod = UrlParameter.Optional }),
Constraints = new RouteValueDictionary(new { soortAanbod = new RegexRouteConstraint("a|b|c|d|e") }),
DataTokens = new RouteValueDictionary { { "area", context.AreaName } }
};
context.Routes.Add("Homepage_soortAanbod", route);
The controller looks like this: public ActionResult Index(string soortAanbod)
I've also tried using an action filter but that messes up other other filters. How can I make this route only match on the specified values for soortAanbod?
Upvotes: 1
Views: 685
Reputation: 56909
You have 2 issues:
^
and $
) to delimit the string you are attempting to match. So, it is matching any string that contains any of these letters.You can get around this by removing your custom route and using an IgnoreRoute
(which behind the scenes uses a StopRoutingHandler
) to prevent those specific URLs from matching.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("Homepage/Index/{soortAanbod}",
new { soortAanbod = new NegativeRegexRouteConstraint(@"^a$|^b$|^c$|^d$|^e$") });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
There is a caveat, though. RegEx's are not very good at doing negative matches, so if you are not a RegEx guru the simplest solution is to build a NegativeRegexRouteConstraint
to handle this scenario.
public class NegativeRegexRouteConstraint : IRouteConstraint
{
private readonly string _pattern;
private readonly Regex _regex;
public NegativeRegexRouteConstraint(string pattern)
{
_pattern = pattern;
_regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (parameterName == null)
throw new ArgumentNullException("parameterName");
if (values == null)
throw new ArgumentNullException("values");
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return !_regex.IsMatch(valueString);
}
return true;
}
}
Upvotes: 1
Reputation: 4456
You can create a custom constraint and use attribute routing, use the custom constraint there and make the constraint constructor accepts the list of strings that you want to avoid
Custom Constraint with Attribute Routing
Upvotes: 1
Reputation: 76
I think you can try attribute routing or maybe write your own attribute for action to check params or redirect somewhere.
public class SomeAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var yourstring = filterContext.RequestContext.HttpContext.Request.QueryString["string"];
if (!string.IsNullOrWhiteSpace(yourstring))
{
if (yourstring is not ok)
filterContext.Result =
new RedirectToRouteResult(
new RouteValueDictionary
{
{"controller", "SomeCtrl"},
{"action", "SomeAction"}
});
}
base.OnActionExecuting(filterContext);
}
Upvotes: 1