3

I'm trying to add some custom routing logic based on url's stored in a database for mvc. (CMS Like), I think its fairly basic, but I feel like i'm not really getting anywhere.

Basically a user may type url's such as:

www.somesite.com/categorya/categoryb/categoryf/someitem
www.somesite.com/about/someinfo

In the database these items are stored, along with the type they are, i.e. a normal page, or a product page.

Depending on this I then want to actually hit a different 'action' method, i.e. I would like the above to hit the methods:

PageController/Product
PageController/Normal

These actions then load the content for this page and display the same view (product view, or a normal view).

Using the normal way of routing won't work, since I could potentially have things like;

cata/producta
cata/catb/catc/catd/cate/catf/producta

Now i've been looking here : ASP.NET MVC custom routing for search

And trying to use this as a basis, but how do I actually 'change' my action method I want to hit within the InvokeActionMethod call?

Using MVC 3.0 btw.

Thanks for any help/suggestions

Final Solution:

Global.asax

routes.MapRoute(
                "Default",
                "{*path}",
                new { controller = "Page", action = "NotFound", path= "Home" }
            ).RouteHandler = new ApplicationRouteHandler();

Route Handlers

public class ApplicationRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new ApplicationHandler(requestContext);
        }
    }

    public class ApplicationHandler : MvcHandler, IRequiresSessionState
    {
        public ApplicationHandler(RequestContext requestContext)
            : base(requestContext)
        {

        }

        protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
        {
            var url = RequestContext.RouteData.Values["path"].ToString();
            var page = SomePageService.GetPageByUrl(url);

            if (page == null)
            {
                RequestContext.RouteData.Values["Action"] = "NotFound";
            }
            else
            {
                RequestContext.RouteData.Values["Action"] = page.Action;
                RequestContext.RouteData.Values["page"] = page;
            }

            return base.BeginProcessRequest(httpContext, callback, state);
        }
    }
1
  • Which is what i've done so far, I'll add some code to show where i'm at Commented Aug 23, 2012 at 10:59

1 Answer 1

4
+50

Maybe not an exact solution for your situation, but I've recently had to handle something similar so this might point you in the right direction.

What I did was setup a simple route in Global.asax with a catch-all parameter which calls a custom RouteHandler class.

// Custom MVC route
routes.MapRoute(
    "Custom",
    "{lang}/{*path}",
    new { controller = "Default", action = "Index" },
    new { lang = @"fr|en" }
).RouteHandler = new ApplicationRouteHandler();

ApplicationRouteHandler.cs :

public class ApplicationRouteHandler : IRouteHandler
{
    /// <summary>
    /// Provides the object that processes the request.
    /// </summary>
    /// <param name="requestContext">An object that encapsulates information about the request.</param>
    /// <returns>
    /// An object that processes the request.
    /// </returns>
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string path = requestContext.RouteData.Values["path"] as string;
    // attempt to retrieve controller and action for current path
        Page page = GetPageData(path);

    // Method that returns a 404 error
        if (page == null)
            return SetupErrorHandler(requestContext, "ApplicationRouteHandler");

    // Assign route values to current requestContext
        requestContext.RouteData.Values["controller"] = page.Controller;
        requestContext.RouteData.Values["action"] = page.Action;
        return new MvcHandler(requestContext);
    }
}

Obviously the way you retrieve the action and controller names from your database will probably be much different than mine, but this should give you an idea.

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

7 Comments

Does exactly what I need, thanks! Knew it would be something fairly trivial just couldnt find any decent examples! I'll accept this as bounty assuming theres no 'nicer' way at end of today :)
Slight hiccup, in that to determine the 'action' I need, i need to use the session, which is currently set to null Basically the handler is hit before the session_start in the global.asax is called, don't suppose you had similar problems?
You're getting null from requestContext.HttpContext.Session? I believe the only way it can be null is if you have nothing stored in it.
Session_Start is hit after the GetHttpHandler method, but think we just need to re-work the way we're currently using the session
You're right, I just assumed session was available at that point but it isn't. You could try implementing the solution in this question (haven't tried it, so I have no idea...) : stackoverflow.com/questions/8810801/…
|

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.