Pregunta

Fondo:En mi MVC Public Back Action Methods que estoy recibiendo dominio objetos en lugar de ver modelos. La idea es que estos objetos de comando (que equivalen aproximadamente a los scripts de transacción) se configurarán y listos para ejecutar al ingresar el método de acción, con el aglutinante del modelo que se establece parámetros que se usan durante el proceso de ejecución:

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...
    }
}

Para hacer las cosas un poco más complejas, mis objetos de comando tienen dependencias (servicios, repositorios, etc.) que se requieren en sus respectivos constructores; Por lo tanto, tuve que crear una carpeta de modelo personalizada que usara el DependencyResolver predeterminado (que ya estaba configurado con mi contenedor IOC) para construir los objetos modelo:

public class DependencyModelBinder : DefaultModelBinder
{
    protected override Object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return DependencyResolver.Current.GetService(modelType);
    }
}

Y configurar en Global.asax.cs al igual que:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();

Nuevamente, todo esto funciona bien, las dependencias se inyectan en el constructor y luego el aglutinante del modelo predeterminado se hace cargo para establecer las propiedades como de costumbre.

La cuestión:El problema que tengo es que todos mis objetos de comando tienen un parámetro GUID 'SessionID' (que proviene de una cookie), y lo primero que hacen es intentar resolver un objeto de sesión de esta identificación utilizando un servicio inyectado.

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...
    }
}

Quería eliminar esta repetición, así que creé una segunda carpeta modelo que se encargaría de esta búsqueda en el repositorio, lo que significa que mis objetos de comando podrían tener un Session propiedad directamente (eliminar la dependencia del constructor para el repositorio de sesión).

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"]);
    }
}

Mi Global.asax.cs Archivo ahora como si así:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
ModelBinders.Binders.Add(typeof(Session), new SessionModelBinder());

Habiendo probado el SessionModelbinder de forma aislada, sé que funciona. Sin embargo, cuando lo usa junto con DependencyModelBinder, nunca se llama. ¿Cómo puedo hacer que MVC use mi dependenciaModelBinder al construir objetos modelo, pero hacer que use mi SessionModelBinder al vincular las propiedades de la sesión? ¿O alguien sabe un mejor enfoque para esto?

¿Fue útil?

Solución

Puede usar el método GetPropertyValue en su carpeta de modelo original para proporcionar un valor para la propiedad de la sesión:

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);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top