Modelo dinâmico MVC Razor, 'objeto' não contém definição para 'PropertyName'


106

Usando MVC 3 com motor de visualização Razor. Eu tenho esta visão:

@model dynamic
@{
    var products = (List<ListItemBaseModel>)Model.Products;
    var threshold = (int)(Model.Threshold ?? 1);
    var id = Guid.NewGuid().ToString();
}

Ele é chamado de outra visualização usando este código:

@Html.Partial("PartialViewName", new { Products = Model, Threshold = 5 })

Em ambas as visualizações, quando eu os depuro e observo o modelo, ele parece conter o objeto correto. Quando executo o código, obtenho um erro na linha "var products =" que diz:

'objeto' não contém uma definição para 'Produtos'

Alguém pode me explicar por que recebo esse erro? Mais uma vez, quando vejo o objeto Model no modo de depuração, parece que está tudo bem (tendo 2 propriedades: Produtos e Limite)


Respostas:


150

Você está passando uma instância de uma classe anônima como o modelo de exibição? Eu apenas tentei isso (modelo de visão dinâmica em CSHTML) e recebi o mesmo erro que você ao usar uma classe anônima, mas funcionou bem se eu criasse uma classe nomeada. Eu procurei, mas não vi isso documentado em nenhum lugar.

// error
return View(new { Foo = 1, Bar = "test" });

// worked
return View(new TestClass { Foo = 1, Bar = "test" });

EDITAR # 1:

De acordo com David Ebbo , você não pode passar um tipo anônimo para uma visão digitada dinamicamente porque os tipos anônimos são compilados como internal. Visto que a visualização CSHTML é compilada em um assembly separado, ela não pode acessar as propriedades do tipo anônimo.

EDITAR # 2:

David Ebbo editou sua postagem com este esclarecimento:

Nota (22/12/2011): agora que MVC 3 tem suporte direto para dinâmica, a técnica abaixo não é mais necessária. Esta postagem é de fato o que levou à integração do recurso no MVC!


1
É bom saber a edição. Eu simplesmente tive o mesmo problema e não entendia o WTF lá. Obrigada pelo esclarecimento.
Yanick Rochon

18
EDIT # 2 sugere que agora (MVC> 3) é possível fazer linha marcada com "erro"? return View(new { Foo = 1, Bar = "test" });? Porque estou usando MVC 4 e ainda estou obtendo "objeto não contém uma definição para Foo"
esportes

@sports me also ... você encontrou uma solução alternativa? (ao lado ToExpandodaquele)
Alex

2
Então, agora em 2018, usando ASP.NET Core 2.1 e visualizações Razor, acho que o erro na pergunta original ainda está me incomodando. Então eu não sei do que se trata essa conversa sobre MVC 3 consertar isso, já que ainda parece quebrado.
Andrew Arnott,

41

No .NET 4.0, os tipos anônimos podem ser facilmente convertidos em ExpandoObjects e, portanto, todos os problemas são corrigidos com a sobrecarga da própria conversão. Confira aqui


Você é bem vindo. Talvez isso gere M $ para tornar os tipos anônimos mais utilizáveis
Adaptabi

Isso se aplica a Partials? Recebi um erro informando que os Partials não podem ser despachados dinamicamente ...
John Bubriski

1
Quais parciais? você pode dar um exemplo?
Adaptabi

27

Isso não tem nada a ver com tipos anônimos com propriedades internas

É perfeitamente possível passar tipos anônimos de uma visão para uma visão parcial

Eu encontrei o mesmo problema hoje e não tinha nada (diretamente) a ver com o problema de passar tipos anônimos e suas internalpropriedades inerentes .

Assim, em relação à pergunta dos POs, a resposta de @Lucas é irrelevante - embora a solução alternativa funcione .

Na questão de OPs, um tipo anônimo está sendo passado de uma visão no assembly X para um parcial no assembly X , portanto, o problema que David Ebbo descreveu das propriedades sendo internas para tipos anônimos não tem consequência; os tipos compilados para a visão, o tipo parcial e o tipo anônimo estão todos contidos no mesmo assembly .

Então, o que está causando a falha repentina de passar um tipo anônimo de uma exibição para uma parcial?

Pelo menos na minha situação, descobri que era devido a ter outra visualização na MESMA PASTA que especifica um tipo de modelo que não pode ser resolvido . As visualizações são compiladas em tempo de execução e, portanto, faria sentido, uma vez que uma falha em tempo de execução para compilar as visualizações também significaria uma falha ao compilar os tipos dinâmicos e o parcial simplesmente receberia um object. Não é imediatamente óbvio o que está acontecendo, mas no exemplo específico de OPs (e no meu) essa é a causa mais provável do problema.

É interessante notar que se o tipo de modelo estiver correto, mas outra parte da visualização não compilar, os tipos anônimos não serão afetados da mesma maneira. Isso deve ser explicado como o Razor divide a compilação dinâmica das partes componentes da visualização.

Depois de corrigir a visão ofensiva, reconstrua toda a solução ou limpe e reconstrua o projeto antes de verificar se foi corrigido.

Para garantir que você não seja pego por isso novamente, você pode habilitar a compilação em tempo de compilação de suas visualizações do Razor adicionando isto ao seu csprojarquivo:

<PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>

2
Isso resolveu meu problema - usar "@model dynamic" inicialmente parecia a solução certa, mas na verdade estava me levando para o caminho errado.
crimbo

Limpei a solução, reconstruí-a e o erro desapareceu ... 121 votos perdidos.
maxbeaudoin

Eu atualizei minha resposta para refletir o suporte do MVC para modelos de visão dinâmica desde MVC 3.
Lucas

Habilitar a compilação de visualizações de tempos em tempos é sempre útil para uma grande base de código. Revela todos os tipos de problemas, erros de digitação, erros com T4MVC graças à digitação forte que ele introduziu etc.
Denis The Menace

Ah, certo: acabei de notar que estamos falando sobre passar de uma vista para uma parcial aqui. Não de um controlador para uma visão, que é o meu problema.
mwardm de

9

Adicione a seguinte classe em qualquer lugar em sua solução (use o namespace System, então está pronto para usar sem ter que adicionar nenhuma referência) -

    namespace System
    {
        public static class ExpandoHelper
        {
            public static ExpandoObject ToExpando(this object anonymousObject)
            {
                IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
                IDictionary<string, object> expando = new ExpandoObject();
                foreach (var item in anonymousDictionary)
                    expando.Add(item);
                return (ExpandoObject)expando;
            }

        }
    }

Ao enviar o modelo para a visualização, converta-o para Expando:

    return View(new {x=4, y=6}.ToExpando());

1
parece uma sobrecarga desnecessária para mim criar um objeto dinâmico primeiro e, em seguida, criar um ExpandoObject ... Basta criar o ExpandoObject.
Baz1nga

@ Baz1nga Você não pode fazer ... new Expando () {prop = value, ...}, o que o torna problemático. Estou usando o JObject do Json.Net para um uso semelhante.
Tracker1

3
Parece errado ter HtmlHelper lá ... public static ExpandoObject ToExpando (este objeto o) {IDictionary <string, object> expando = new ExpandoObject (); foreach (var propertyInfo em o.GetType (). GetProperties ()) {expando.Add (new KeyValuePair <string, object> (propertyInfo.Name, propertyInfo.GetValue (o, index: null))); } return (ExpandoObject) expando; }
erlando

6

Em vez de usar o dynamictipo de modelo na vista parcial.

Você pode chamar os atributos do objeto anônimo usando em @ViewData.Eval("foo")vez de @Model.foo.

Em seguida, você pode remover @Model dynamicda vista.

Eu me deparei com esse problema recentemente ao passar alguns atributos entre visualizações para a integração de comentários sociais do Facebook. Código de exemplo:

Html.RenderPartial(@"Layouts/Partials/_Comments", new {currentUrl = Model.CurrentPage.GetAbsoluteUrl(), commentCount = 5 });

Então, na minha opinião, eu tinha apenas este div:

<div class="fb-comments" data-href="@ViewData.Eval("currentUrl")" data-numposts="@ViewData.Eval("commentCount")" data-width="100%"></div>

0

Não tenho certeza se você está recebendo esse erro porque não está implementando a solução alternativa. eu tenho o mesmo erro em uma visão parcial. a solução era apenas limpar a construção e reconstruí-la. se a sintaxe estiver correta, o código deve funcionar, mas o mecanismo de barbear pode não estar atualizando as alterações de código corretamente.


0

Eu contornei esse problema usando um Dicionário.

 @Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });

-6

Para usar o dynamictipo, você precisa fazer referência ao Microsoft.CSharpassembly

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.