Eugene Tsimberg
Eugene Tsimberg

Reputation: 1

MVC DisplayFor templates seem to quit working if the same model is reused within the template

I have a really strange situation. I have a single Model, and two templates that are both strong-typed on the type of this model. The templates are nested, or in other words, I use DisplayFor on the second Template from within the first template. If I use the model associated with the first template, in the DisplayFor call for the second template, the second template does not render. If I use another instance of the same model type, everything works fine. It seems like there is some sort of cycle checking on the models associated with nested templates.

Model:

public class MyModel
{
    public string Value { get; set; }
    public MyModel Copy
    {
        get { return (MyModel) this.MemberwiseClone(); }
    }

    public MyModel MySelf
    {
        get { return this; }
    }
}

DisplayTemplate1:

@model TestNestedTemplateSameReference.Models.MyModel

<div>Model1</div>
<div>@Model.Value</div>
<div>@Html.DisplayFor(x=>x, "ModelTemplate2")</div>

DisplayTemplate2:

@model TestNestedTemplateSameReference.Models.MyModel

<div>Model2</div>
<div>@Model.Value</div>

Interestingly if instead of calling

@Html.DisplayFor(x=>x, "ModelTemplate2")

I call it with the Copy property

<div>@Html.DisplayFor(x=>x.Copy, "ModelTemplate2")</div>

everything works fine as the actual instance of the MyModel class is different.

Does anyone know why this is done. Is there a viable workaround. It seems like this is a perfectly legitimate usage which shouldnot cause a stack overflow, or any similar issues. I could see how this could be used to protect against cycles for DisplayFor call without template name, but if I specify the template name seems like it should work fine.

It seems like it would be dangerous to bind the same model to multiple EditFor templates, but DisplayFor seems safe.

I can of course create a separate model for nesting level, but that is creating redundand class.

Any help is appreciated.

Upvotes: 0

Views: 463

Answers (1)

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93424

If what you were trying to do worked, it would result in a stack overflow as object after object was created via the Copy method. Each object would in turn create a new copy of itself, and you would quickly either run out of memory or run out of stack.

The default template executes this method before showing a property

bool ShouldShow(ModelMetadata metadata) {
    return metadata.ShowForEdit
        && metadata.ModelType != typeof(System.Data.EntityState)
        && !metadata.IsComplexType
        && !ViewData.TemplateInfo.Visited(metadata);
}

My guess is that it's tripping either IsComplexType or TemplateInfo.Visited.

There's more info on this here:

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html

Upvotes: 1

Related Questions