Как указать связующему по умолчанию для модели игнорировать свойство при обратной передаче
Так что у меня есть этот абстрактный класс Плата в моих моделях (сгенерированный EF с базой данных в первую очередь)
public abstract partial class Fee
{
public int FeeId { get; set; }
public int ProductId { get; set; }
public string Name { get; set; }
public decimal StandardPrice { get; set; }
}
Он наследуется рядом других классов для моделирования различных видов сборов, например, QuarterlyFee и тому подобное. У меня также есть класс Customer в модели, и клиенты могут иметь собственные тарифы, смоделированные классом CustomerRate.
Теперь на странице сведений о клиенте я пытаюсь отобразить все возможные сборы для клиента, чтобы пользователь мог выбрать, какие тарифы являются пользовательскими, а какие - стандартами, без ставки. Я просто создаю класс ViewModel возможный вариант, чтобы смоделировать это:
public class PossibleFee
{
public int CustomerId { get; set; }
public int FeeId { get; set; }
public Boolean CustomRate { get; set; }
public decimal CustomerPrice { get; set; }
public virtual Customer Customer { get; set; }
public virtual Fee Fee { get; set; }
}
И я добавил свойство в класс Customer для хранения возможных сборов (ICollection ВОЗМОЖНЫЕ ФАЙЛЫ), заполнил это свойство в методе Controller (общедоступные подробности ActionResult (int id = 0)), позже EditorTemplate и получил список. всех возможных сборов для клиента в зависимости от продуктов, которые он использует, которые пользователь может редактировать.
Теперь, однако, при обратной передаче, когда я нажимаю кнопку "Сохранить", механизм связывания моделей по умолчанию выполняет свою работу и пытается заполнить ICollection of OptionFee, и для каждого возможного объекта попробуйте создать объект Fee для заполнения свойства с тем же именем.
Конечно, это не работает, так как Fee является абстрактным, вопрос довольно прост: как мне сказать Default Model Binder игнорировать это свойство при обратной передаче, ну, потому что он мне не нужен при обратной передаче?
Я знаю, что мог бы просто скопировать нужные мне поля на EditorTenplate для возможного класса в классе Возможный ответ или даже удалить реферат из комиссии. Но я хочу знать, могу ли я настроить Default Model Binder под свои нужды, не касаясь модели.
РЕДАКТИРОВАТЬ 2: Yarx предложил более чистое решение, на мой взгляд, см. 2 сообщения ниже
РЕДАКТИРОВАТЬ: Ну Карлос Коррал Карвахал почти все понял, метод SetProperty вызывается после того, как ModelBinder пытается создать объект, поэтому мне пришлось перезаписать BindProperty вместо
public class CustomModelBinder : DefaultModelBinder
{
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.Attributes.Contains(new ModelBinderIgnoreOnPostback()))
{
return;
}
base.BindProperty(controllerContext, bindingContext,propertyDescriptor);
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
public class ModelBinderIgnoreOnPostback : Attribute {}
Добавлен пользовательский атрибут на тот случай, если он кому-то нужен
2 ответа
Я предлагаю разделить ваши ViewModel, чтобы у вас была отдельная ViewModel для каждого действия. Имейте ViewModel, который предназначен только для отображения информации, и тот, который используется для принятия информации от Post Back. Потому что в подобных случаях большинство полей, которые вы хотите привязать к PostBack, также необходимы в ViewModel, который используется для отображения данных. Прежде всего проще всего унаследовать ваши ViewModels. Смотрите ниже, например.
public class PossibleFeeInputModel
{
public int CustomerId { get; set; }
public int FeeId { get; set; }
public Boolean CustomRate { get; set; }
public decimal CustomerPrice { get; set; }
public virtual Customer Customer { get; set; }
}
,
public class PossibleFeeViewModel : PossibleFeeInputModel
{
public virtual Fee Fee { get; set; }
}
Таким образом, вы можете использовать возможную версию для просмотра вида, но используйте возможную привязку для вероятности, когда принимаете PostBack.
Вы можете создать пользовательский механизм связывания моделей, унаследованный от механизма связывания моделей по умолчанию, а также перехватить класс Fee и выполнить с ним определенные действия:
public class CustomModelBinder : DefaultModelBinder
{
protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
{
if (propertyDescriptor.PropertyType == typeof(Fee))
{
//Take desicions
}
base.SetProperty(controllerContext, bindingContext,
propertyDescriptor, value);
}
}
И в глобальном.asax:
ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
Надеюсь, поможет