Domanda

Sfondo:Nei miei metodi di azione post back MVC che sto ricevendo comando oggetti piuttosto che visualizzare i modelli. L'idea è che questi oggetti di comando (che equivalgono approssimativamente agli script delle transazioni) saranno impostati e pronti per essere eseguiti all'ingresso del metodo di azione, con il legante del modello che ha parametri impostati che vengono utilizzati durante il processo di esecuzione:

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

Per rendere le cose un po 'più complesse, i miei oggetti di comando hanno dipendenze (servizi, repository ecc.) Che sono richiesti nei rispettivi costruttori; Quindi ho dovuto creare un legante modello personalizzato che utilizzava la dipendenza predefinita Resolver (che era già impostata con il mio contenitore IOC) per costruire gli oggetti del modello:

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

E impostare Global.asax.cs così:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();

Ancora una volta tutto funziona bene, le dipendenze vengono iniettate nel costruttore e quindi il legante del modello predefinito prende il sopravvento per impostare le proprietà come al solito.

Il problema:Il problema che ho è che tutti i miei oggetti di comando hanno un parametro GUID "SessionID" (che proviene da un cookie) e la prima cosa che fanno è provare a risolvere un oggetto di sessione da questo ID usando un servizio iniettato.

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

Volevo rimuovere questa ripetizione, quindi ho creato un secondo legante modello che si sarebbe preso cura di questa ricerca nel repository, il che significa che i miei oggetti di comando potrebbero avere un Session Proprietà direttamente (rimozione della dipendenza dal costruttore per il repository della sessione).

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

Mio Global.asax.cs File ora sembra così:

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

Dopo aver testato il moderno sessione in isolamento, so che funziona. Tuttavia, quando lo usi insieme al DipendencyModelbinder, non viene mai chiamato. Come posso convincere MVC a utilizzare la mia DipendencyModelbinder durante la costruzione di oggetti del modello, ma ho usato la mia session modelbinder quando le proprietà di sessione di legame su di essi? O qualcuno sa un approccio migliore a questo?

È stato utile?

Soluzione

È possibile utilizzare il metodo GetPropertyValue nel legante del modello originale per fornire un valore per la proprietà della sessione:

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);
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top