StructureMap IOC / DI и создание объектов - PullRequest
1 голос
/ 02 ноября 2008

Я создаю небольшой интернет-магазин с asp.net mvc и Structuremap ioc / di. Мой класс Basket использует объект сессии для сохранения, и я хочу использовать SM для создания моего объекта корзины через интерфейс IBasket. Моя реализация корзины требует HttpSessionStateBase (оболочка состояния сеанса из mvc) в конструкторе, который доступен внутри Controller / Action. Как зарегистрировать мою реализацию IBasket для SM?
Это интерфейс моей корзины:

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

И СМ регистрация:

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

Но моя реализация StoreBasketService имеет конструктор:

public StoreBasketService(HttpSessionStateBase sessionState)

Как мне предоставить объект HttpSessionStateBase для SM, который доступен только в контроллере?
Это мое первое использование SM IOC / DI, и я не могу найти решение / пример в официальной документации и на веб-сайте;)

Ответы [ 5 ]

4 голосов
/ 03 ноября 2008

Если вам абсолютно необходимо, чтобы ваш StoreBasketService использовал сеанс, у меня возникло бы желание определить интерфейс и оболочку вокруг HttpSessionState вместо использования HttpSessionStateBase, чтобы вы могли также зарегистрировать его в StructureMap. из текущего контекста. Зарегистрируйте обертку в StructureMap и затем пусть ваш StoreBasketService принимает интерфейс в качестве аргумента для конструктора. Карта структуры должна затем знать, как создать экземпляр интерфейсной оболочки и внедрить его в ваш класс StoreBasketService.

Использование интерфейса и оболочки позволит вам смоделировать оболочку в ваших модульных тестах, так же как HttpSessionStateBase позволяет имитировать реальный сеанс.

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

Однако вы можете сделать так, чтобы StructureMap фактически сохранял вашу корзину в сеансе, используя .CacheBy(InstanceScope.HttpContext) при ее регистрации. На самом деле может быть лучше, если ваш StoreBasketService реализует внутреннее хранилище, а не хранит вещи в сеансе - тогда вы полностью потеряете зависимость от состояния сеанса (с точки зрения вашего класса), и ваше решение может быть проще. Ваше внутреннее хранилище может быть Dictionary<Guid,Product>, так как вы получаете к ним доступ через интерфейс.

Смотри также:

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

1 голос
/ 16 декабря 2008
ForRequestedType<IBasketService>()
    .TheDefault.Is.OfConcreteType<StoreBasketService>()
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);

?? это работает?

0 голосов
/ 08 декабря 2008

Я только что сделал свою первую попытку создания настраиваемой области видимости ... создаю с ее помощью небольшое веб-приложение, и, насколько я вижу, оно работает. Это кеширует объект внутри текущего сеанса пользователя и возвращает тот же объект, пока вы остаетесь в том же сеансе:

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

}

Вы должны настроить ObjectFactory следующим образом в global.asax Application_start

        ObjectFactory.Initialize(x=>
            x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
0 голосов
/ 08 декабря 2008

Вы также можете использовать один из методов ObjectFactory.Inject для внедрения HttpSessionStateBase в StructureMap. Затем он вызовет конструктор с введенным HttpSessionStateBase.

0 голосов
/ 08 декабря 2008

Я только начал с StructureMap, и я не получаю результаты, которые вы описываете. Я выполнил простой тест с использованием простого класса, настроив Structuremap для кэширования с помощью HttpContext, и, как я вижу, CacheBy.HttpContext означает, что в рамках одного и того же запроса вы получите один и тот же экземпляр ... а не в рамках одного сеанса

Конструктор моего класса, устанавливает дату / время в приватном поле У меня есть кнопка, которая получает 2 экземпляра MyClass с интервалом в одну секунду ... Затем он отображает время обоих экземпляров в метке.

При первом нажатии этой кнопки объекты A и B являются одним и тем же экземпляром, поскольку время их создания точно такое же, как и ожидалось.

При повторном нажатии кнопки вы можете ожидать, что время создания не изменится, если экземпляры будут кэшироваться в сеансе ... однако в моем тесте я получаю новое время создания ...

Конфигурация структуры карты:

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

событие нажатия кнопки на тестовой странице

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