views:

1348

answers:

3

I'm currently creating a CMS system and found that the following doesn't work.

I do have a work around that isn't exactly ideal and feels dirty. I'm cool with it for now and not really that interested in a different approach (but don't let that stop you answering). What I am after is some kind of explaination on why it doesn't work - is it a bug in ASP.NET MVC?

It's hard to explain so I'll let my code (minus alot of fluff) do the talking... hope it makes sense!

EDIT: It seems that the compiler totally ignores the second masterpage's 'inherits' attribute - see at the bottom of the question.

ContentViewData.cs - notice it inherits from BaseViewData

public class ContentViewData : BaseViewData
{
    public MyCMS.Data.Models.Content ContentItem { get; set; }
}

Site.Master - Notice the strongly typed viewdata of type BaseViewData

<%@ Master
    Language="C#"
    Inherits="System.Web.Mvc.ViewMasterPage<MyCMS.WebSite.ViewData.BaseViewData>" %>

Content.Master - Notice the strongly typed viewdata of type ContentViewData and the fact that it's a child masterpage of Site.Master

<%@ Master
    Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewMasterPage<MyCMS.WebSite.ViewData.ContentViewData>" %>

...blah blah blah...

<% Html.RenderPartial("ContentItemImage", Model.ContentItem); %>

ContentItemImage.ascx

<%@ Control
    Language="C#"
    Inherits="System.Web.Mvc.ViewUserControl<MyCMS.Data.Models.Content>" %>

<% if (Model.HasPrimaryPhoto)
   { %>
    <img src="/content/photos/<%= Model.GetPrimaryPhoto.ThumbFileName %>"
         title="<%= Model.GetPrimaryPhoto.Caption %>" />
<% } %>

Now inside the Content.Master if I try and render the ContentItemImage partial and refer to a property on the ContentViewData object (specifically the 'ContentItem' property) like I have - repeated below.

<% Html.RenderPartial("ContentItemImage", Model.ContentItem); %>

If falls over on that line with the following error

Compilation Error

CS1061: 'object' does not contain a definition for 'ContentItem' and no extension method 'ContentItem' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

BUT if I change things up like so, it all works fine and dandy.

Content.Master - Notice I'm passing into RenderPartial() the whole Model (ContentViewData object) rather than trying to refer to a property on the ContentViewData object

<%@ Master
    Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewMasterPage<MyCMS.WebSite.ViewData.ContentViewData>" %>

...blah blah blah...

<% Html.RenderPartial("ContentItemImage", Model); %>

ContentItemImage.ascx - notice the changed strongly typed viewdata from MyCMS.Data.Models.Content to the ContentViewData class.

<%@ Control
    Language="C#"
    Inherits="System.Web.Mvc.ViewUserControl<MyCMS.WebSite.ViewData.ContentViewData>" %>

<% if (Model.ContentItem.HasPrimaryPhoto)
   { %>
    <img src="/content/photos/<%= Model.ContentItem.GetPrimaryPhoto.ThumbFileName %>"
         title="<%= Model.ContentItem.GetPrimaryPhoto.Caption %>" />
<% } %>

So yeah, that works but it aint go not alibi.

Thanks in advance, Charles.

EDIT: Interestingly it seems that the compiler totally ignores the second master page's 'inherits' attribute.

Eg. I can do this and it still compiles without a complaint...

<%@ Master
    Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewMasterPage<ThisDoesntExist.AtAll>" %>
+1  A: 

Interesting...A resonable guess would be that your ContentViewData object is being upcast to BaseViewData due to some interaction with your nested master page (if that is indeed the case, someone else will need to weigh in as to why).

You could verify trying this:

<% Html.RenderPartial("ContentItemImage", ((MyCMS.WebSite.ViewData.ContentViewData)Model).ContentItem); %>

The reason your workaround "works" is because your partial view is typed for ContentViewData, so when you pass in Model it is downcast to that type.

Yep, casting like that works fine. Check out my edit, it seems that the compiler totally ignores the nested masterpage's inherits attribute.
Charlino
A: 

As you can see from my edit, it seems that the compiler totally ignores the nested master page's 'inherits' attribute.

This leads me to believe that a nested masterpage in ASP.NET MVC will always inherit from it's parent masterpage and as I've witnessed, totally ignore the inherits attribute.

EDIT: There must be some magic going on here... If I remove the 'inherits' attribute it won't compile because it doesn't know about the HtmlHelper class. But if I have the 'inherits' attribute in there with garbage inside it, it does compile.

Doesn't work

<%@ Master
    Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master" %>

Does work

<%@ Master
    Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="Sysasfdaasdtem.Web.Mvsdfc.ViewMasterPage<ThisDoesntExist.AtAll>" %>

Very odd indeed.

Charlino
I have found that you can't have a strongly typed master page at all. It doesn't matter if it is nested or not.
Alex
I've just upgraded to mvc 2 preview 2 and it fixes this bug :)
Alex
A: 

Just try to do the next thing:

<%@ Master
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewMasterPage<MyCMS.WebSite.ViewData.ContentViewData>" %>

...blah blah blah...

<%= string.Empty %>

...blah blah blah...

<% Html.RenderPartial("ContentItemImage", Model.ContentItem); %>

Don't ask anything, just try to put <%= string.Empty %> in your master page's code and then use your strongly typed Model property.

s8k
This is important for me if it will help you. Looking forward to your reply.
s8k