none
Como passar objeto dinamica para view RRS feed

  • Pergunta

  • Olá estou estudando o MVC, fazendo um projetinho de aprendizado, mas me deparai com um problema :

    Fiz um select para listar todos os registros pegando informações de tabelas diferentes, não estou conseguindo fazer o foreach para listar as informações. Verifiquei que na viewbag está com o objeto, mas não consigo acessá-lo, tipo "item.name"...

    Alguém pode me ajudar?

    Tem como pegar o objeto passado no retorno da viewbag?

    Até o momento só aprendiu a tipa o view com classes criada não dinamicas @Model projeto.Model.classe e tal.

    Segue código:

    / /Código do controlle
    public ActionResult Lista()
            {
                var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }).ToList();
                ViewBag.charnames = charnames.ToList();
                ViewBag.fullname = charnames.Select(x => x.name + " " + x.lastname).ToList();
                ViewBag.system = charnames.Select(x => x.breedidentication).ToList();
                ViewBag.breed = charnames.Select(x => x.systemidentication).ToList();
    
                ViewData["charname"] = charnames.ToList();
                ViewData["name"] = charnames.Select(x => x.name).ToList();
    
                return View(charnames);
            }

    @{
        ViewBag.Title = "Lista";
        //charnames itemcharnames = ViewBag.charnames;
    }
    
    <h2>Viewbag.charname</h2>
    
    @foreach (var item in Model)
    {
        @item.
    }


    Guisal

    sábado, 12 de março de 2016 22:54

Respostas

  • Boa noite.

    Seguindo a linha de raciocínio do Cesar, tente esse método de extensão (as referências necessárias estão já nos usings):

    using System.Collections.Generic;
    using System.Dynamic;
    using System.Web.Mvc;    
    
    public static class ExpandoExt
        {
            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;
            }
        }

    Na tua Controller ficaria algo do tipo:

    var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }).Select(x => x.ToExpando());
    
    return View(charnames);

    E para finalizar, na tua View tu podes tentar o seguinte (mais para verificar se funcionou e tudo o mais):

    @model IEnumerable<dynamic>
    @{
        ViewBag.Title = "Index";
    }
    
    @foreach (dynamic item in Model)
    {
        @item.name
        <br/>
        @item.lastname
        <br/>
    }

    Att., Rafael Simor

    • Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    quarta-feira, 16 de março de 2016 02:04
  • Boa noite.

    Pelo erro, tente fazer o seguinte:

    var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }).AsEnumerable().Select(x => x.ToExpando());
    Que acredito que tu forçaria a fazer o ToExpando com LINQ to Objects.

    Att., Rafael Simor


    • Editado SimorC quinta-feira, 17 de março de 2016 02:57 ToEnumerable > AsEnumerable
    • Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    quarta-feira, 16 de março de 2016 22:06

Todas as Respostas

  • Você está passando sua lista via ViewBag, então basta pegar por ela, como no exemplo abaixo:

    @foreach (var item in ViewBag.charnames)
    {
        @item.name
    }


    Mas como você quer utilizar a Model, você precisa tipar ela e como a lista não é tipada você utiliza:

    @model dynamic


    O problema aqui é que quando utiliza dynamic você fica sem intellisense, ou seja, seu @item. não presentará sugestões como (@item.name, @item.lastaname...)

    segunda-feira, 14 de março de 2016 02:15
  • Oi, obrigado pela atenção. 

    Então já havia tentado dessa forma, nem copila... dá o erro abaixo:

    se colocar:

    @foreach (var item in ViewBag.charnames)
    {
        @item
    }

    ele mostra tudo, o nome da propriedade e seu valor

    name

    jão

    maria 

    lastname

    Silva

    Silvestre

    Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled by user code
      HResult=-2146233088
      Message='object' does not contain a definition for 'name'
      Source=Anonymously Hosted DynamicMethods Assembly
      StackTrace:
           at CallSite.Target(Closure , CallSite , Object )
           at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
           at ASP._Page_Views_RandomName_Lista_cshtml.Execute() in G:\C#\Estudo\RandomCharNames\RandomCharNames\Views\RandomName\Lista.cshtml:line 11
           at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
           at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
           at System.Web.WebPages.StartPage.RunPage()
           at System.Web.WebPages.StartPage.ExecutePageHierarchy()
           at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
           at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
           at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
           at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
      InnerException: 


    Guisal

    terça-feira, 15 de março de 2016 02:31
  • Você testou tipando como dynamic (@model dynamic)?

    @model dynamic
    ...
    @foreach (var item in Model)
    {
        @item.name
    }

    O que você poderia utilizar neste caso é um ExpandoObject, como neste exemplo aqui:
    http://stackoverflow.com/questions/5120317/dynamic-anonymous-type-in-razor-causes-runtimebinderexception


    Seu código ficaria assim:

    public static ExpandoObject ToExpando(this object anonymousObject)
    {
        IDictionary<string, object> anonymousDictionary =  new RouteValueDictionary(anonymousObject);
        IDictionary<string, object> expando = new ExpandoObject();
        foreach (var item in anonymousDictionary)
            expando.Add(item);
        return (ExpandoObject)expando;
    }
    public ActionResult Lista()
            {
                var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }.ToExpando());
                ViewBag.charnames = charnames;

    Depois:

    @foreach (var item in ViewBag.charnames)
    {
        @item.name
    }


    terça-feira, 15 de março de 2016 03:27
  • Não consegui fazer funcionar, rs.

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

    Não encontrei a referencia para "RouteValueDictionary" qual é?


    fiz dessa forma e funcionou meia boca:

    ViewBag.fullname = charnames.Select(x => x.name + ' ' + x.lastname);

    Mas gostaria de manipular o objeto na view.

    Tem alguma outra forma de passa as informações? 



    Guisal


    • Editado GuiSal quarta-feira, 16 de março de 2016 01:09
    quarta-feira, 16 de março de 2016 00:52
  • A ideia do RouteValueDictionary é facilitar a conversão do objeto em Dictionary.

    A View em tese só exibe a informação, essa é a ideia no MVC e Views fortemente tipadas facilitam a manipulação de dados.

    quarta-feira, 16 de março de 2016 01:46
  • Boa noite.

    Seguindo a linha de raciocínio do Cesar, tente esse método de extensão (as referências necessárias estão já nos usings):

    using System.Collections.Generic;
    using System.Dynamic;
    using System.Web.Mvc;    
    
    public static class ExpandoExt
        {
            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;
            }
        }

    Na tua Controller ficaria algo do tipo:

    var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }).Select(x => x.ToExpando());
    
    return View(charnames);

    E para finalizar, na tua View tu podes tentar o seguinte (mais para verificar se funcionou e tudo o mais):

    @model IEnumerable<dynamic>
    @{
        ViewBag.Title = "Index";
    }
    
    @foreach (dynamic item in Model)
    {
        @item.name
        <br/>
        @item.lastname
        <br/>
    }

    Att., Rafael Simor

    • Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    quarta-feira, 16 de março de 2016 02:04
  • Rafael, obrigado pelo auxilio, copiando o seu código funcionou o Expando, mas ainda não está dando certo...

    Não sei o que estou fazendo de errado. 

    copiando o seu código está dando exception

    System.NotSupportedException was unhandled by user code
      HResult=-2146233067
      Message=LINQ to Entities does not recognize the method 'System.Dynamic.ExpandoObject ToExpando(System.Object)' method, and this method cannot be translated into a store expression.
      Source=EntityFramework
      StackTrace:
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
           at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()
           at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
           at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
           at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
           at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
           at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
           at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
           at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
           at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
           at ASP._Page_Views_RandomName_Lista_cshtml.Execute() in G:\C#\Estudo\RandomCharNames\RandomCharNames\Views\RandomName\Lista.cshtml:line 9
           at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
           at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
           at System.Web.WebPages.StartPage.RunPage()
           at System.Web.WebPages.StartPage.ExecutePageHierarchy()
           at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
           at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
           at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
           at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
           at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
      InnerException: 

    colocando o ".ToExpando()" fora do select :

                .Select(x => new { name = x.name }).ToExpando();
                ou return View(charnames.ToExpando());

    


    Guisal

    • Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    • Não Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    quarta-feira, 16 de março de 2016 22:02
  • Boa noite.

    Pelo erro, tente fazer o seguinte:

    var charnames = db.CharName.Select(x => new
                {
                    name = x.Name,
                    lastname = x.LastName,
                    breedidentication = x.Breeds.Identification,
                    systemidentication = x.Systems.Identification
                }).AsEnumerable().Select(x => x.ToExpando());
    Que acredito que tu forçaria a fazer o ToExpando com LINQ to Objects.

    Att., Rafael Simor


    • Editado SimorC quinta-feira, 17 de março de 2016 02:57 ToEnumerable > AsEnumerable
    • Marcado como Resposta GuiSal sábado, 19 de março de 2016 19:51
    quarta-feira, 16 de março de 2016 22:06
  • Quando tento colocar o toEnumerable() não reconhece...

    Não tem uma forma mais fácil de passar os valores?

    Essa não é uma forma gabiarra? se tiver uma forma mais correta por favor me fale...


    Guisal

    quinta-feira, 17 de março de 2016 02:50
  • Quando tento colocar o toEnumerable() não reconhece...

    Não tem uma forma mais fácil de passar os valores?

    Essa não é uma forma gabiarra? se tiver uma forma mais correta por favor me fale...


    Guisal

    Tentei colocar 

    IEnumerable<dynamic> charnames  

    Em minhas referencias não encontre  "System.Collections.Generic.IEnumerable" onde posso baixar ou encontrar?


    Guisal

    quinta-feira, 17 de março de 2016 02:55
  • Guilherme, erro meu.

    Deveria ser "AsEnumerable()" (Já alterei o post para futuras referências ;P)

    A forma mais "correta" seria tratar esta chamada do banco em uma camada separada, retornar um IEnumerable<>/IQueryable<> desta camada (preferencialmente passar por outra(s) camada(s)) e depois utilizar o ToExpando, mas não tenho certeza que seria uma opção viável alterar toda a estrutura do projeto.


    Att., Rafael Simor

    quinta-feira, 17 de março de 2016 02:59
  • Agora deu certo, vlw ae!!!

    Mas da forma que estava fazendo .ToArray() ele é um "IEnumerable", certo?! se passar para view da o problema que estava ocorrendo sem o ToExpando.

    Existe outra forma de fazer? 

    Não conseguiria passar um objeto sem o toExpando? não gosto dos "Dictionary" rs.

    Como passaria IQueryable para view, tipo 

    Faço a query sem executar ela (sem toList, array e etc..) e passa o objeto para view ou viewbag? 

    pq não deu muito certo assim.. rs.


    Guisal

    sábado, 19 de março de 2016 19:51