Las plantillas MVC DisplayFor parecen dejar de funcionar si se reutiliza el mismo modelo dentro de la plantilla

Tengo una situación realmente extraña. Tengo un solo modelo y dos plantillas que tienen un tipo fuerte en el tipo de este modelo. Las plantillas están anidadas, o en otras palabras, uso DisplayFor en la segunda plantilla desde dentro de la primera plantilla. Si uso el modelo asociado con la primera plantilla, en la llamada DisplayFor para la segunda plantilla, la segunda plantilla no se procesa. Si uso otra instancia del mismo tipo de modelo, todo funciona bien. Parece que hay algún tipo de verificación de ciclo en los modelos asociados con plantillas anidadas.

Modelo:

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

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

PantallaTemplate1:

@model TestNestedTemplateSameReference.Models.MyModel

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

PantallaTemplate2:

@model TestNestedTemplateSameReference.Models.MyModel

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

Curiosamente si en lugar de llamar

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

Lo llamo con la propiedad Copiar

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

todo funciona bien ya que la instancia real de la clase MyModel es diferente.

¿Alguien sabe por qué se hace esto? ¿Hay una solución viable? Parece que este es un uso perfectamente legítimo que no debería causar un desbordamiento de pila o problemas similares. Pude ver cómo esto podría usarse para proteger contra los ciclos de llamada DisplayFor sin el nombre de la plantilla, pero si especifico el nombre de la plantilla, parece que debería funcionar bien.

Parece que sería peligroso vincular el mismo modelo a varias plantillas de EditFor, pero DisplayFor parece seguro.

Por supuesto, puedo crear un modelo separado para el nivel de anidamiento, pero eso es crear una clase redundante.

Cualquier ayuda se agradece.

preguntado el 22 de mayo de 12 a las 14:05

1 Respuestas

Si lo que intentaba hacer funcionaba, daría como resultado un desbordamiento de pila a medida que se creaba un objeto tras otro a través del método Copiar. Cada objeto, a su vez, crearía una nueva copia de sí mismo, y rápidamente se quedaría sin memoria o sin pila.

La plantilla predeterminada ejecuta este método antes de mostrar una propiedad

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

Mi conjetura es que está tropezando con IsComplexType o TemplateInfo.Visited.

Hay más información sobre esto aquí:

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

contestado el 22 de mayo de 12 a las 19:05

¿Porqué haría eso? No tengo un bucle de anidamiento infinito. El anidamiento de plantillas se detiene después de dos. De hecho, si este comportamiento se debe a las protecciones contra el anidamiento infinito, parece que la prueba debería estar en el nombre de la plantilla o en la instancia de la plantilla en lugar del modelo. De hecho, usar la propiedad .Copy funciona bien. - eugenio tsimberg

Mystere Man, ¿sabes si el comportamiento ShouldShow se puede sobrescribir o si hay puntos de extensión que podría usar para cambiar el comportamiento? - eugenio tsimberg

@EugeneTsimberg: sí, puede anularlo con una nueva plantilla de objeto. Si descarga la fuente de MVC3 Futures, incluye las plantillas predeterminadas utilizadas internamente. Si coloca Ojbect.ascx en ~/Views/Shared/EditorTemplates y luego lo modifica, lo usará en su lugar. - Erik Funkenbusch

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.