Свойство унаследованного интерфейса, не найденное с помощью привязки модели в MVC3, но отлично работает в MVC2
ОБНОВЛЕНИЕ: проблема решена.
Дарин Димитров отвечает ссылкой на другой, связанный с этим вопрос. Одно из предлагаемых решений на этой странице оказалось для нас трудным.
Оригинальный вопрос
Пример кода ниже работает в MVC 2, но генерирует исключение в MVC 3. Кто-нибудь знает, почему MVC 3 ввел это нарушение? Есть ли способ заставить это работать в MVC 3, все еще позволяя мне описывать viewmodel как интерфейс из представления?
В StackOverflow есть еще один вопрос, но он не дает мне никакой информации о том, почему существует разница между MVC 2 и MVC 3.
Model
public interface IPerson {
string Name { get; set; }
}
public interface ISpy : IPerson {
string CodeName { get; set; }
}
public class Spy : ISpy {
public string Name { get; set; }
public string CodeName { get; set; }
}
Действие контроллера
public ActionResult Index() {
var model = new Spy { Name = "James Bond", CodeName = "007" };
return View(model);
}
MVC2 View (работает отлично)
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcApp.Models.ISpy>" %>
<p>CodeName: <%: Html.TextBoxFor(x => x.CodeName) %></p>
<p>Name: <%: Html.TextBoxFor(x => x.Name) %></p>
MVC3 Просмотр (исключение исключений)
@model MvcApp.Models.ISpy
<p>Name: @Html.TextBoxFor(x => x.Name)</p>
<p>CodeName: @Html.TextBoxFor(x => x.CodeName)</p>
Информация об исключении MVC3
Ниже приведена информация о соответствующих исключениях, но вы можете просмотреть весь вывод страницы с ошибкой здесь: https://gist.github.com/1443750.
Runtime Exception
System.ArgumentException: The property **`MvcApp.Models.ISpy.Name`** could not be found.
Source Error:
Line 1: @model MvcApp.Models.ISpy
Line 2: <p>CodeName: @Html.TextBoxFor(x => x.CodeName)</p>
Line 3: <p>Name: @Html.TextBoxFor(x => x.Name)</p>
Stack Trace:
[ArgumentException: The property MvcApp.Models.ISpy.Name could not be found.]
System.Web.Mvc.AssociatedMetadataProvider.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName) +502169
System.Web.Mvc.ModelMetadata.GetMetadataFromProvider(Func`1 modelAccessor, Type modelType, String propertyName, Type containerType) +101
System.Web.Mvc.ModelMetadata.FromLambdaExpression(Expression`1 expression, ViewDataDictionary`1 viewData) +421
System.Web.Mvc.Html.InputExtensions.TextBoxFor(HtmlHelper`1 htmlHelper, Expression`1 expression, IDictionary`2 htmlAttributes) +58
System.Web.Mvc.Html.InputExtensions.TextBoxFor(HtmlHelper`1 htmlHelper, Expression`1 expression) +50
ASP._Page_Views_Home_Index_cshtml.Execute() in c:\Projects\MvcApplication1\MvcApplication1\Views\Home\Index.cshtml:3
Помогите нам Дарин Димитров, вы - наша единственная надежда.
Ответы
Ответ 1
Я уже довел эту проблему до сведения Microsoft. К сожалению, я получил ответ: извините, что по дизайну. Лично вывод, который я нахожу из такого ответа, состоит в том, что команда MVC разрабатывает багги-продукт, если это по дизайну. И их нельзя обвинять в принятии такого дизайнерского решения, они за то, что не упоминают об этом нигде в разделе об изменениях документа выпуска. Если бы они упомянули об этом, тогда это было бы нашей ошибкой, когда мы приняли решение о мигрировании, даже если бы мы сознательно знали о разрушительных изменениях.
В любом случае, здесь связанный вопрос.
И вот ответ от команды MVC:
К сожалению, код фактически использовал исправленную ошибку, где контейнер выражения для целей ModelMetadata был непреднамеренно устанавливается на тип объявления вместо содержащего тип. Эта ошибка должна была быть исправлена из-за потребностей виртуальных свойства и метаданные проверки/модели.
Наличие интерфейсных моделей не является чем-то, что мы поощряем (и, учитывая ограничения, налагаемые исправлением ошибок, может реально поддержка). Переключение на абстрактные базовые классы устранит проблему.
Ответ 2
Измените эту строку:
@model MvcApp.Models.ISpy
Для
@model MvcApp.Models.Spy
Ответ 3
Я нашел жалкое обходное решение, которое позволяет использовать эту модельную структуру:
@model MvcApp.Models.IPerson
<p>Name: @Html.TextBoxFor(x => x.Name)</p>
@Html.Partial('_SpyBox')
И в _SpyBox.cshtml
@model MvcApp.Models.ISpy
<p>CodeName: @Html.TextBoxFor(x => x.CodeName)</p>
Мех.