2

I have a custom MvcRouteHandler which checks database if a Url exists and pairs it with some controller action and Id.

However if this route handler can not find a matching pair in database, I'd like MVC to keep try with other defined route handlers in route table.

How can I do that?

Update: (Example code added)

routes.MapRoute(
    name: "FriendlyRoute",
    url: "{FriendlyUrl}").RouteHandler = new FriendlyRouteHandler();

FriendlyRouteHandler is:

public class FriendlyRouteHandler : MvcRouteHandler
{
    private TancanDbContext db = new MyDbContext();

    protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
    {
        if (requestContext.RouteData.Values["FriendlyUrl"] != null)
        { 
            string friendlyUrl = requestContext.RouteData.Values["FriendlyUrl"].ToString();

            //Here, you would look up the URL Record in your database, then assign the values to Route Data
            //using "where urlRecord.Url == friendlyUrl"         
            try
            {
                UrlRecord urlRecord = db.UrlRecords.Single(u => u.URL == friendlyUrl);          
                //Now, we can assign the values to routeData
                if (urlRecord != null)
                {
                    requestContext.RouteData.Values["controller"] = urlRecord.Controller;
                    requestContext.RouteData.Values["action"] = urlRecord.Action;
                    if(urlRecord.EntityId != null)
                    requestContext.RouteData.Values["id"] = urlRecord.ObjectId;
                   }
                }
                else
                {
                    //Here, I want to redirect to next RouteHandler in route Table
                  requestContext.RouteData.Values["controller"] = friendlyUrl;
                }
            }
            catch (Exception ex)
            {               
                //throw;
                //Here too, I want to redirect to next RouteHandler in route Table
                requestContext.RouteData.Values["controller"] = friendlyUrl;
            }
        }
        return base.GetHttpHandler(requestContext);
    }
}

After adding this line it seems to work:

requestContext.RouteData.Values["controller"] = friendlyUrl;

Am I lucky or this is right way to do ? Do I need to use IRouteConstraint somewhere?

By the way, my influence was this article by Adam Riddick.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Bogac
  • 3,596
  • 6
  • 35
  • 58

1 Answers1

4

You want to use a custom Constraint, not a custom Handler for this.

routes.MapRoute(
    name: "example",
    url: "{friendly}",
    defaults: new { controller = "FriendlyController", action = "Display" },
    constraints: new { friendly = new FriendlyUrlConstraint() }
);

and then the constraint becomes:

public class FriendlyUrlConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var friendlyUrl = values[parameterName];

        // Your logic to return true/false here
    }
}
Peter Dolkens
  • 133
  • 1
  • 7
  • Thanks for your answer, but I didn't touch ASP .Net for more than a year now. – Bogac Mar 21 '18 at 13:01
  • 3
    Yup, I didn't think this would help you, but the next guy to stumble across your question while searching for something else (as I did) might find it useful :) Cheers – Peter Dolkens Mar 26 '18 at 23:34