MVC Routing

Corbin Camp
Member since: 2012

I'm trying to wrap my head around how EPi7 using MVC handles custom routing.  I have a custom data search page (not content. data is managed in a seperate system) where I want to pull two paramenters from the url.

My url is something like

"find-data" is a page that collects the search parameters. "results" is a page that processes the request. "texas" and "green" are the two parameters. If I navigate to it loads correctly but with no search data. What I'm hoping will happen is when /find-data/results/texas/green/ is requested, I can pass "texas" and "green" into my code and display the results for the "results" page.

I can't seem to figure out how make the routing work. I've done similar things plenty of times with plain MVC apps and I can get the data I need from teh ViewContext.RouteData. Granted that was MVC 3, but I can't imagine it's that much different in 4. I have the route registered in my Global.ascx. When I debug through VS, it hits the RegisterRoutes method. I'm get a 404 every time I run the page request with parameters. I know I could do a query string but I'm really trying to stay away from that. I like my urls to be descriptive.

#65320 Jan 26, 2013 0:26

    Could you post the code where you´re registering the route and the code for your controller (just the method signatures).



    #65326 Jan 26, 2013 12:00
  • Corbin Camp
    Member since: 2012

    public class Global : EPiServer.Global
            protected void Application_Start()

            protected override void RegisterRoutes(System.Web.Routing.RouteCollection routes)

                RouteTable.Routes.MapContentRoute(name: "FindData",
                url: "find-data/results/{state}/{color}/",
                defaults: new { action = "index" });



    controller: // no controller for partial view. Do I need one?

    public class InteriorController : PageController<InteriorPage>
            public ActionResult Index(InteriorPage currentPage)
                /* Implementation of action. You can create your own view model class that you pass to the view or
                 * you can pass the page type for simpler templates */

                return View(currentPage);


    I'm trying to get my page to run a partial view only if there are parameters present. If not, then, it will display content


    @model Models.Pages.InteriorPage

        Layout = "~/Views/Layouts/_Layout.cshtml";

       var data = ???? // ViewContext.RouteData.Values

    <div class="article-gen" role="main">
                @if (data != null) { // data would be a dictionary with the parameters - texas and green in this case
                   Html.RenderPartial("~/Views/Shared/FindDataResults.cshtml", data.ToDictionary<string, string>());
                } else {
                    <h1 @Html.EditAttributes(x => x.Title)>@Model.Title</h1>
                    @Html.PropertyFor(m => m.MainBody) // probably some default message pulled from CMS.



    I've modified the route a bit to use

    defaults: new { controller = "Interior",
                                action = "Index",
                                state = UrlParameter.Optional,
                                color = UrlParameter.Optional });

    I no longer get a 404 but I do get this message, when I'm running on Cassini. If I use my IIS, it gives a 404.

    The provided content link does not have a value

    [ArgumentNullException: The provided content link does not have a value. Parameter name: contentLink] EPiServer.DataFactory.Get(ContentReference contentLink, ILanguageSelector languageSelector) +161 EPiServer.Web.Routing.MultiplexingRouteHandler.GetRoutedData(RequestContext requestContext, String language) +225 EPiServer.Web.Routing.MultiplexingRouteHandler.GetRouteHandler(RequestContext requestContext) +82 EPiServer.Web.Routing.MultiplexingRouteHandler.GetHttpHandler(RequestContext requestContext) +44 System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +8913000 System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +86 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +


    I'm on the right track but I'm obviously missing something.




    #65382 Edited, Jan 28, 2013 16:16


    I’m not really sure what you want to do here, if you want to route to a CMS page or not.

    Routing to a CMS page

    If you want to route to a CMS page, which you have specified in your controller, you should register a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: "{node}/{action}/{state}/{color}/", defaults: new { action = "index" }); This route will route to a page in the page tree. If you have created a page with the name “find-data” and goes to it will go to the controller that handles the pagetype the “find-data” have been created with. It will then use the “results” action in that controller. To use the index action you have to go to

    If you want to go to a page called “results”, you have to create a subpage to “find-data” called “results”, which you now can reach with the url: /results/index/texas/green/

    What I don’t understand is that you are saying that it’s not content data. If that’s true, this is not what you want, and then you shouldn’t even involve EPiServer MVC in this.

    Routing with plain MVC, not EPiServer

    In this case, you should add a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: "find-data/results/{action}/{state}/{color}/", defaults: new { controller = “interior”, action = "index" });

    Now, you cannot use the PageController<T> base class, because you haven’t specified that any content from EPiServer should be loaded. If you want that, you need to use the {node} in the pattern. Now you can use the url /results/index/texas/green/ which will go to the controller “interior” that cannot use PageController as base class. Base class should be “Controller” here. Now you can have two inparameters, state and color:

    Public class InteriorController : Controller


    Public ActionResult Index(string state, string color)




    Something in between

    Maby you want something in between those alternatives, like /results/MYPAGE/index/texas/green/. Now you can create a page called MYPAGE and register a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: " find-data/results /{node}/{action}/{state}/{color}/", defaults: new { action = "index" });

    Your controller can now look like (InteriorPage must inherit from PageData):

    Public class InteriorController : PageController<InteriorPage>


    Public ActionResult Index(InteriorPage currentPage, string state, string color)





    I need more info of what you are trying to do. I’m very confused about the code you posted.

    Regards, Jonas

    #65920 Feb 14, 2013 10:12