2016-07-26 59 views
5

Używam NHibernate w aplikacji MVC C# z MySQL. Próbuję mieć wielu użytkowników dostęp do sesji. Używam .InRequestScope() na mojej sesji, ale nadal otrzymuję:Sesja jest zamknięta Nazwa obiektu: 'ISession'. at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - Jak zatrzymać sesję przed zamknięciem przedwcześnie

System.ObjectDisposedException: Session is closed! Nazwa obiektu: "ISession". w NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() *

... lub błędy dataReader kiedy mam kolegom wszystko nawigować do tej samej strony, która korzysta z usługi w tym samym czasie.

Moja wtrysk IMasterSessionSource

Bind<IMasterSessionSource>().To<GeneralMasterSessionSource() 
          .InRequestScope(); 

Moja IContentService gdzie moje mapowania są coraz serwisowane

 //ContentService Bingings 
     Bind<IContentService>().To<ContentService>().InRequestScope(); 
     Bind<ISession>() 
      .ToMethod(
       context => 
        context.Kernel.Get<IMasterSessionSource>() 
         .ExposeConfiguration() 
         .BuildSessionFactory() 
         .OpenSession() 
      ) 
      .WhenInjectedInto<IContentService>() 
      .InRequestScope(); 

contentService

public interface IContentService 
    { 
     IQueryable<Question> Questions{ get; } 
    } 


public class ContentService : IContentService 
    { 
     private readonly ISession _session; 

     public ContentService(ISession session) 
     { 
      _session = session; 
     } 

     public IQueryable<Question> Questions 
     { 
      get { return _session.Query<Question>(); } 
     } 
    } 

DetailsService

public interface IDetailsService 
    { 
     IEnumerable<Question> PullQuestions(); 
    } 

public class DetailsService : IDetailsService 
    { 
     private readonly IContentService _contentService; 


     public GeneralService(IContentService contentService) 
     { 
      _contentService = contentService; 
     } 

     public IEnumerable<Question> PullQuestions() 
     { 
      var result = _contentService.Questions; 
      return result; 
     } 
} 

KONTROLER

public class Test: Controller 
    { 

     private readonly IContentService _contentService; 
     private readonly IGeneralService _generalService; 

     public CollegeController(IContentService contentService, IDetailsService detailsService) 
     { 
      _contentService = contentService; 
      _detailsService = detailsService; 
     } 

     public ActionResult Index() 
     { 
      { 
       var model = new HomePageContent 
       { 
        Questions = _detailsService.PullQuestions().ToList(); 
       }; 
      } 
     } 
    } 

MODEL

public class HomePageContent 
    { 
     public IEnumerable<Question> Questions { get; set; } 
    } 

WIDOK

foreach(var question in Model.Questions){ 
@Html.Raw(question.Question) 
} 

Tak więc dla pojedynczego użytkownika odwiedzającego tę stronę. Wszystko działa dobrze. Ale kiedy mutliple użytkowników visist tę samą stronę każdy się błędy:

{ „Jest już otwarty DataReader skojarzony z tym połączeniem, które muszą najpierw zostać zamknięte.”} { "Jest już otwarty DataReader skojarzony z to połączenie, które musi zostać zamknięte jako pierwsze. "} {" Brak aktualnego zapytania w czytniku danych "} {" Brak bieżącego zapytania w czytniku danych "} {" Istnieje już otwarty obiekt DataReader powiązany z tym połączeniem, który musi zostać zamknięty jako pierwszy . "} {" Sesja jest zamknięta! \ R \ nObject name: 'ISession'. "}

Dodałem już InRequestScope. Dodałem nawet tę implementację: NHibernate, and odd "Session is Closed!" errors

, ale nadal otrzymuję sesje zamknięte! błędy. Próbowałem nawet utworzyć nowy Kernel.Get, jeśli sesja została zamknięta, ale problem polega na tym, że błąd czasami pojawia się nawet wtedy, gdy sesja jest otwarta. Proszę pomóż! Jestem na skraju rozumu z tym problemem i nie mogę znaleźć rozwiązania w dowolnym miejscu. Sądzę, że nie jest możliwe, aby NHibernate obsługiwał więcej niż jedną sesję naraz.

UPDATE

Może istnieje sposób, aby czekać na sesji umieszczonym przed otwarciem nowego?

Śledzenie stosu

[ObjectDisposedException: Sesja jest zamknięty! nazwa obiektu. 'ISession'] NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() +192
NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus() +55 NHibernate.Impl.AbstractSessionImpl.CreateQuery (IQueryExpression queryExpression) +171
NHibernate.Linq.DefaultQueryProvider.PrepareQuery (wyrażenie wyrażenie IQuery & kwerendy NhLinqExpression & nhQuery) +226
NHibernate.Linq.DefaultQueryProvider.Execute (wyrażenie ekspresji) +80 NHibernate.Linq.DefaultQueryProvider.Execute (wyrażenie ekspresji) + 74 Remotion.Linq.QueryableBase 1.GetEnumerator() +193 System.Collections.Generic.List 1..ktor (IEnumerable 1 collection) +432 System.Linq.Enumerable.ToList(IEnumerable 1 source) +70
Gcus.PublicGeneralSite.Data.Core.Service.General.DetailsService.FindItems (String pozycja, kontroler String) w c: \ Users \ wd \ Desktop \ master \ Gcus.PublicGeneralSite.Data. Rdzeń \ Usługa \ Ogólne \ Szczegóły usługi.cs: 724 Gcus.Com.Web.Controllers.CoursesController.Details (Kategoria String, Element ciągu) w c: \ Users \ wd \ Desktop \ master \ Gcus.Com.Web \ Regulatory \ CoursesController.cs: 213 lambda_method (zamknięcie, ControllerBase, obiekt []) +366
System.Web.Mvc.ActionMethodDispatcher.Execute (ControllerBase sterowania, obiekt [] parametry) +87
System.Web.Mvc .ReflectedActionDescripto r.Execute (ControllerContext controllerContext, IDictionary parametry) +93
System.Web.Mvc.Async.ActionInvocation.InvokeSynchronousActionMethod() +97 System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39 (IAsyncResult asyncResult, ActionInvocation innerInvokeState) +53
System.Web.Mvc.Async.WrappedAsyncResult 2.CallEndDelegate(IAsyncResult asyncResult) +137
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +187
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResult, znacznik Object) +136
systemu .Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod (IAsyncResult asyncResult) +76
System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +164 System.Web.Mvc.Async. <> c__DisplayClass46.b__3f() +549 System.Web.Mvc.Async. <> c__DisplayClass33.b__32 (IAsyncResult asyncResult) +75
System.Web.Mvc.Async.WrappedAsyncResult 1.CallEndDelegate(IAsyncResult asyncResult) +79
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +187
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResult, znacznik Przedmiot) +136
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters (IAsyncResult asyncResult) +76
System.Web.Mvc.Async. <> c__DisplayClass2b.b__1c() +114 System.Web.Mvc.Async. <> c__DisplayClass21.b__1e (IAsyncResult asyncResult) +306
System.Web.Mvc.Async.WrappedAsyncResult 1.CallEndDelegate(IAsyncResult asyncResult) +75
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResult, znacznik Object) +72
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction (IAsyncResult asyncResult) +60
System.Web.Mvc.Controller.b__1d (IAsyncResult asyncResult, ExecuteCoreState innerState) +70
System.Web.Mvc.Async .WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +135
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176
System.Web.Mvc.Async.Asyn cResultWrapper.End (IAsyncResult asyncResult, znacznik Object) +72
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResult, znacznik Object) +51
System.Web.Mvc.Controller.EndExecuteCore (IAsyncResult asyncResult) +66 System.Web.Mvc.Controller.b__15 (IAsyncResult asyncResult, kontroler) +60
System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +98
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176
System.Web.Mvc. Async.AsyncResultWrapper.End (IAsyncResult asyncResult, Znacznik obiektu) +72
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResul t, znacznik Object) +51 System.Web.Mvc.Controller.EndExecute (IAsyncResult asyncResult) +60
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute (IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.b__5 (IAsyncResult asyncResult, ProcessRequestState innerState) +70
System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +135
System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176
System.Web.Mvc. Async.AsyncResultWrapper.End (IAsyncResult asyncResult, Znacznik obiektu) +72
System.Web.Mvc.Async.AsyncResultWrapper.End (IAsyncResult asyncResult,Przedmiot tag) +51
System.Web.Mvc.MvcHandler.EndProcessRequest (IAsyncResult asyncResult) +60 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest (IAsyncResult wynik) +59
systemu. Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399 System.Web.HttpApplication.ExecuteStep (krok IExecutionStep, Boolean & completedSynchronously) +137

+0

NHibernate z pewnością nie ma problemu z wieloma równoległymi sesjami. W rzeczywistości jest przeznaczony do obsługi właśnie tego scenariusza. Nie może jednak obsługiwać równoczesnego dostępu do _jeden_ sesji. Sesja nie jest chroniona wątkami. Wydaje się, że jesteś tego świadomy, ponieważ mówisz o InRequestScope() itp., Co brzmi jak powinno wystarczyć. Wydaje się, że jest to bardziej problem z ninject (lub jak go używasz) niż NHibernate. –

+0

Może nie poprawnie skonfigurowałeś NInject dla MVC? http://stackoverflow.com/questions/24928070/asp-net-mvc-ninject-inrequestscope –

+0

Mam go poprawnie skonfigurowany. Używam NInject.MVC5 i wstrzykiwanie ich do odpowiednich kontrolerów. Problem wydaje się być, gdy są dwie prośby o tę samą sesję. Jakoś być może trzeba poczekać, aż połączenie się zamknie. Ale nie jestem pewien. Po prostu nie mogę uwierzyć, że to takie trudne. – NeoSketo

Odpowiedz

1

I wreszcie zdobione. Wielkie uznanie dla @Oskara Berggrena za bycie zagorzałym w zrozumieniu mojego dylematu.

Problem polegał na tym, że przez cały czas dzieliłem jedną sesję.

o to, gdzie jestem wiążące otwartą sesję contentService:

Bind<IContentService>().To<ContentService>().InRequestScope(); 
     Bind<ISession>() 
      .ToMethod(
       context => 
        context.Kernel.Get<IMasterSessionSource>() 
         .ExposeConfiguration() 
         .BuildSessionFactory() 
         .OpenSession() 
      ) 
      .WhenInjectedInto<IContentService>() 
      .InRequestScope(); 

Oto gdzie Wołam tej samej sesji w contentService

public class ContentService : IContentService 
    { 
     private readonly ISession _session; 

     public ContentService(ISession session) 
     { 
      _session = session; 
     } 

     public IQueryable<Question> Questions 
     { 
      get { return _session.Query<Question>(); } 
     } 
    } 

Oto gdzie rzecz w tym. Wołam tej samej sesji w innej usługi, która jest używana w innym

public class DetailsService : IDetailsService 
    { 
     private readonly IContentService _contentService; //BAD 


     public GeneralService(IContentService contentService) 
     { 
      _contentService = contentService; //BAD 
     } 

To nie jest wątku bezpieczne, ponieważ jedna sesja otwarta jest uzyskiwanie ponownie wykorzystane. Każda usługa powinna mieć własną sesję.

Stworzyłem więc wiążące dla DetailService z własnej sesji jak tak ....

Bind<IDetailsService>() 
       .To<DetailsService>() 
       .InRequestScope(); 

      Bind<ISession>() 
       .ToMethod(
        context => 
        { 
         var lockObject = new object(); 

         lock (lockObject) 
         { 
          return context.Kernel.Get<IMasterSessionSource>() 
           .ExposeConfiguration() 
           .BuildSessionFactory() 
           .OpenSession(); 
         } 
        } 
       ) 
       .WhenInjectedInto<IDetailsService>() 
       .InRequestScope(); 

i zamiast wywoływania _contentService w tej służby dodałem sesji do jej constrictor

private readonly ISession Session; 

    public DetailsService(ISession session) 
    { 
     Session = session; 
    } 

następnie po prostu uruchomił zapytania bezpośrednio za pomocą Session.Query();

nie więcej Sesja to błędy zamknięte, nie ma już błędów DataReadera, a na końcu działający produkt.

0

jestem zaznajomiony z ninject, co ja podejrzany jest zaangażowany w problem tutaj.

Jeżeli nie możesz dowiedzieć się, jak zrobić to prawidłowo obsługiwać sesje, można rzucić okiem na NHibernate własnej obsługi sesji kontekstowych: http://nhibernate.info/doc/nhibernate-reference/architecture.html#architecture-current-session

+0

Okazuje się, że nie jest to sesje to problem ... Wydaje się, że MySQL przedwcześnie kończy sesję w innych wątkach, ale wciąż nie mam pojęcia dlaczego i nie mogę znaleźć dla tego poprawki. – NeoSketo

Powiązane problemy