2008-11-02 5 views
1

Je construis une petite boutique en ligne avec asp.net mvc et Structuremap ioc/di. La classe Mon panier utilise l'objet de session pour la persistance, et je veux utiliser SM pour créer mon objet panier via l'interface IBasket. L'implémentation de mon panier nécessite HttpSessionStateBase (wrapper d'état de session de mvc) dans le constructeur, disponible dans Controller/Action. Comment puis-je enregistrer mon implémentation IBasket pour SM?
Ceci est mon interface panier:StructureMap IOC/DI et création d'objet

public interface IBasketService { 
    BasketContent GetBasket(); 
    void AddItem(Product productItem); 
    void RemoveItem(Guid guid); 
} 

et l'enregistrement SM:

ForRequestedType(typeof (IBasketService)).TheDefaultIsConcreteType(typeof (StoreBasketService)); 

Mais ma mise en œuvre de StoreBasketService a constructeur:

public StoreBasketService(HttpSessionStateBase sessionState) 

Comment puis-je fournir objet HttpSessionStateBase à SM, qui est disponible uniquement dans le contrôleur?
Ceci est ma première utilisation de SM CIO/DI et cann't trouver une solution/par exemple dans les documents officiels et site Web;)

Répondre

4

Si vous devez absolument avoir votre StoreBasketService utiliser la session, je serais tenté pour définir une interface et un wrapper autour de HttpSessionState au lieu d'utiliser HttpSessionStateBase pour que vous puissiez également l'enregistrer avec StructureMap. L'encapsuleur obtiendrait l'état de session du contexte actuel. Enregistrez le wrapper avec StructureMap, puis demandez à StoreBasketService de prendre l'interface en tant qu'argument du constructeur. Structure map doit alors savoir comment créer une instance de l'encapsuleur d'interface et l'injecter dans votre classe StoreBasketService. L'utilisation d'une interface et d'un wrapper vous permettra de simuler le wrapper dans vos tests unitaires, de la même manière que HttpSessionStateBase permet de se moquer de la session actuelle.

public interface IHttpSessionStateWrapper 
{ 
    HttpSessionState GetSessionState(); 
} 

public class HttpSessionStateWrapper : IHttpSessionStateWrapper 
{ 
    public virtual HttpSessionState GetSessionState() 
    { 
     return HttpContext.Current.Session; 
    } 
} 

ForRquestedType(typeof(IHttpSessionStateWrapper)) 
    .TheDefaultIsConcreteType(typeof(IHttpSessionStateWrapper)); 

public class StoreBasketService 
{ 
    HttpSessionState session; 
    public StoreBasketService(IHttpSessionstateWrapper wrapper) 
    { 
     session = wrapper.GetSessionState(); 
    } 

    // basket implementation ... 
} 

Cependant, vous pouvez avoir StructureMap stocker réellement votre panier dans la session en utilisant .CacheBy(InstanceScope.HttpContext) lors de son enregistrement. Il peut être préférable que votre StoreBasketService implémente le stockage interne au lieu de stocker des choses dans la session - alors vous perdez complètement la dépendance à l'état de la session (du point de vue de votre classe) et votre solution pourrait être plus simple. Votre stockage interne peut être un Dictionary<Guid,Product> car c'est ainsi que vous y accédez via votre interface.

Voir aussi:

http://www.lostechies.com/blogs/chad_myers/archive/2008/07/15/structuremap-basic-scenario-usage.aspx

http://www.lostechies.com/blogs/chad_myers/archive/2008/07/17/structuremap-medium-level-usage-scenarios.aspx

+0

Je vais essayer aujourd'hui, merci. Mais pour la mise en cache de la classe Basket avec SM, IS.Httpcontext stocke l'objet dans le dictionnaire httpcontext.items, qui est disponible juste au-dessus d'une demande de page, mais je le veux tout au long de la session des utilisateurs. –

0

Je viens de commencer avec StructureMap, et je ne reçois pas les résultats que vous décrivez. j'ai effectué un test simple en utilisant une classe simple, la configuration StructureMap à cacheby HttpContext, et de ce que je peux voir, CacheBy.HttpContext signifie dans le même demande, vous obtiendrez la même instance ... pas dans la même session

Le constructeur de ma classe, définit la date/heure dans un champ privé J'ai un bouton qui obtient 2 instances de MyClass avec un intervalle d'une seconde ... Il affiche ensuite l'heure des deux instances dans une étiquette.

En appuyant la première fois sur ce bouton, les objets A et B sont la même instance, car leur temps de création est exactement le même que prévu.

En cliquant sur le bouton une deuxième fois, vous pouvez prévoir le temps de la création à ne pas avoir changé si les instances seraient mises en cache en session ... Cependant, dans mon test, je reçois un nouveau temps de création ...

configuration StructureMap:

  ObjectFactory.Initialize(x=>x.ForRequestedType<MyClass>(). CacheBy(InstanceScope.HttpContext)); 

événement cliqué bouton de page de test

 protected void btnTest_Click(object sender, EventArgs e) 
    { 
     MyClass c = ObjectFactory.GetInstance<MyClass>(); 
     System.Threading.Thread.Sleep(1000); 
     MyClass b = ObjectFactory.GetInstance<MyClass>(); 



     lblResult.Text = String.Format("cache by httpcontext First:{0} Second:{1} session id {2} ", c.GetTimeCreated(), b.GetTimeCreated(),Session.SessionID); 
    } 

MyClass

public class MyClass 
{ 
    private DateTime _timeCreated; 
    public MyClass() 
    { 
     _timeCreated = DateTime.Now; 
    } 

    public string GetTimeCreated() 
    { 
     return _timeCreated.ToString("dd/MM/yyyy hh:mm:ss"); 
    } 
} 
0

Vous pouvez également utiliser l'une des méthodes ObjectFactory.Inject pour injecter le HttpSessionStateBase dans StructureMap. Il invoquerait alors le constructeur avec le HttpSessionStateBase injecté.

0

Je viens de faire ma première tentative de création d'une portée personnalisée ... construire une petite application web avec, et pour autant que je puisse voir, cela semble fonctionner. Cela cache l'objet dans la session utilisateur en cours et retourne le même objet que tant que vous restez dans la même session:

public class HttpSessionBuilder : CacheInterceptor 
{ 
    private readonly string _prefix = Guid.NewGuid().ToString(); 

    protected override CacheInterceptor clone() 
    { 
     return this; 
    } 

    private string getKey(string instanceKey, Type pluginType) 
    { 
     return string.Format("{0}:{1}:{2}", pluginType.AssemblyQualifiedName, instanceKey, this._prefix); 
    } 

    public static bool HasContext() 
    { 
     return (HttpContext.Current.Session != null); 
    } 

    protected override bool isCached(string instanceKey, Type pluginType) 
    { 
     return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)] != null; 
    } 

    protected override object retrieveFromCache(string instanceKey, Type pluginType) 
    { 
     return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)]; 
    } 

    protected override void storeInCache(string instanceKey, Type pluginType, object instance) 
    { 
     HttpContext.Current.Session.Add(this.getKey(instanceKey, pluginType), instance); 
    } 

} 

Vous devez configurer le ObjectFactory comme suit dans le global.asax Application_Start

 ObjectFactory.Initialize(x=> 
      x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder())); 
1
ForRequestedType<IBasketService>() 
    .TheDefault.Is.OfConcreteType<StoreBasketService>() 
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session); 

?? Est-ce que ça fonctionne?

Questions connexes