Search code examples
asp.net-mvc-4partial-viewspermalinkspushstate

Gracefully handling permalinks when using pushstate for partial view pagination


I'm looking for a clean way to handle permalinks when my application uses pushstate to load ASP.NET MVC partial views for pagination

If my controller returns a partial view (currently) then the permalink will display the partial view alone without the rest of the site defined by _Layout.cshtml.

If my controller return a regular view, the permalink works but loading the entire page into the container provided only for part of the page creates a type of Droste Effect.

The only solution I've found is to redirect the 404 to the homepage and navigate to correct page using the relevant portion of the url.

However, this prevents me from using my custom error page (which just happens to be an awesome error page).


Solution

  • Ok I figured out how to make this work with a double-controller setup.

    NavigationController handles ajax calls and returns partial views (note there is no "Index")

    public class NavigationController : Controller
    {
        public PartialViewResult Home()
        {
            return PartialView("Home", null);
        }
    
        public PartialViewResult About()
        {
            return PartialView("About", null);
        }
    
        ...
     }
    

    Separate PermalinkController handles permalinks by returning entire regular Views (note this has an "Index" but no "Home":

    public class PermalinkController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult About()
        {
            return View();
        }
    
        ...
    }
    

    Routes:

           routes.MapRoute(
                "PermalinkRouter",
                "{action}",
                new { controller = "Permalink", action = "Index" },
                new { }
            );
    
            routes.MapRoute(
                "NavigationRouter",
                "Navigation/{action}/{id}",
                new { controller = "Navigation", action = "Home", id = UrlParameter.Optional },
                new { }
            );
    

    Views:

    ~/Views/Shared/_Layout.cshtml:

    ...
    <header></header>
    <div id="pageViewContainer">
        @RenderBody()
    </div>        
    <footer></footer>
    ...
    

    ~/Views/Navigation/Home.cshtml PartialView:

    <div> Home Content </div>
    

    ~/Views/Permalink/Index.cshtml View:

    @{
        ViewBag.Title = "Index";
        Layout = "~/Views/Shared/_Layout.cshtml";
     }
    
     @Html.Partial("~/Views/Navigation/Home.cshtml", null)