Одна пользовательская модель связующего с CreateModel и другой для BindModel?
-
27-10-2019 - |
Вопрос
Фон:В моем посте MVC методы действия я получаю командование объекты, а не просмотреть модели. Идея состоит в том, что эти объекты команды (которые примерно равняются сценариям транзакций) будут настроены и готовы к выполнению при введении метода действия, при этом связующее модель с установкой параметров, которые используются в процессе выполнения:
public class MyCommand : IMyCommand
{
// In this case Value1 and Value2 are being set by the default model binder from posted form values - wonderful :)
public String Value1 { get; set; }
public String Value2 { get; set; }
public CommandResult ExecuteCommand()
{
// Does something awesome...
}
}
Чтобы сделать вещи немного более сложными, мои командные объекты имеют зависимости (услуги, репозитории и т. Д.), Которые требуются в их соответствующих конструкторах; Поэтому мне пришлось создать пользовательскую модель -связующее, которое использовало зависимость по умолчанию (который уже был настроен с моим контейнером IOC) для построения объектов модели:
public class DependencyModelBinder : DefaultModelBinder
{
protected override Object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return DependencyResolver.Current.GetService(modelType);
}
}
И настроен в Global.asax.cs
вот так:
ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
Опять же, все работает нормально, зависимости впрыскивают в конструктор, а затем связующий модель по умолчанию вступает во владение, чтобы установить свойства как обычно.
Проблема:Проблема, которую у меня есть, заключается в том, что все мои командные объекты имеют параметр GUID «SessionId» (который поступает из файла cookie), и первое, что они делают, это попытаться разрешить объект сеанса с этого идентификатора с использованием введенного услуги.
public class MyCommand : IMyCommand
{
public MyCommand (ISessionRepository sessionRepository) { ... }
public Guid SessionId { get; set; } // Set by model binder from a cookie...
public CommandResult Execute()
{
Session session = SessionRepository.Get(SessionId);
if (session == null)
// Do something not so awesome...
}
}
Я хотел удалить это повторение, поэтому я создал вторую модель связующего, которое позаботилось бы об этом поиске в репозитории, что означает, что мои командные объекты могут иметь Session
Свойство напрямую (удаление зависимости конструктора для репозитория сеанса).
public class SessionModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
return sessionRepository.Get((Guid)controllerContext.HttpContext.Request["SessionId"]);
}
}
Мой Global.asax.cs
Файл теперь выглядит так:
ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
ModelBinders.Binders.Add(typeof(Session), new SessionModelBinder());
Протестировав SessionModelbinder в изоляции, я знаю, что это работает. Однако при использовании его в сочетании с зависимостью модельбиндера он никогда не вызывается. Как я могу заставить MVC использовать мой зависимостьмодельбиндер при построении объектов модели, но использовать его в моем SessionModelbinder при связывании свойств сеанса на них? Или кто -нибудь знает лучший подход к этому?
Решение
Вы можете использовать метод GetPropertyValue в своей оригинальной модели связующего, чтобы предоставить значение для свойства сеанса:
public class DependencyModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return DependencyResolver.Current.GetService(modelType);
}
protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
{
if (propertyDescriptor.Name == "Session")
{
var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
return sessionRepository.Get(controllerContext.HttpContext.Request["SessionId"]);
}
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
}