Pergunta

Estou construindo pequena loja web com asp.net MVC e StructureMap IOC / di. Minha classe Basket usa objeto de sessão para persistência, e eu quero usar SM para criar meu objeto cesta através da interface iBasket. Minha implementação cesta necessidade HttpSessionStateBase (sessão de estado do invólucro da MVC) no construtor, que está disponível dentro do controlador / ação. Como faço para registrar minha implementação iBasket para SM?
Esta é a minha interface cesta:

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

E Registro de SM:

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

Mas minha implementação StoreBasketService tem construtor:

public StoreBasketService(HttpSessionStateBase sessionState)

Como posso fornecer HttpSessionStateBase objeto para SM, que está disponível somente no controlador?
Este é o meu primeiro uso de SM IOC / DI, e cann't encontrar solução / exemplo na documentação oficial e web site;)

Foi útil?

Solução

Se você absolutamente tem que ter seu uso StoreBasketService a sessão, eu estaria tentado a definir uma interface e invólucro em torno HttpSessionState em vez de usar HttpSessionStateBase de modo que você pode registrá-lo com StructureMap como well.The invólucro iria ficar o estado da sessão a partir do contexto atual. Registre o wrapper com StructureMap e, em seguida, ter seu StoreBasketService tomar a interface como o argumento para o construtor. mapa estrutura deve, em seguida, saber como criar uma instância do invólucro interface e injetá-lo em sua classe StoreBasketService.

Usando uma interface e invólucro permitirá que você zombar o wrapper em seus testes de unidade, muc da mesma forma HttpSessionStateBase permite zombando da sessão real.

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

No entanto, você pode ter StructureMap realmente armazenar sua cesta na sessão usando .CacheBy(InstanceScope.HttpContext) ao registrá-lo. Ele pode realmente ser melhor para ter seu StoreBasketService implementar armazenamento interno em vez de armazenar coisas na sessão - então você perde a dependência do estado da sessão inteiramente (a partir da perspectiva de sua classe) e sua solução poderia ser mais simples. Seu armazenamento interno pode ser um Dictionary<Guid,Product> já que é assim que você acessá-los através de sua interface.

Veja também:

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

Outras dicas

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

?? é que isso funciona?

Eu só comecei com StructureMap, e eu não obter os resultados que você está descrevendo. I realizado um teste simples usando uma classe simples, configurando StructureMap para cacheby HttpContext, e pelo que posso ver, meios CacheBy.HttpContext dentro do mesmo pedido que você vai ter o mesmo exemplo ... não dentro da mesma sessão

O construtor da minha classe, define a data / hora em um campo privado Eu tenho um botão que fica 2 instâncias de MyClass com intervalo de um segundo ... Em seguida, exibir o tempo de ambas as instâncias em um rótulo.

Pressionando a primeira vez que este botão, objeto A e B são os mesmos exemplo, como sua data de criação é exatamente o mesmo, como esperado.

Ao clicar no botão uma segunda vez, você esperaria o tempo de criação não ter mudado se casos seriam armazenados em cache na sessão ... No entanto, no meu teste eu conseguir um novo tempo de criação ...

configuração StructureMap:

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

Button clicado caso de página de teste

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

Você também pode usar um dos métodos ObjectFactory.Inject para injetar o HttpSessionStateBase em StructureMap. Em seguida, ele iria chamar o Construtor com o injetado HttpSessionStateBase.

Eu só fiz minha primeira tentativa de criar um escopo personalizado ... construir uma pequena aplicação web com ele, e, tanto quanto eu posso ver, parece trabalho. Isto irá armazenar em cache o objeto dentro da sessão atual do usuário e irá retornar o mesmo objeto, enquanto você permanecer dentro da mesma sessão:

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

}

Você tem que configurar o ObjectFactory da seguinte forma no Global.asax Application_Start

        ObjectFactory.Initialize(x=>
            x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top