ASP.NET MVC - 将动态 ExpandoObject 从控制器传递到视图时出现 RuntimeBinderException

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

由于无法将多个模型传递给 ASP.NET MVC 4 中的视图,我试图将各种模型填充到动态 ExpandoObject 中,然后从视图中解包.

我的模型(不仅仅包含这个 class,但为了简洁起见,我只展示这个):

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

我的控制器: (我将不仅仅是这个 List<> 对象打包到 dynamic 对象中,但为了简洁起见...)

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;

我的看法: (这是视图中的第一件事,程序在接下来的赋值时阻塞)

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

当光标到达View层上面的赋值时,抛出如下异常:

'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)}

有谁知道我需要做什么来解决这个问题?不确定这是快速修复还是更广泛的重新设计。

您发送了列表艺术家,但试图获得一位艺术家,您应该更改此设置

string artist_Name = Model.Artist.Artist_Name;

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

改变

@model dynamic

@model ExpendoObject

我认为使用动态对象不是一个好主意,默认情况下视图是强类型的,没有模型就无法创建基于属性的模型验证...

通过参考官方文档和其他资源,您可以使用扩展方法将您的对象转换为 ExpandoObject,您的函数应该可以工作:

扩展方法:

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

在您的控制器方法的 return 中尝试添加:

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

解释:

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.

有关详细信息,请阅读此答案:

Dynamic Anonymous type in Razor causes RuntimeBinderException

和这篇文章:

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