Domanda

Sto costruendo un piccolo negozio online con asp.net mvc e Structuremap ioc / di. La mia classe Basket usa l'oggetto sessione per la persistenza e voglio usare SM per creare il mio oggetto basket attraverso l'interfaccia IBasket. L'implementazione del mio basket richiede HttpSessionStateBase (wrapper dello stato della sessione da mvc) nel costruttore, che è disponibile all'interno di Controller / Azione. Come posso registrare la mia implementazione IBasket per SM?
Questa è la mia interfaccia basket:

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

E registrazione SM:

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

Ma la mia implementazione StoreBasketService ha il costruttore:

public StoreBasketService(HttpSessionStateBase sessionState)

Come posso fornire l'oggetto HttpSessionStateBase a SM, che è disponibile solo nel controller?
Questo è il mio primo utilizzo di SM IOC / DI e non riesco a trovare la soluzione / esempio nella documentazione ufficiale e nel sito Web;)

È stato utile?

Soluzione

Se devi assolutamente utilizzare StoreBasketService per utilizzare la sessione, sarei tentato di definire un'interfaccia e un wrapper attorno a HttpSessionState invece di utilizzare HttpSessionStateBase in modo da poterlo registrare anche con StructureMap. Il wrapper otterrebbe lo stato della sessione dal contesto attuale. Registrare il wrapper con StructureMap e fare in modo che StoreBasketService prenda l'interfaccia come argomento per il costruttore. La mappa della struttura dovrebbe quindi sapere come creare un'istanza del wrapper di interfaccia e iniettarla nella classe StoreBasketService.

L'uso di un'interfaccia e di un wrapper ti consentirà di deridere il wrapper nei test delle unità, allo stesso modo in cui HttpSessionStateBase consente di deridere la sessione effettiva.

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

Tuttavia, puoi fare in modo che StructureMap memorizzi effettivamente il carrello nella sessione usando .CacheBy(InstanceScope.HttpContext) al momento della registrazione. In realtà potrebbe essere meglio avere StoreBasketService implementare la memoria interna invece di archiviare le cose nella sessione - quindi si perde completamente la dipendenza dallo stato della sessione (dal punto di vista della classe) e la soluzione potrebbe essere più semplice. La tua memoria interna potrebbe essere un Dictionary<Guid,Product> poiché è così che accedi ad essi tramite la tua interfaccia.

Vedi anche:

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

Altri suggerimenti

ForRequestedType<IBasketService>()
    .TheDefault.Is.OfConcreteType<StoreBasketService>()
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);

?? funziona?

Ho appena iniziato con StructureMap e non ottengo i risultati che stai descrivendo. Ho eseguito un semplice test usando una semplice classe, configurando Structuremap per cacheby HttpContext, e da quello che posso vedere, CacheBy.HttpContext significa che all'interno della stessa richiesta otterrai la stessa istanza ... non all'interno della stessa Sessione

Il costruttore della mia classe, imposta la data / ora in un campo privato Ho un pulsante che ottiene 2 istanze di MyClass con un intervallo di un secondo ... Quindi visualizza l'ora di entrambe le istanze in un'etichetta.

Premendo la prima volta questo pulsante, gli oggetti A e B sono della stessa istanza, poiché il loro tempo di creazione è esattamente lo stesso, come previsto.

Facendo clic sul pulsante una seconda volta, ti aspetteresti che il tempo di creazione non sia cambiato se le istanze fossero memorizzate nella cache in sessione ... tuttavia, nel mio test ottengo un nuovo tempo di creazione ...

Configurazione mappa strutturale:

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

Evento fatto clic sul pulsante della pagina di 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");
    }
}

È anche possibile utilizzare uno dei metodi ObjectFactory.Inject per iniettare HttpSessionStateBase in StructureMap. Quindi invocherebbe il costruttore con HttpSessionStateBase iniettato.

Ho appena fatto il mio primo tentativo di creare un ambito personalizzato ... creare una piccola applicazione Web con essa e, per quanto posso vedere, sembra funzionare. Ciò memorizzerà nella cache l'oggetto all'interno della sessione dell'utente corrente e restituirà lo stesso oggetto fintanto che rimani all'interno della stessa sessione:

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

}

Devi configurare ObjectFactory come segue nel global.asax Application_start

        ObjectFactory.Initialize(x=>
            x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top