У меня есть интерфейс модели объявлена с классом, реализующим его:ASP.NET MVC - метаданные используются с моделью от типа модели объекта вместо заявленной модели View
public interface IMyModel
{
[Range(1, 1000)]
[Display(Name = "ModelProp From Interface")]
int MyIntProperty { get; set; }
IMySubModel SubModel { get; }
}
public interface IMySubModel
{
[Range(1,1000)]
[Display(Name = "SubModelProp From Interface")]
int MyIntSubProperty { get; set; }
}
У меня также есть реализация модели, с различными Метаданные:
public class MyModelImplementation:IMyModel
{
[Display(Name = "ModelProp From Class")]
[Range(1, 15)]
public int MyIntProperty
{
get;
set;
}
public IMySubModel SubModel { get; set; }
public MyModelImplementation()
{
SubModel = new MySubModelImplementation();
}
}
public class MySubModelImplementation: IMySubModel
{
[Display(Name = "SubModelProp From Class")]
[Range(1, 15)]
public int MyIntSubProperty
{
get;
set;
}
}
у меня есть вид, где я использую эту модель интерфейса:
@model MvcApplicationModelInterface.Models.IMyModel
@using (Html.BeginForm())
{
<p>Using Lambda Expression:</p>
@Html.DisplayNameFor(m=>m.MyIntProperty)
@Html.EditorFor(m=>m.MyIntProperty)
@Html.ValidationMessageFor(m=>m.MyIntProperty)
<br/>
@Html.DisplayNameFor(m=>m.SubModel.MyIntSubProperty)
@Html.EditorFor(m=>m.SubModel.MyIntSubProperty)
@Html.ValidationMessageFor(m=>m.SubModel.MyIntSubProperty)
<br/>
<p>Using String Expression:</p>
@Html.DisplayName("MyIntProperty")
@Html.Editor("MyIntProperty")
@Html.ValidationMessage("MyIntProperty")
<br/>
@Html.DisplayName("SubModel.MyIntSubProperty")
@Html.Editor("SubModel.MyIntSubProperty")
@Html.ValidationMessage("SubModel.MyIntSubProperty")
<br/>
@Html.ValidationSummary(true)
<br/>
<input type="submit" name="btnSubmit" value="btnSubmit" />
}
An d У меня есть контроллер, который делает правильное связывание и инициализации модели:
[HttpGet]
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
var model = new MyModelImplementation();
model.MyIntProperty = 111;
model.SubModel.MyIntSubProperty = 222;
return View(model);
}
[ActionName("Index"), HttpPost]
public ActionResult Save([ModelBinder(typeof(MyModelBinder))]IMyModel model)
{
return View(model);
}
public class MyModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return new MyModelImplementation();
}
}
Проблема:
Если возвращает действие контроллера вид с NOT NULL модели (возвращение View (новый MyModelImplementation() { ...});), результаты я вижу на экране, являются:
Однако, если возвращает действие результатов контроллера с нулевой модели (возвращение View (нуль);), то результаты:
Как вы можете видеть, поведение для хелмеров Lambda html и помощников строковых выражений различно, и ни одно из них не является согласованным вообще, и какое-то поведение выглядит как ошибка:
- (ожидаемый) Для лямбда-хелперов отображаемое_имя берется из IMyModel
- (неожиданный) Для выражения Струнный все метаданные взяты из MyModelImplementation класса (Другими словами, если вы используете Html.DisplayNameFor (м = > m.MyIntProperty) - он показывает метаданные из интерфейса (тип модели Declared in view), однако, если вы используете Html.DisplayName («MyIntProperty»), он использует метаданные model.GetType()).
- (неожиданно) ВСЕ. Правила и последовательности проверки ВСЕГДА выбраны из метаданных MyModelImplementation (model.GetType()) вместо объявленного типа модели (IMyModel).
- (ожидаемый) Для собственности строкового выражения помощников модели берется из интерфейса только в случае, если модель передается в представление является NULL
- (неожиданный) Для метаданных свойства строкового выражения помощников подмодели является не возобновлено/уважаться на все , в случае, если модель передается зрения NULL
Вопрос:
Каков наилучший способ решения этой ASP.NET MVC Bug/Feature? Как заставить Html-расширения всегда использовать метаданные из типа модели Объявлено в представлении по умолчанию? Я попытался использовать MetadataTypeAttribute, но в этом случае тот, кто реализует модель, получит свободу перезаписывать оригинальные метаданные, указанные в интерфейсе, которые я не хочу разрешать.Поэтому я скорее ищу какую-то пользовательскую реализацию ModelMetadataProvider. Также некоторые атрибуты метаданных не соблюдаются в случае MetadataType, например RequiredAttribute.
это неправда. Как редактор, так и редактор. Используйте ViewData.Metadata и ExpressionHelper для получения метаданных, поэтому они оба имеют доступ к объекту ContainerType объекта Metadata, указывающему на интерфейс. Но почему-то вместо ContainerType используется model.GetType() –
@Philipp - Нет, оба используют 'ViewData.ModelMetadata', но способ, которым он получает метаданные, отличается. Они оба попадают туда через объект TemplateHelper, а TemplateHeler вызывает 'ModelMetadata.FromLambdaExpression' для строго типизированных и' ModelMetadata.FromStringExpression' для типов строк. Версия Lambda ищет тип контейнера на основе выражения, в то время как в строковой версии нет этой информации, поэтому нужно искать контейнер, используя 'GetType()'. В любом случае это не ошибка, потому что версии строк просто не имеют доступа к данным выражения. –
Это утверждение также неточно: как вы видите, если вы передаете Model = null - для выражения строки он извлекает метаданные из IModel.Property, однако он не делает то же самое для ISubModel.SubProperty (Model.SubModel.SubProperty). Поэтому по крайней мере поведение непоследовательно. –