2015-11-13 3 views
3

My Post call не возвращает правильный тип модели. Всегда используйте BaseObject вместо правильного производного объекта, который я прошел в от ПолучитьEditorFor Inheritance Model MVC

RestaurantViewModel.cs

public class RestaurantViewModel{ 
    public Food BaseFoodObject{get;set;} 
} 

Food.cs

public class Food{ 
    public string Price{get;set;) 
} 

Bread.cs - Наследование Food

public class Bread:Food{ 
    public int Unit{get;set;} 
} 

Milk.cs - Наследование Food

public class Milk:Food{ 
    public string Brand{get;set} 
} 

Редактор для шаблона для хлеба. Дисплей устройства и позволяет пользователю редактировать

Index.html

@Model RestaurantViewModel 

@using(Html.BeginForm("SaveFood", "Food")) 
{ 
    @Html.EditorFor(m=>m.BaseFoodObject) 
<input type="submit" value="Process"/> 
} 

Bread.cshtml

@Model Bread 
<div> 
    @Html.TextboxFor(bread=>bread.Unit) 
</div> 

FoodController.cs

public ActionResult Index(){ 
    Bread bread = new Bread(){ 
    Price = "$10", 
    Unit = 1 
    } 
    RestaurantViewModel viewModel = new RestaurantViewModel(){ 
    BaseFoodObject = bread 
    } 
    return View(viewModel); 
} 

public ActionResult Post(RestaurantViewModel viewModelPost) 
{ 
// When I inspect the viewModelPost, there is no attribute for unit 
} 

Конечный результат: 1. Дисплей выглядит правильно. EditorFor достаточно умен, чтобы выбрать правильный шаблон редактора и правильно отобразить значение 2. Сохранить не Работа. Единица атрибут Хлеб Объект не передается с RestaurantViewModel. Причиной этого является RestaurantViewModel используется объект Food вместо хлеба

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

Благодаря

Update 1: Я решил эту проблему с помощью пользовательского связующего и используя фабрику для того чтобы решить, какой объект я действительно хочу. Это помогает построить правильную модель, которую я хочу

ответ

2

MVC не имеет гражданства. A couple от references.

Там есть несколько заявлений в вашем вопросе, что конфликт с этим, и как MVC переплетные работы, например:

Мои сообщения вызов не возвращает правильный тип модели.

Возможно только терминология, но Опубликуйте вызов не «возвращает тип модели» - она ​​идет в модель, которая определила в пост действия, в данном случае RestaurantViewModel.

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

, потому что он является лицом без гражданства, он ничего не знает о модели передается из get ... абсолютно ничего.

Последний html, обработанный с помощью getaction + view.cshtml + модели, не является связан с реакцией. Вы можете так же легко взять предоставленный html, сохранить его, перезагрузить свой компьютер, перезагрузить визуализированный html, и он будет работать точно так же.

способ изменить EditorFor и сказать ему, чтобы использовать модель в View или тип объекта, который я прошел, когда я отобразить его

При использовании EditorFor он устанавливает ID и name атрибут, основанный на модели, к которой он привязан, поэтому он уже делает это, но, возможно, вы не привязываетесь к модели, которую хотите привязать, чтобы получить правильный id.


Так, на вопрос, если в «нормальном» код C# вы должны были создавать новый экземпляр RestaurantViewModel, что бы вы ожидать тип BaseFoodObject быть?

Это то, что делает ModelBinder - это создание нового RestaurantViewModel.

Поскольку подпись вашего действия после действия не включает ничего общего с Bread - все свойства хлеба игнорируются.

Некоторые опции:


Проверьте наличие свойств пищи после связывания и читать их вручную (вероятно, самый быстрый + простой, но не очень «MVC-иш»)

public ActionResult Post(RestaurantViewModel viewModelPost) 
{ 
    if (!string.IsNullOrEmpty(Request.Form["Unit"])) 
     // it's a bread form 

, чтобы сделать это проще, вы могли бы обеспечить скрытое поле с типом

if (Request.Form["Type"] == typeof(Bread).Name) 
    { 
     var bread = new Bread { Unit = Request.Form["Unit"] } 

Добавить хлеб к действию, так что это связано

public ActionResult Post(RestaurantViewModel viewModelPost, Bread bread) 

но, очевидно, он не будет работать на молоко.

Так может расширить это с помощью ActionNameSelector, чтобы выбрать правильное действие

public ActionResult PostBread(RestaurantViewModel viewModelPost, Bread bread) 
public ActionResult PostMilk(RestaurantViewModel viewModelPost, Milk milk) 

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 
public sealed class FoodSelectorAttribute : ActionNameSelectorAttribute 
{ 
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) 
    { 
     ... check if provided parameters contains bread/milk 

(related link, но не решение этого конкретного случая)


Другим вариантом может быть, чтобы изменить тип ресторана на общий, но потребует еще нескольких изменений (и в идеале использования интерфейсов) и более подробной информации (представленной здесь как идея, а не решение)

Основы будет:

public class RestaurantViewModel<T> 
    where T: Food 
{ 
} 

public ActionResult Post(RestaurantViewModel<Bread> viewModelPost) 

public ActionResult Post(RestaurantViewModel<Milk> viewModelPost) 

, но я не подтверждается, если ModelBinder по умолчанию будет работать в этом случае.

+0

Спасибо. Я решил это с помощью специального связующего и фабрики. Ваше предложение замечательно. – namhoaingo

2

Проблема связана с сообщением. После публикации все, что у вас есть, это набор опубликованных данных и параметр типа, RestaurantViewModel. Modelbinder устанавливает все соответствующие поля на Food, потому что это все, что он знает. Все остальное отбрасывается. Нет ничего, что можно было бы сделать по этому поводу. Если вам нужно разместить поля, связанные с Bread, тогда тип вашей недвижимости должен быть Bread. Это единственный способ, которым это будет работать.

+0

Вы можете сделать HiddenFor (тип модели) в Bread.cshtml? Когда страница отображается, тип модели должен быть Bread, и мы можем расширить ModelBinder, чтобы искать это поле. – namhoaingo

+0

Возможно, вы сможете это сделать, но я, как правило, нахожусь в замешательстве с помощью modelbinder, особенно для конкретного и узкого сценария. Я бы счел более уместным просто взять «FormCollection» и вручную обновить и привязать значения к вашей модели. –

+0

Не могли бы вы подробнее объяснить этот подход с помощью FormCollection? – namhoaingo

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