Одна пользовательская модель связующего с CreateModel и другой для BindModel?

StackOverflow https://stackoverflow.com/questions/9342686

Вопрос

Фон:В моем посте 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);
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top