Wydaje kiedy uruchomić zadanie w osobnym wątku w ASP.NET MVC, SimpleInjector tworzy nową instancję DbContext dla każdego połączenia.
Zachowanie RegisterPerWebRequest
życia Simple wtryskiwacza v1.5 i poniżej jest powrót przejściową przypadek, gdy wystąpienia są o poza ramach żądania sieci (gdzie HttpContext.Current
jest zerowa). Zwrócenie przejściowej instancji było wadą projektową w prostym wtryskiwaczu, ponieważ ułatwia to ukrycie niewłaściwego użycia. Version 1.6 of the Simple Injector wygeneruje wyjątek zamiast niepoprawnego zwrócenia instancji przejściowej, aby wyraźnie stwierdzić, że źle skonfigurowałeś kontener.
Chociaż niektóre biblioteki IoC (na przykład StructureMap) mają mieszane życia dla per-thread-per-WebRequest wydaje Proste Injector ma nie jeden
Prawdą jest, że prosty Injector nie ma wbudowanej obsługi mieszanego stylu życia z kilku powodów. Przede wszystkim jest to dość egzotyczna funkcja, której nie potrzebuje wiele osób. Po drugie, możesz łączyć ze sobą dwa lub trzy style życia, dzięki czemu będzie to prawie nieskończona kombinacja hybryd.I na koniec łatwo zarejestrować się samemu.
Chociaż można mieszać Per Web Request z Per Thread życia, prawdopodobnie byłoby lepiej, kiedy wymieszać Per internetowej Zamówienie z Per Lifetime Scope, ponieważ z zakresem całokształt jawnie rozpoczęcia i zakończenia zakresu (i może wyrzucać DbContext
gdy zakres kończy) .
Od Simple Injector 2 można łatwo łączyć dowolną liczbę stylów życia, korzystając z metody . Oto przykład:
var hybridLifestyle = Lifestyle.CreateHybrid(
() => HttpContext.Current != null,
new WebRequestLifestyle(),
new LifetimeScopeLifestyle());
// Register as hybrid PerWebRequest/PerLifetimeScope.
container.Register<DbContext, MyDbContext>(hybridLifestyle);
Jest jeszcze inna kwestia Stackoverflow, że idzie do tego tematu nieco głębiej, może chcesz przyjrzeć: Simple Injector: multi-threading in MVC3 ASP.NET
UPDATE
słów o aktualizacji. Jesteś prawie na miejscu. Polecenia działające w wątku w tle muszą być uruchamiane w zasięgu Lifetime Scope, więc będziesz musiał uruchomić go jawnie. Sztuką jest tutaj wywołanie BeginLifetimeScope
w nowym wątku, ale przed faktycznym tworzeniem obsługi komend (i jej zależności). Innymi słowy, najlepszym sposobem na to jest wewnątrz dekoratora.
Najprostszym rozwiązaniem jest, aby zaktualizować AsyncCommandHandlerDecorator
dodać zakresu:
public class AsyncCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand> where TCommand : ICommand
{
private readonly Container _container;
private readonly Func<ICommandHandler<TCommand>> _factory;
public AsyncCommandHandlerDecorator(Container container,
Func<ICommandHandler<TCommand>> factory)
{
_container = container;
_factory = factory;
}
public void Handle(TCommand command)
{
ThreadPool.QueueUserWorkItem(_ =>
{
using (_container.BeginLifetimeScope())
{
// Create new handler in this thread
// and inside the lifetime scope.
var handler = _factory();
handler.Handle(command);
}
});
}
}
purystów że popierają zasady SOLID będzie krzyczeć, że ta klasa jest naruszenie Single Responsibility Principle, ponieważ dekorator zarówno uruchamia polecenia w nowym wątku i rozpoczyna nowy zakres życia. Nie martwiłbym się tym zbytnio, ponieważ uważam, że istnieje bliski związek między rozpoczynaniem wątku tła a uruchamianiem zakresu życia (nie używałbyś go bez drugiego). Ale nadal można łatwo opuścić AsyncCommandHandlerDecorator
nietknięty i utworzyć nowy LifetimeScopedCommandHandlerDecorator
następująco:
public class LifetimeScopedCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand> where TCommand : ICommand
{
private readonly Container _container;
private readonly Func<ICommandHandler<TCommand>> _factory;
public LifetimeScopedCommandHandlerDecorator(Container container,
Func<ICommandHandler<TCommand>> factory)
{
_container = container;
_factory = factory;
}
public void Handle(TCommand command)
{
using (_container.BeginLifetimeScope())
{
// The handler must be created inside the lifetime scope.
var handler = _factory();
handler.Handle(command);
}
}
}
Kolejność, w jakiej te dekoratorzy są zarejestrowane jest oczywiście niezbędny, ponieważ AsyncCommandHandlerDecorator
musi owinąć LifetimeScopedCommandHandlerDecorator
. Oznacza to, że rejestracja LifetimeScopedCommandHandlerDecorator
musi pochodzić pierwszy:
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(LifetimeScopedCommandHandlerDecorator<>),
backgroundCommandCondition);
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(AsyncCommandHandlerDecorator<>),
backgroundCommandCondition);
This old Stackoverflow question rozmowy na ten temat bardziej szczegółowo. Powinieneś zdecydowanie rzucić okiem.
Powiązane: http://stackoverflow.com/questions/11041601/simple-injector-multi-threading-in-mvc3-asp-net – Steven
Powiązane: http://stackoverflow.com/questions/10304023/simpleinjector-is -to-right-way-to-registerermanyforopengeneric-when-i-have – Steven