Есть ли способ определить рамки для определенного образа жизни? Я пытаюсь реализовать свою собственную область видимости, которую я хочу сохранить в приложении, но внутренне я также создаю другую область, а затем запрос GetInstance возвращает экземпляр с внутренним областью.
Я подумал, могу ли я определить свой образ жизни как:
public class MyScopedLifestyle : ExecutionContextScopeLifestyle
{
public MyScopedLifestyle(bool disposeInstanceWhenScopeEnds)
: base("MyScopedLifestyle", disposeInstanceWhenScopeEnds)
{
}
protected override int Length
{
get
{
return 100;
}
}
}
И мое использование:
var container = new Container();
container.Register<IRequestData, RequestData>(new MyScopedLifestyle());
// i had hoped I could say
// container.BeginExecutionContextScope(MyScopedLifestyle)
// or something similar
// this is controlled by me
using (var scope1 = container.BeginExecutionContextScope())
{
// do some stuff
container.GetInstance<IRequestData>().RequestMarket = "en-US";
// this is done via the webapi execution scope (using simpleinjector dependency resolver)
using (var scope2 = container.BeginExecutionContextScope())
{
Assert.Equal("en-US", container.GetInstance<IRequestData>().RequestMarket); // false
}
}
Но я не уверен, как использовать свой стиль жизни при создании внутренней области выполнения.
Я действительно хочу, чтобы мой экземпляр IRequestData, используемый в scope1, является тем же самым экземпляром IRequestData внутри области2. Можно ли достичь этого с помощью SimpleInjector?
Редактировать Я удалил тот факт, что я пытаюсь создать экземпляр объекта по запросу OWIN, а не по запросу WebAPI. В идеале я пытаюсь создать:
container.RegisterOwinRequest<IRequestData, RequestData>();
Поэтому, когда я разрешаю IFoo
любом месте моего конвейера (будь то промежуточное ПО OWIN или в части WebAPI, тот же экземпляр возвращается для конкретного запроса).
Edit 2 Сменил наш IFoo/Foo/MyProperty для лучшего имени.
То, что вы пытаетесь выполнить с помощью привычного образа жизни, абсолютно возможно, но может быть и не так просто, потому что вам нужно будет хранить эту область где-то (возможно, в CallContext
) и нужно создать метод BeginMyCustomScope
который создает новую область и имеют пользовательскую реализацию Scope
которая удаляет себя из CallContext
когда CallContext
Dispose
. Я думаю, что это слишком много работы и слишком много сложностей.
Проблема возникает из-за того, что за время, когда вы хотите установить свойство RequestMarket
, не существует области запроса веб-API. Способ принудительного запуска такой области - вызвать метод GetDependencyScope
в HttpRequestMessage
:
message.GetDependencyScope();
Сразу после этого вы можете разрешить IRequestData
и он работает как ожидалось:
container.GetInstance<IRequestData>().RequestMarket = "en-US";
Однако я не уверен, доступен ли HttpRequestMessage
в этот момент времени, поэтому, если нет, я думаю, что работать с DelegatingHandler
как вы выразили в комментариях, является хорошей альтернативой.
Раньше хорошим способом передачи данных по стоп-косту были использование переменных, зависящих от потока, но это явно не удается при использовании моделей async/await, как в Web API и OWIN. Таким образом, новый способ сделать это - использовать CallContext
. Поэтому вместо использования DelegatingHandler
вы можете сделать что-то вроде этого:
container.RegisterInitializer<IRequestData>(data =>
data.RequestMarket = (string)CallContext.LogicalGetData("RequestMarketKey"));
И когда начнется запрос OWIN, вы выполните следующее:
CallContext.LogicalSetData("RequestMarketKey", "en-US");
DelegatingHandler
, так как я не хочу брать зависимость от CallContext
(только пока). Что касается объема работы, необходимого для реализации пользовательского стиля жизни, то это похоже на общий запрос ( RegisterOwinRequest
, особенно при продвижении к OWIN), поэтому мне интересно, стоит ли открывать вопрос для голосования на сайте SimpleInjector, и посмотреть куда это идет.
Foo
был единый образ жизни, или я неправильно понял твой вопрос? Вы можете зарегистрировать его какLifestyle.Singleton
. Сохранять экземпляры в приложениях обычно не нужно, особенно в случае сервисов.container.RegisterPerOwinRequest<TInterface, TConcrete>()