简体   繁体   中英

ASP.NET MVC - RuntimeBinderException when passing dynamic ExpandoObject from Controller to View

Since it is not possible to pass multiple models to a view in ASP.NET MVC 4, I am trying to stuff the various models into a dynamic ExpandoObject and then unpacking it from within the view.

My Model (consists of more than just this class, but for brevity I'll just show this):

public class Modular_ArtistModel
{
    public string Artist_Name { get; set; }
}

My Controller: (I am packing more than just this List<> object into the dynamic object, but for brevity's sake...)

dynamic ArtistModel = new ExpandoObject();

        var Modular_ArtistModel = LoadSP_Modular_ArtistModel("sp_Mod_Artist_Artist", i);
        List<Modular_ArtistModel> mod_ArtistModel = new List<Modular_ArtistModel>();
        foreach (var row in Modular_ArtistModel)
        {
            mod_ArtistModel.Add(new Modular_ArtistModel
            {
                Artist_Name = row.Artist_Name
            });
        }
        ArtistModel.Artist = mod_ArtistModel;

My View: (This is the first thing in the view and the program chokes on the following assignment)

@model dynamic
@{
string artist_Name = Model.Artist.Artist_Name;
}

When the cursor reaches the above assignment in the View layer, it throws the following exception:

'Model.Artist.Artist_Name' threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146233088
HelpLink: null
InnerException: null
Message: "'System.Collections.Generic.List<....Models.Modular_ArtistModel>' does not contain a definition for 'Artist_Name'"
Source: "Anonymously Hosted DynamicMethods Assembly"
StackTrace: "   at CallSite.Target(Closure , CallSite , Object )\r\n   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)"
TargetSite: {System.Object CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object)}

Does anyone know what I need to do to fix this? Not sure if it's a quick fix or a more extensive redesign.

You send list artist but try to get one artist you should change this

string artist_Name = Model.Artist.Artist_Name;

To

string artist_Name= Model.Artist.FirstOrDefault().Artist_Name;

Or

Change

@model dynamic

To

@model ExpendoObject

I think that using dynamic object is not a good idea,by default views are strongly typed and without Model there is no way to create attribute based model validation ...

By referring to the official documentation and others resources you can use extension method to convert your object into an ExpandoObject and your function should be works :

Extension method :

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;
}

In the return of your controller method try to add:

return ( "yourView", ArtistModel.ToExpando() ); 

Explanation:

The reason for this is that the anonymous type being passed in the controller in internal, so it can only be accessed from within the assembly in which it's declared. Since views get compiled separately, the dynamic binder complains that it can't go over that assembly boundary.

But if you think about it, this restriction from the dynamic binder is actually quite artificial, because if you use private reflection, nothing is stopping you from accessing those internal members (yes, it even work in Medium trust). So the default dynamic binder is going out of its way to enforce C# compilation rules (where you can't access internal members), instead of letting you do what the CLR runtime allows.

For more details please read this answer:

Dynamic Anonymous type in Razor causes RuntimeBinderException

and this article:

https://blogs.msdn.microsoft.com/davidebb/2009/12/18/passing-anonymous-objects-to-mvc-views-and-accessing-them-using-dynamic/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM