Question

Contexte: Dans mes méthodes d'action après la baisse des MVC Je reçois commande objets plutôt que des modèles de vue. L'idée est que ces objets de commande (qui équivalent à peu près à des scripts de transaction) seront mis en place et prêt à exécuter en entrant dans le mode d'action, avec le modèle de liant ayant des paramètres de réglage qui sont utilisés au cours du processus d'exécution:

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

Pour rendre les choses un peu plus complexe, mes objets de commande ont des dépendances (services, dépôts, etc.) qui sont nécessaires à leurs constructeurs respectifs; donc je devais créer un modèle de liaison personnalisé qui a utilisé la valeur par défaut DependencyResolver (qui a déjà été mis en place avec mon conteneur IoC) pour construire les objets du modèle:

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

Et mis en place dans Global.asax.cs comme ceci:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();

Encore une fois tout cela fonctionne très bien, les dépendances sont injectés dans le constructeur et le modèle de liaison par défaut prend le relais pour définir les propriétés, comme d'habitude.

Le problème: Le problème que j'ai est que tous mes objets de commande ont un paramètre GUID « SessionId » (qui provient d'un cookie), et la première chose qu'ils font est d'essayer de résoudre un objet de la session de cet ID en utilisant un service injecté.

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

Je voulais enlever cette répétition, donc je créé un deuxième modèle de liaison qui prendrait soin de cette recherche dans le référentiel, ce qui signifie mes objets de commande pourrait avoir une propriété Session directement (suppression de la dépendance du constructeur pour le dépôt de la 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"]);
    }
}

Mon fichier Global.asax.cs maintenant à la recherche comme ceci:

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

Après avoir testé le SessionModelBinder dans l'isolement, je sais que cela fonctionne. Cependant lors de l'utilisation en conjonction avec le DependencyModelBinder, il est jamais appelé. Comment puis-je obtenir MVC utiliser mon DependencyModelBinder lors de la construction des objets du modèle, mais l'avez utiliser mon SessionModelBinder lors de la liaison des propriétés de session sur eux? Ou est-ce que quelqu'un sait une meilleure approche à ce sujet?

Était-ce utile?

La solution

Vous pouvez utiliser la méthode GetPropertyValue dans votre classeur de modèle original pour fournir une valeur de la propriété session:

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);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top