views:

103

answers:

2

I've got a Site.Master file I've created to be my template for the majority of the site, with a navigation. This navigation is dynamically created, based on a recursive Entity (called Page) - Pages with a parentID of 0 are top level, and naturally each child carries it's parent's Id in that field.

I've created a quick little HTML Helper that accepts the ID of an Page and generates the nav by doing a foreach on the children that have a parentId matching the passed Id. On the majority of the site, I want the Site.Master to use a parentId of 0, but if I'm on a strongly typed View displaying a Page, I naturally want to use the Id of the page.

Is there a way to do such conditional logic in a Site.Master (and, does that violate MVC rules)? "If I'm on a strongly typed Page of /Page/{Id}, use the Id render nav, else use 0"

+1  A: 

It sounds like your PageID is only useful in the Pages Controller.

Consider passing the PageID via the ViewData into your View. The Master Page can simply check whether the ViewData exists, and optionally call your Html helper method.

Pages Controller:

    ViewData["PageID"] = somePageID; //zero or non-zero.

Master: when any controller infact passes a value in ViewData for PageID, the Html snippet will be written. When it's not passed, it's an inexpensive check for null.

<% if (ViewData["PageID"] != null)
{
   Response.Write(Html.RenderNav(ViewData["PageID"]));
}
%>

This style, to me, makes the most sense. The PagesController passes a simple value into the ViewData.

Contrast this with the Master Page trying determine, on every request,: what's the URL is, who's the Controller, OK, now go get the PageID, is it numeric, ok, now write the HTML. All that logic doesn't belong in the View. As the convention goes: keep Views dumb.

Prefer to keep this out of your strongly typed ViewModels, but rather use in ViewData. This way, it's a simple check for existance in the Master, which is NOT strongly typed.

I'll suggest that the ViewData strategy is easier to understand and maintain.

It sounds that you're wanting to write out this Navigation in the Master. Perhaps consider moving it to a Content Area, where the View has the fine-grain control of what appears?

Pages View:

<asp:Content ID="nav" ContentPlaceHolderID="PagesNavContent" runat="server">
    <%= Html.RenderNav(ViewData["PageID"])%>
</asp:Content>
p.campbell
I should say I'm using strongly typed pages - every View has a ViewModel I'm creating. However, I'd really rather not add a property for the pageId to EVERY ViewModel. I mean, I could just have every single View for other systems (News, events, calendar, about our company, etc etc) have a pageId = 0 in their ViewModel, but I'm hoping I can just detect "Are we in the Pages Controller? Use the pageID. Otherwise, use 0"
Mortanis
+1  A: 

Figured it out:

        int navPageId = 0;
        if (ViewContext.RouteData.Values["controller"] == "Pages" && ViewContext.RouteData.Values["Id"] != null)
        {
            navPageId = Convert.ToInt32(ViewContext.RouteData.Values["Id"]);
        }
        Html.RenderNav(navPageId);
Mortanis