Структура жизненного цикла PerRequest - PullRequest
5 голосов
/ 29 марта 2011

Я хочу добавить экземпляр в карту структуры на лету (т. Е. Вне реестра / конфигурации), которая живет в течение срока действия запроса.

В настоящее время я делаю это в HandleBeginRequest событии IHttpModule:

container.Configure(x => x.For<IMyClass>()
  .LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
  .Use(new MyClass()));

Однако, если в какой-то момент в жизни приложения я сделаю:

ObjectFactory.WhatDoIHave();

Я вижу столько настроенных экземпляров для IMyClass, сколько было запросов (или, по крайней мере, значительную сумму).

Думая об этом, этот вид имеет смысл, учитывая мой код.

Есть ли лучший способ внедрить экземпляр в контейнер просто для жизни текущего запроса таким образом, чтобы не загрязнять весь контейнер?

Спасибо

Ответы [ 3 ]

13 голосов
/ 31 марта 2011

Ваша проблема в том, что вы регистрируете тип в контейнере один раз для каждого запроса, что основывается на регистрациях. Настройка контейнера в идеале должна выполняться один раз в жизненном цикле приложения - обычно в событии Application_Start для веб-приложений.

Структура карты позволяет вам указать функцию создания, которая будет вызываться при создании объекта, что позволит вам настроить дополнительные этапы создания объекта.

Вместо вашего текущего вызова Configure в событии Begin_Request вставьте следующее в конфигурацию контейнера во время Application_Start.

For<IMyClass>().HttpContextScoped().Use(() => new MyClass());

Обратите внимание на лямбду в методе Use. Лямбда может содержать любую логику, необходимую для создания объекта, и она будет вызываться по одному на каждый жизненный цикл (на запрос в случае жизненного цикла HttpContext).

6 голосов
/ 21 апреля 2011

Я пошел с этим в конце

For<IRequestContextStorage>()
    .HybridHttpOrThreadLocalScoped()
    .Use<RequestContextStorage>();

For<MyClass>()
    .Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());

...

public class RequestContextStorage : IRequestContextStorage
{
    readonly IDictionary<Type, object> hash;

    public RequestContextStorage()
    {
        this.hash = new Dictionary<Type, object>();
    }

    public T Get<T>() where T : class
    {
        if(this.hash.ContainsKey(typeof(T)))
            return this.hash[typeof (T)] as T;

        return null;
    }

    public void Set<T>(T instance)
    {
        this.hash[typeof (T)] = instance;
    }
}

...


static void HandleBeginRequest(object sender, EventArgs e) {

    ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());

}
3 голосов
/ 29 марта 2011

Если у вас есть только один контейнер, и у вас есть несколько запросов, вы столкнетесь с этой проблемой. Я бы предложил самостоятельно управлять экземплярами для каждого запроса, сохраняя их в HttpContext.Items.

Если вы хотите иметь доступ к нему через контейнер, создайте класс шлюза, который не содержит состояния и извлекает вашу зависимость для каждого запроса из HttpContext для вас. Зарегистрируйте это в своем контейнере и обновите зависимости на объекте запроса для вашего шлюза.

Обновление

Не могу поверить, что я упустил это из виду, что вы действительно хотите использовать HttpContextLifecycle, который будет кэшировать данный экземпляр в коллекции HttpContext.Items, где он будет доступен на протяжении всего вашего запроса. У вас по-прежнему будет несколько активных экземпляров во время одновременных запросов, но StructureMap может выяснить, какой из них возвращать, основываясь на HttpContext.Current.

...