2013-11-12 5 views
4

Я столкнулся с необычной аномалией, изучая/возившись с asp.net.RuntimeBinderException при доступе к динамическому анонимному типу в представлении

Я пытаюсь показать частичное представление, как это:

@Html.Partial("_PartialView", new { Action = "Foo" }) 

Когда я пытаюсь получить доступ к действию с

// Throws Microsoft.Csharp.RuntimeBinder.RuntimeBinderException 
string throwsException = Model.Action; 

в RuntimeBinderExceptionis с сообщением

«объект» не содержит определения для «действия»

бросается.
Самое странное в том, что эта линия работает отлично:

// This line works fine 
string works = ((Type)Model.GetType()).GetProperty("Action").GetValue(Model); 

Такое поведение озадачивает меня совсем немного, и я предпочел бы не использовать этот обходной путь. Кроме того, я не думаю, что проблема anonymous types being internal, так как шаблон MVC для ASP.NET проекта в VS2013 делает это успешно:

enter image description here

Так что здесь произошло?

+0

Это случилось со мной; он работал - и тогда он просто остановился, без уважительной причины. Я не могу понять, почему. Как вы упомянули в другом комментарии: слабо типизированные представления с анонимными типами * do * работают в других местах, например, в шаблонах Visual Studio. Вопрос в том, что заставляет их внезапно перестать работать здесь. – joshcomley

ответ

3

А что здесь произошло?

Ваш неполный вид слабо типизирован. У вас нет определения @model. Таким образом, по умолчанию это object, который, очевидно, не имеет свойства Action.

Правильный способ решения этой проблемы заключается в определении вида модели:

public class MyViewModel 
{ 
    public string Action { get; set; } 
} 

, что ваш частичный вид будет сильно типизированных к:

@model MyViewModel 
@{ 
    string throwsException = Model.Action; 
} 

и который будет принят в главном окне :

@Html.Partial("_PartialView", new MyViewModel { Action = "Foo" }) 

Другая возможность (которая лично мне не нравится, поскольку она зависит от времени выполнения связывание) заключается в использовании динамической модели в частичном виде:

@model dynamic 
@{ 
    string throwsException = Model.Action; 
} 

и тогда вы будете иметь возможность пройти анонимный объект при вызове его:

@Html.Partial("_PartialView", new { Action = "Foo" }) 
+1

Спасибо за ваш ответ. Создание модели представления решает эту проблему (динамическая модель этого не сделала, модель уже динамична). Я приму этот ответ через несколько дней, если до сих пор он остается лучшим/единственным. Но меня все еще беспокоит: почему работает шаблон MVC для ASP.NET Project в VS2013?Его частичный вид также слабо типизирован. На самом деле, мое частичное представление - это просто исправленная версия. Если вы можете добавить объяснение в свой ответ, я сразу приму его. – Kabbalah

+0

При использовании виртуальной машины VM избегает/решает проблему, она не объясняет ошибку. Случай по умолчанию обычно принимает динамические/анонимные объекты (а не объект). Анонимные типы обычно работают в частичных представлениях, но при некоторых (пока неизвестных обстоятельствах) он просто перестает работать. Я просто попал в эту же проблему и должен был изменить ее, чтобы использовать сильно типизированные объекты. Как говорит Каббала, '@model dynamic' терпит неудачу так же, как оригинал (поскольку он уже ожидает динамику). –

+0

Вы также можете использовать отражение, но это было бы неправильно. Вы можете добавить метод расширения объекта Object с T GetData (эта объектная модель, клавиша String) ... return model.GetType(). GetProperty (key) .GetValue (model) as T. Как статический метод утилиты, это будет лучше. Давайте будем честными, удар производительности не так уж плох. Helper.Data (Модель, ключ). – jwize

0

Вот некоторые варианты использования отражения. Производительность должна быть незначительной в большинстве сценариев.

Utility Класс

public static class ModelHelper 
{ 
    public static T Data<T>(String key) 
    { 
     var html = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html; 
     var model = html.ViewData.Model; 
     return (T)model.GetType().GetProperty(key).GetValue(model) ; 
    } 
} 

вид.cshtml

@(Html.Partial("partial",new { Id="InstructorId"})) 

paritial.cshtml файл

@model dynamic 
@{ 
    var id = ModelHelper.Data<String>("Id"); 
} 

с более компактной parital вызова в view.cshtml

@{ 
    var instructorId = "InstructorId"; 
    var windowTitle = "Window Title"; 
    var editorPageUrl = "~/View/Editors/Instructors.chstml"; 
} 

@(Html.Partial("partial",new { instructorId, windowTitle, editorPageUrl })) 

с переменными скорректированной получить выведенные имена в Файл paritial.cshtml

@model dynamic 
@{ 
    var id = ModelHelper.Data<String>("instructorId"); 
    var id = ModelHelper.Data<String>("windowTitle"); 
    var id = ModelHelper.Data<String>("editorPageUrl"); 
} 

Это не трудно создать простой класс вид-модель, но я не люблю классы, которые будут только когда-либо использовать один раз для передачи данных, так что это работает для меня.

Можно также расширить вид по умолчанию базы на

namespace SafetyPlus.Shell.Code 
{ 
    public abstract class ExtendedPageBaseClass<TModel> : WebViewPage<TModel> where TModel : class 
    { 
     public T Data<T>(String key) 
     { 
      return (T)Model.GetType().GetProperty(key).GetValue(Model); 
     } 

     public Object Data(String key) 
     { 
      return Data<Object>(key); 
     } 
    } 
} 

Зарегистрируйте базовый класс в /Views/web.config

<pages pageBaseType="SafetyPlus.Shell.Code.ExtendedPageBaseClass"> 
    ... 
</pages> 

Получить данные в вашей частичное представление например

@{ 
    var id = Data("Id"); 
    var idTyped = Data<String>("Id"); 
} 

Или использование метода расширения, который я предложил против.

namespace NotYourDefaultNamespace 
{ 
    public static class ModelExtensions 
    { 
     public static T Data<T>(this Object model, String key) 
     { 
      return (T)model.GetType().GetProperty(key).GetValue(model) ; 
     } 
    } 
} 

Эта опция действительно не купить вам что-нибудь, так как мы найти модель из предыдущего метода полезности. Звонок станет.

@{ 
    var id = Model.Data("Id"); 
} 
5

Ответ на этот вопрос можно найти здесь: http://www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic

вытягивать из превосходной блоге:

Anonymous Types are Internal

Причина вызов Model.Action не удается, что информация о типе Model не доступен во время выполнения. Причина, по которой она недоступна, заключается в том, что анонимные типы не являются общедоступными. Когда метод возвращает экземпляр этого анонимного типа, он возвращает System.Object, который ссылается на экземпляр анонимного типа - тип, информация которого недоступна основной программе. Динамическое время выполнения пытается найти свойство, называемое Action, но не может устранить его из информации о типе, которую он имеет. Таким образом, он выдает исключение.

+2

Почему шаблон VS2013 MVC работает? См. Скриншот в моем вопросе. – Kabbalah

+0

Больше не может – Grokodile

Смежные вопросы