ASP.NET MVC - RuntimeBinderException при передаче динамического ExpandoObject из контроллера в представление

Поскольку невозможно передать несколько моделей в представление в ASP.NET MVC 4, я пытаюсь объединить различные модели в динамический ExpandoObject а затем распаковать его изнутри зрения.

Моя модель (состоит не только из этого класса, но для краткости я просто покажу это):

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;

My View:(Это первое, что есть в представлении, и программа задыхается от следующего назначения)

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

Кто-нибудь знает, что мне нужно сделать, чтобы это исправить? Не уверен, что это быстрое исправление или более обширный редизайн.

2 ответа

Решение

Я думаю, что использование динамического объекта не является хорошей идеей, по умолчанию представления строго типизированы, и без модели нет способа создать аттестацию на основе модели...

Ссылаясь на официальную документацию и другие ресурсы, вы можете использовать метод расширения для преобразования вашего объекта в 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 ( "yourView", ArtistModel.ToExpando() ); 

Объяснение:

Причина этого заключается в том, что анонимный тип передается во внутренний контроллер, поэтому к нему можно получить доступ только из сборки, в которой он объявлен. Поскольку представления компилируются отдельно, динамическое связующее устройство жалуется, что оно не может пересечь эту границу сборки.

Но если подумать, это ограничение динамического связывания на самом деле довольно искусственное, потому что, если вы используете личное отражение, ничто не мешает вам получить доступ к этим внутренним членам (да, это работает даже в Medium trust). Таким образом, динамическое связующее устройство по умолчанию делает все возможное для обеспечения соблюдения правил компиляции C# (когда вы не можете получить доступ к внутренним членам), вместо того, чтобы позволять вам делать то, что позволяет среда выполнения CLR.

Для более подробной информации, пожалуйста, прочитайте этот ответ:

Динамический анонимный тип в Razor вызывает исключение RuntimeBinderException

и эта статья:

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

1

Вы отправляете список исполнителей, но пытаетесь найти одного исполнителя, вы должны изменить это

string artist_Name = Model.Artist.Artist_Name;

к

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

Или же

+ Изменить

@model dynamic

к

@model ExpendoObject
1
Другие вопросы по тегам