Справочная информация:
В моих методах обратной реакции 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...
}
}
Чтобы сделать вещи немного сложнее, мои командные объекты имеют зависимости (сервисы, репозитории и т. Д.), Которые требуются в их соответствующих конструкторах; поэтому мне пришлось создать пользовательский механизм связывания модели, который использовал DependencyResolver по умолчанию (который уже был настроен с моим контейнером 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 изолированно, я знаю, что он работает. Однако при использовании его вместе с DependencyModelBinder он никогда не вызывается. Как я могу заставить MVC использовать мой DependencyModelBinder при построении объектов модели, но можно ли использовать его SessionModelBinder при привязке к ним свойств сеанса? Или кто-нибудь знает лучший подход к этому?