Мне понадобился хороший день, чтобы найти ответ на тесно связанную проблему - хотя я не уверен, что это точно такая же проблема, я публикую ее здесь на тот случай, если другие ищут решение той же проблемы.Точная проблема.
В моем случае у меня есть абстрактный базовый тип для ряда различных типов моделей представления.Поэтому в основной модели представления у меня есть свойство абстрактного базового типа:
class View
{
public AbstractBaseItemView ItemView { get; set; }
}
У меня есть несколько подтипов AbstractBaseItemView, многие из которых определяют свои собственные эксклюзивные свойства.
Моя проблема в том, что связыватель модели не смотрит на тип объекта, присоединенного к View.ItemView, а вместо этого смотрит только на объявленный тип свойства, которым является AbstractBaseItemView, и решает связать only свойства, определенные в абстрактном типе, игнорируя свойства, специфичные для конкретного типа AbstractBaseItemView, который, как оказалось, используется.
Обходной путь для этого не очень приятен:
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
// ...
public class ModelBinder : DefaultModelBinder
{
// ...
override protected ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType.IsAbstract && bindingContext.Model != null)
{
var concreteType = bindingContext.Model.GetType();
if (Nullable.GetUnderlyingType(concreteType) == null)
{
return new AssociatedMetadataTypeTypeDescriptionProvider(concreteType).GetTypeDescriptor(concreteType);
}
}
return base.GetTypeDescriptor(controllerContext, bindingContext);
}
// ...
}
Хотя это изменение кажется хакерским и очень «системным», оно, похоже, работает - и, насколько я могу судить, не представляет значительного риска для безопасности, поскольку оно не связано с CreateModel() и, следовательно, не позволяет вам публиковать что-либо и обманывать связыватель модели при создании просто любого объекта.
Он также работает только тогда, когдаобъявленный тип свойства является абстрактным типом, например, абстрактным классом или интерфейсом.
В связанной заметке мне приходит в голову, что другие реализации, которые я видел здесь, переопределяют CreateModel (), вероятно, будет только работать, когда вы публикуете совершенно новые объекты - и будет страдать от той же проблемы, с которой я столкнулся, когда объявленный тип свойства имеет абстрактный тип.Таким образом, вы, скорее всего, не сможете редактировать определенные свойства конкретных типов на существующих объектах модели, но только создавать новые.
Так, другими словами,вам, вероятно, потребуется интегрировать этот обходной путь в связыватель, чтобы также иметь возможность правильно редактировать объекты, которые были добавлены в модель представления перед привязкой ... Лично я считаю, что это более безопасный подход, так как я контролирую, какой конкретный типдобавляется - так что контроллер / действие может, косвенно, указать конкретный тип, который может быть связан, просто заполнив свойство пустым экземпляром.
Я надеюсь, что это полезно для других ...