Moim celem jest posiadanie jednego kontekstu danych (MainDbContext) na żądanie HTTP w ASP.NET MVC i usuwanie kontekstu danych po zakończeniu żądania.

Używam następującej konfiguracji StructureMap:

public static class ContainerConfigurer
{
    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<MainDbContext>().HttpContextScoped();
        });
    }
}

Ilekroć potrzebuję MainDbContext, używam tego kodu:

var dbContext = ObjectFactory.GetInstance<MainDbContext>();

Działa to zgodnie z oczekiwaniami: tylko jeden kontekst danych jest tworzony na żądanie HTTP. Problem polega na tym, że MainDbContext nie jest usuwany na końcu żądania.

Jak skonfigurować obiekt ObjectFactory, aby usuwał kontekst danych po zakończeniu żądania HTTP? Czy jest to po prostu coś, co muszę zrobić ręcznie, używając Application_EndRequest() w Global.asax.

Aktualizuj

Właśnie próbowałem dodać następujący kod do Global.asax:

protected virtual void Application_EndRequest()
{
    ObjectFactory.GetInstance<MainDbContext>().Dispose();
}

Zgodnie z oczekiwaniami rozwiązuje to problem. Wciąż jednak zastanawiam się, czy jest jakiś sposób, aby zrobić to automatycznie za pomocą StructureMap.

10
devuxer 17 czerwiec 2011, 23:07

2 odpowiedzi

Najlepsza odpowiedź

Zamiast:

x.For<MainDbContext>().HttpContextScoped();

Próbować:

x.For<MainDbContext>().HttpContextScoped().Use(() => new MainDbContext());

Również normalnie są to klasy repozytorium, które wymagają kontekstu db. Więc zamiast ObjectFactory.GetInstance<MainDbContext>(); niech twoje repozytoria wezmą jakiś kontekst bazy danych interfejsu i skonfigurują StructureMap, aby wstrzyknąć do nich MainDbContext. Następnie spraw, aby StructureMap wstrzyknął repozytoria do kontrolerów, ...

W Application_EndRequest:

protected void Application_EndRequest()
{
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
9
Darin Dimitrov 17 czerwiec 2011, 23:25
Nie robi różnicy. Dispose() nadal nie jest sprawdzany.
 – 
devuxer
17 czerwiec 2011, 23:14
Jak sugerujesz, już wstrzykuję kontekst danych do moich repozytoriów/usług. Problem polega na tym, że mam również ActionFilters, Validators i MembershipProvider, które wymagają kontekstu danych, a ponieważ te obiekty są tworzone automatycznie przez ASP.NET MVC (podobnie jak kontrolery), używam StructureMap do zarządzania okresem istnienia mojego kontekst danych. Jeśli masz lepsze rozwiązanie, daj mi znać.
 – 
devuxer
17 czerwiec 2011, 23:23
@DanM, masz rację, przetestowałem to i wygląda na to, że StructureMap nie usuwa automatycznie obiektów objętych zakresem IDisposable HttpContext na końcu żądania. Wywołanie ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects w Application_EndRequest jest prawdopodobnie najlepszym sposobem zapewnienia, że ​​tak się stanie dla wszystkich obiektów.
 – 
Darin Dimitrov
17 czerwiec 2011, 23:26
Kiedy wywołuję metodę „ReleaseAndDisposeAllHttpScopedObjects”, jest to dla mnie tylko część rozwiązania; Muszę również dodać ręczne usuwanie jednostki pracy (LightSpeed) w następujący sposób: StructureMap.ObjectFactory.GetInstance().Dispose(). Nie wiem dokładnie dlaczego, ale jeśli nie wywołam ostatniego, to jednostka prac nie jest zlikwidowana, a połączenia nie zwolnione.
 – 
Samuel
11 styczeń 2012, 01:19

Korzystanie z zagnieżdżonego kontenera to jedyny sposób pobierz mapę struktury, aby automatycznie usuwać obiekty. Jeśli nie używasz tej techniki, jedynym sposobem jest samodzielne pozbycie się obiektów w sposób opisany w OP (wyciągnięcie obiektu z pojemnika i wyrzucenie go; zobacz ten przykład NHibernate dla jednego sposobu wykonania) lub zakres obiektu do HttpRequest i wywołanie ReleaseAndDisposeAllHttpScopedObjects zgodnie z opisem Darina.

5
PHeiberg 18 czerwiec 2011, 16:12
+1 i dzięki, PHeiberg. Zagnieżdżony kontener wygląda na interesujące rozwiązanie, ale gdybym użył próbki kodu, z którą się połączyłeś w mojej sytuacji, wierzę, że usunęłoby to mój kontekst danych kilka razy na żądanie. Moim celem jest posiadanie tylko jednego kontekstu danych na żądanie. Wygląda też na to, że zaowocowałoby to znacznie większą ilością kodu. Więc myślę, że zostanę przy rozwiązaniu Darina. Proszę mnie poprawić, jeśli nie rozumiem.
 – 
devuxer
18 czerwiec 2011, 21:24
Korzystając z zagnieżdżonego kontenera, utworzysz jedno wystąpienie zagnieżdżonego kontenera na żądanie i pozbędziesz się go na końcu żądania. Usunięcie kontenera zagnieżdżonego spowoduje usunięcie wszystkich utworzonych w nim obiektów przejściowych. Nie widziałem żadnych przykładów używania zagnieżdżonych kontenerów z ASP.NET MVC lub Webforms. Przykładem Jeremy'ego jest użycie Fubu i NHibernate (codebetter. com/jeremymiller/2010/01/06/…). W przypadku prostych scenariuszy droga Darina lub Twoja jest prawdopodobnie najłatwiejsza. Używałem ich we wszystkich moich aplikacjach internetowych z SM.
 – 
PHeiberg
19 czerwiec 2011, 12:20
1
Dodałbym tylko, jak wspomniano w połączonym artykule, że zagnieżdżony kontener „wyciąga” wszystkie instancje objęte zakresem jako coś innego niż przejściowe (obiekty objęte zakresem HttpContext, obiekty objęte zakresem ThreadLocalStorage itp.) Z kontenera nadrzędnego. Te obiekty nie są usuwane z zagnieżdżonego kontenera. Więc jeśli moje zrozumienie jest dobre, obiekty HttpContextScoped i tak nie zostaną usunięte.
 – 
Tomasz Jaskuλa
30 sierpień 2012, 18:13
1
— w przypadku korzystania z kontenera zagnieżdżonego zakres kontekstu Db jest określany jako przejściowy w kontenerze zagnieżdżonym, a nie HttpContextScoped.
 – 
PHeiberg
6 wrzesień 2012, 12:05
PHeiberg, dziękuję za wyjaśnienie Nie jestem native speakerem. Czy to oznacza, że ​​DbContext po wyciągnięciu z kontenera podrzędnego będzie miał przejściowy okres istnienia i zostanie usunięty, gdy kontener podrzędny zostanie usunięty. Nawet jeśli DbContext został zarejestrowany z okresem istnienia HttpContextSoped ?
 – 
Tomasz Jaskuλa
6 wrzesień 2012, 14:04