1

I have problems building an ASP.NET MVC page which allows two sorts of routing.

I have a database where all pages are stored with an url-path like: /Site1/Site2/Site3 i tried to use an IRouteConstraint in my first route, to check wether the requested site is a site from my database (permalink).

In the second case, i want to use the default asp.net mvc {controller}/{action} functionality, for providing simple acces from an *.cshtml.

Now i don't know if this is the best way. Furthermore i have the problem, how to root with the IRouteContraint.

Does anyone have any experiance with this?

I'm using asp.net mvc 5.

Problem solved, final solution:

  1. Adding this two routes:

    routes.MapRoute(
        "FriendlyUrlRoute",
        "{*FriendlyUrl}"
    ).RouteHandler = new FriendlyUrlRouteHandler();
    
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Page", action = "Load", id = UrlParameter.Optional },
        namespaces: controllerNamespaces.ToArray()
    );
    
  2. My own Route-Handler:

    public class FriendlyUrlRouteHandler : System.Web.Mvc.MvcRouteHandler
    {
        protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
        {
            var friendlyUrl = (string)requestContext.RouteData.Values["FriendlyUrl"];
    
            WebPageObject page = null;
    
            if (!string.IsNullOrEmpty(friendlyUrl))
            {
                page = PageManager.Singleton.GetPage(friendlyUrl);
            }
    
            if (page == null)
            {
                page = PageManager.Singleton.GetStartPage();
            }
    
            // Request valid Controller and Action-Name
            string controllerName = String.IsNullOrEmpty(page.ControllerName) ? "Page" : page.ControllerName;
            string actionName = String.IsNullOrEmpty(page.ActionName) ? "Load" : page.ActionName;
    
            requestContext.RouteData.Values["controller"] = controllerName;
            requestContext.RouteData.Values["action"] = actionName;
            requestContext.RouteData.Values["id"] = page;
    
            return base.GetHttpHandler(requestContext);
        }
    }
    

1 Answer 1

2

You can use attribute routing which is in MVC 5 and combine attribute routing with convention-based routing to check the condition that you want on controller class or action methods.

And you could make the constraint yourself to use it on the action methods like this:

public class ValuesConstraint : IRouteConstraint
{
    private readonly string[] validOptions;
    public ValuesConstraint(string options)
    {
        validOptions = options.Split('|');
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
        }
        return false;
    }
}

To use attribute routing you just need to call MapMvcAttributeRoutes during configuration and call the normal convention routing afterwards. also you should add your constraint before map the attributes, like the code below:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    var constraintsResolver = new DefaultInlineConstraintResolver();
    constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));
    routes.MapMvcAttributeRoutes(constraintsResolver);

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

Now on your controller class you can check the route and decide what to do with different urls like below:

for example: // /mysite/Site1 and /mysite/Site2 but not /mysite/Site3

[Route("mysite/{site:values(Site1|Site2)}")]
public ActionResult Show(string site)
{
    return Content("from my database " + site);
}

And you could do all kind of checking just on you controller class as well.

I hope this gives you a bit of clue to achieve the thing that you want.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, but when i use Attribute-Routing, how can i handle dynamic routs, which are stored in my database?
You can get the rout value within the ValuesConstraint class from your database and write the convention that suits your needs and then apply it on you action methods in your controller class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.