ASP.NET MVC - метаданные модели, используемые из типа объекта модели вместо объявленной модели представления

У меня есть интерфейс объявленной модели с классом, реализующим его:

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" />
}

И у меня есть контроллер, который делает правильную привязку и инициализацию модели:

    [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 (new MyModelImplementation () {...});), результаты, которые я вижу на экране:

Однако, если действие контроллера возвращает результаты с нулевой моделью (return View (null);), тогда получаются следующие результаты:

Как вы можете видеть, поведение помощников Lambda HTML и помощников по строковым выражениям отличается, и ни один из них не является согласованным вообще, и некоторое поведение выглядит как ошибка:

  • (ожидается) Для лямбда-помощников DisplayName взято из IMyModel
  • (неожиданно) Для выражения String все метаданные берутся из класса MyModelImplementation (другими словами, если вы используете Html.DisplayNameFor(m=>m.MyIntProperty) - он показывает метаданные из интерфейса (тип модели объявлен в представлении), однако, если вы используете Html.DisplayName("MyIntProperty") использует метаданные модели. GetType ()).
  • (неожиданно) ВСЕ правила и строки проверки ВСЕГДА берутся из метаданных MyModelImplementation (model.GetType()) вместо объявленного типа модели (IMyModel).
  • (ожидается) Для строкового выражения вспомогательное свойство Модель берется из интерфейса только в том случае, если модель, передаваемая в представление, имеет значение NULL.
  • (неожиданно) Для помощника строкового выражения метаданные свойства SubModel вообще не извлекаются / не соблюдаются, если модель, переданная в представление, имеет значение NULL

Вопрос:

Каков наилучший обходной путь для этой ошибки / функции ASP.NET MVC? Как заставить расширения HTML всегда использовать метаданные из типа модели, объявленной в представлении по умолчанию? Я пытался использовать MetadataTypeAttribute, но в этом случае тот, кто реализует модель, получит свободу перезаписи исходных метаданных, указанных в интерфейсе, что я не хочу допускать. Поэтому я скорее ищу некоторую пользовательскую реализацию ModelMetadataProvider. Также некоторые атрибуты метаданных не учитываются в случае MetadataType, например RequiredAttribute.

1 ответ

Я не верю разнице между Editor() а также EditorFor() это ошибка Я думаю это потому что EditorFor() имеет доступ к информации о типах строго типизированной модели, тогда как редактор должен использовать отражение, чтобы получить тип, который возвращает фактический тип, а не используемый тип интерфейса.

Я думаю, что вы видите, что строго типизированные версии имеют больше контекста и могут получить информацию об интерфейсе, а не просто вызывать GetType(),

Проверка работает правильно, потому что вы сказали, что связыватель модели связывается с MyModelBinder, который связывается с MyModelImplementation. Проверка основана на методе, который вы публикуете, и аргументах, которые он принимает.

Другие вопросы по тегам