2009-09-23 13 views
38

Tworzę ActionResult w ASP.Net MVC do wyświetlania obrazów. Po włączeniu stanu sesji usługi IIS obsługują tylko jedno żądanie naraz od tego samego użytkownika. (Jest to prawdą nie tylko w MVC.)Wyłącz stan sesji na żądanie w ASP.Net MVC

Dlatego na stronie z wieloma obrazami wywołującymi tę akcję można obsłużyć tylko jedno żądanie obrazu naraz. Jest synchroniczny.

Chciałbym, aby ten obraz był asynchroniczny - chciałbym otrzymać wiele żądań obrazów dla każdego wykonania bez konieczności poprzedniej. (Jeśli obrazy były po prostu plikami statycznymi, usługi IIS udostępniałyby je w ten sposób.)

Chciałbym wyłączyć sesję tylko dla wywołań tej akcji lub określić, że niektóre żądania nie mają stanu sesji. Ktoś wie, jak to się robi w MVC? Dzięki!

+0

http://stackoverflow.com/questions/2250940/enable-disable-session-state-per-controller-action-method –

Odpowiedz

33

Zamiast implementować do tego filtr akcji, dlaczego nie wdrożysz RouteHandler?

Oto umowa - IRouteHandler ma jedną metodę - GetHttpHandler. Po wysłaniu żądania ASP.Net MVC do kontrolera, domyślnie silnik routingu obsługuje żądanie, tworząc nowe wystąpienie MvcRouteHandler, które zwraca wartość MvcHandler. MvcHandler to implementacja IHttpHandler, która jest oznaczona interfejsem (niespodzianka!) IRequiresSessionState. Z tego powodu zwykłe żądanie korzysta z sesji.

Jeśli you follow my blog post sprawie sposobu realizacji niestandardowych RouteHandler (zamiast używania MvcRouteHandler) dla obsługujących obrazów - można pominąć powrocie sesja znakowane IHttpHandler.

To powinno uwolnić IIS od narzucenia synchroniczności. Prawdopodobnie byłby także bardziej wydajny, ponieważ pomija wszystkie warstwy kodu MVC obsługującego filtry.

+0

Wow, świetny wpis na blogu. wydaje się, że przy użyciu standardowego kontrolera MVC, zależność Session byłaby nieunikniona ..? –

+0

Tak. Na szczęście zrobili MVC jak najprościej, więc nie ma zbyt wiele pracy, aby ominąć wszystko, czego nie lubisz. – womp

+0

Dzięki! To było dla mnie bolesne, gdy wyłączyłem sesję i obraz powracający do działania zmieszał wyniki (może obrazy na stronie za pomocą tej akcji). –

6

Spróbuj podać zdjęcia z innej domeny. Więc coś jak images.mysite.com.

Zapewni to dwie korzyści: Po pierwsze, sesje są śledzone przez plik cookie, więc images.mysite.com nie będzie mieć pliku cookie. Po drugie, dostarczy ci dodatkowe dwie równoczesne prośby o odzyskanie obrazów.

Czy rozważałeś konfigurację HttpHandler do serwowania swoich zdjęć?

+0

To ciekawy pomysł.mogę wyłączyć stan sesji w całej tej aplikacji/witrynie. nadal chciałbym wiedzieć, czy możliwe jest również zgłoszenie wniosku/działania. –

1

Na naszym serwerze usługi IIS nie wiedzą nawet o sesjach - jest to stos ASP.NET, który obsługuje jedno żądanie na sesję naraz. Pliki statyczne, takie jak obrazy, nigdy nie zostaną naruszone.

Czy to możliwe, że aplikacja ASP.NET obsługuje pliki zamiast usług IIS?

+0

To prawda, to ASP wymusza sesję/synchroniczne elementy, a nie sam IIS. rozwiązaniem jest wcześniejsze uruchomienie w systemie, jak opisano powyżej. –

3

Zmiana właściwości DefaultChilderFactory na niestandardową klasę ControllerFactory. Domyślny Controller.TempDataProvider używa SessionStateTempDataProvider. możesz to zmienić.

1.Ustaw serwer.config/system.web/sessionState: mode = "Off".

2.utwórz klasę DictionaryTempDataProvider.

public class DictionaryTempDataProvider : ITempDataProvider 
    { 
    public IDictionary<string, object> LoadTempData(ControllerContext controllerContext) 
    { 
     return new Dictionary<string, object>(); 
    } 

    public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
    { 
    } 
    } 

3.Create DictionaryTempDataControllerFactory

public class DictionaryTempDataControllerFactory : DefaultControllerFactory 
    { 
    public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) 
    { 
     var controller = base.CreateController(requestContext, controllerName) as Controller; 
     if (controller!=null) 
     controller.TempDataProvider = new DictionaryTempDataProvider(); 

     return controller; 
    } 
    } 

4.In global.asax.cs Apprication_Start zestaw zdarzeń DictionaryTempDataControllerFactory.

protected void Application_Start() 
{ 
    RegisterRoutes(RouteTable.Routes); 

    ControllerBuilder.Current.SetControllerFactory(
    new DictionaryTempDataControllerFactory() 
); 
} 
46

Jeśli ktoś jest w sytuacji, byłem w, gdzie kontroler obraz rzeczywiście potrzebuje tylko do odczytu dostęp do sesji, można umieścić atrybut sessionState na kontrolerze

[SessionState(SessionStateBehavior.ReadOnly)] 

Zobacz http://msdn.microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx dłużej info.

Dzięki https://stackoverflow.com/a/4235006/372926

+0

Jest to świetny atrybut, ale działa tylko w MVC3 + – Kousha

+2

Atrybut sesji poziomu działania https://technologyatfingertips.wordpress.com/2016/06/14/session-state-on-action/ – SeeTheC

4

atrybutu sessionState jest bardzo pomocne, jeśli u używać mvc3. Jak to osiągnąć z mvc2 potrzebuje trochę więcej kodowania.

Pomysł polega na przekazaniu asp.netowi, że określone żądanie nie użyje obiektu sesji.

Więc utworzyć obsługi niestandardowych trasach obsługiwanych przez konkretne wnioski

public class CustomRouteHandler : IRouteHandler 
    { 
     public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext) 
     { 
      requestContext.HttpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly); 
      return new MvcHandler(requestContext); 
     } 
    } 

SessionStateBehavior enum ma 4 członków, należy użyć „wyłączone” lub „readonly” trybów, aby uzyskać zachowanie asynchronicznej.

Po utworzeniu tego niestandardowego programu obsługi trasy, należy się upewnić, że określone żądania są przekazywane przez ten moduł obsługi. Można to zrobić poprzez definiowanie nowych tras w Global.asax

routes.Add("Default", new Route(
       "{controller}/{action}", 
       new RouteValueDictionary(new { controller = "Home", action = "Index"}), 
       new CustomRouteHandler() 
       )); 

Dodanie tej trasy sprawia, że ​​wszystkie wnioski mają być obsługiwane przez niestandardowej klasy procedury obsługi trasy. Możesz to zrobić, definiując różne trasy.

+1

Twoje rozwiązanie jest dla mvc 3+ , czy podzieliłbyś się tym, jak to zrobić w mvc 2, gdy piszesz, że można to osiągnąć w kodowaniu mvc 2 w/trochę więcej? – adardesign

+0

Na wszelki wypadek, jeśli ma dla kogoś wartość, to nadal działa dla mnie w MVC 5.2.3.0. Musiałem jednak zmienić 'SessionStateBehaviour' na' Disabled' i dodać trasę w 'RouteConfig.cs' (metoda' RegisterRoutes (RouteCollection) ') zamiast w' Global.asax'. – MeterLongCat

0

Tworzenie nowego kontrolera

Udekoruj kontroler z [sessionState (SessionStateBehavior.Disabled)]

kod

Refactor chcesz seesion stwierdził wyłączone dla tej kontrolera

+0

nie zawsze jest możliwe do większych zastosowań – SeeTheC

3

doszedłem również w poprzek tego samego problemu i po robi R & D ten link pracował dla mnie referencyjny: https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/

  1. Utwórz niestandardowy atrybut
  2. Zastępuje metodę "GetControllerSebeBavior" obecną w klasie DefaultControllerFactory.
  3. zarejestruj go w global.aspx

1>tworzyć niestandardowe Atrybut

public sealed class ActionSessionStateAttribute : Attribute 
    { 
      public SessionStateBehavior SessionBehavior { get; private set; }   
      public ActionSessionStateAttribute(SessionStateBehavior sessionBehavior) 
      { 
       SessionBehavior = sessioBehavior; 
      } 
    } 

2. Zastąp

public class SessionControllerFactory : DefaultControllerFactory 
{  
     protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType) 
     { 
      if (controllerType == null) 
       return SessionStateBehavior.Default; 

      var actionName = requestContext.RouteData.Values["action"].ToString(); 
      Type typeOfRequest=requestContext.HttpContext.Request.RequestType.ToLower() =="get"?typeof(HttpGetAttribute):typeof(HttpPostAttribute); 
      // [Line1] 
      var cntMethods = controllerType.GetMethods() 
        .Where(m => 
        m.Name == actionName && 
        ( ( typeOfRequest == typeof(HttpPostAttribute) && 
          m.CustomAttributes.Where(a => a.AttributeType == typeOfRequest).Count()>0 
         ) 
         || 
         ( typeOfRequest == typeof(HttpGetAttribute) && 
          m.CustomAttributes.Where(a => a.AttributeType == typeof(HttpPostAttribute)).Count() == 0 
         ) 
        ) 
       ); 
      MethodInfo actionMethodInfo = actionMethodInfo = cntMethods != null && cntMethods.Count() == 1 ? cntMethods.ElementAt(0):null; 
      if (actionMethodInfo != null) 
      { 
       var sessionStateAttr = actionMethodInfo.GetCustomAttributes(typeof(ActionSessionStateAttribute), false) 
            .OfType<ActionSessionStateAttribute>() 
            .FirstOrDefault(); 

       if (sessionStateAttr != null) 
       { 
        return sessionStateAttr.Behavior; 
       } 
      } 
      return base.GetControllerSessionBehavior(requestContext, controllerType); 
} 

3. Rejestracja klasy w Global.asax

public class MvcApplication : System.Web.HttpApplication 
{ 
     protected void Application_Start() 
     { 
      // --- other code --- 
      ControllerBuilder.Current.SetControllerFactory(typeof(SessionControllerFactory)); 
     } 
} 
Powiązane problemy