web-dev-qa-db-fra.com

Désactiver l'état de session par demande dans ASP.Net MVC

Je crée un ActionResult dans ASP.Net MVC pour servir des images. Lorsque l'état de session est activé, IIS ne traitera qu'une seule demande à la fois du même utilisateur. (Cela n'est pas vrai uniquement dans MVC.)

Par conséquent, sur une page avec plusieurs images rappelant cette action, une seule demande d'image peut être traitée à la fois. C'est synchrone.

Je voudrais que cette action d'image soit asynchrone - je voudrais que plusieurs demandes d'images soient exécutées sans que la précédente ne soit terminée. (Si les images n'étaient que des fichiers statiques, IIS les servirait de cette façon.)

Donc, je voudrais désactiver la session uniquement pour les appels à cette action, ou spécifier que certaines demandes n'ont pas d'état de session. Quelqu'un sait comment cela se fait dans MVC? Merci!

45
Matt Sherman

Plutôt que d'implémenter un filtre d'action pour cela, pourquoi ne pas implémenter un RouteHandler?

Voici l'affaire - IRouteHandler a une méthode - GetHttpHandler. Lorsque vous effectuez une demande ASP.Net MVC à un contrôleur, par défaut, le moteur de routage gère la demande en créant une nouvelle instance de MvcRouteHandler, qui renvoie un MvcHandler. MvcHandler est une implémentation de IHttpHandler qui est marquée avec l'interface (surprise!) IRequiresSessionState. C'est pourquoi une requête normale utilise Session.

Si vous suivez mon article de blog sur la façon d'implémenter un RouteHandler personnalisé (au lieu d'utiliser MvcRouteHandler) pour servir des images - vous pouvez ignorer le retour d'un IHttpHandler marqué par session .

Cela devrait libérer IIS de vous imposer la synchronicité. Il serait également probablement plus performant car il saute toutes les couches du code MVC traitant des filtres.

36
womp

Si quelqu'un se trouve dans la situation où je me trouvais, où votre contrôleur d'image a réellement besoin d'un accès en lecture seule à la session, vous pouvez placer l'attribut SessionState sur votre contrôleur

[SessionState(SessionStateBehavior.ReadOnly)]

Voir http://msdn.Microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx pour plus d'informations.

Merci à https://stackoverflow.com/a/4235006/372926

55
SamStephens

J'ai également rencontré le même problème et après avoir fait de la R&D, ce lien a fonctionné pour moi Référence: https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/

  1. Créer un attribut personnalisé
  2. Substituez la méthode "GetControllerSessionBehavior" présente dans la classe DefaultControllerFactory.
  3. Enregistrez-le dans global.aspx

1> Créer un attribut personnalisé

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

2. Remplacer

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. Inscrire la classe dans Global.asax

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

Essayez de diffuser les images d'un autre domaine. Donc quelque chose comme images.mysite.com.

Cela vous offrira deux avantages: premièrement, les sessions sont suivies par un cookie, donc images.mysite.com n'aura pas le cookie. Deux, il vous donnera deux demandes supplémentaires simultanées pour récupérer des images.

Avez-vous envisagé de configurer un HttpHandler pour diffuser vos images?

6
Chuck Conway

L'attribut SessionState est très utile si vous utilisez mvc3. Comment y parvenir avec mvc2 nécessite un peu plus de codage.

L'idée est de dire à asp.net que la requête spécifique n'utilisera pas d'objet de session.

Donc, créez un gestionnaire d'itinéraire personnalisé pour des demandes spécifiques

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

L'énumération SessionStateBehavior compte 4 membres, vous devez utiliser les modes "désactivé" ou "en lecture seule" pour obtenir un comportement asynchrone.

Après avoir créé ce gestionnaire d'itinéraire personnalisé, assurez-vous que vos demandes spécifiques passent par ce gestionnaire. Cela peut être fait en définissant de nouveaux itinéraires sur Global.asax

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

L'ajout de cet itinéraire fait que toutes vos demandes seront traitées par votre classe de gestionnaire d'itinéraire personnalisé. Vous pouvez le rendre spécifique en définissant différents itinéraires.

5
Serdar

Remplacez DefaultCOntrollerFactory par la classe ControllerFactory personnalisée. Controller.TempDataProvider par défaut utilise SessionStateTempDataProvider. vous pouvez le changer.

1.Définissez web.config/system.web/sessionState: mode = "Off".

2. créez la classe 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.Créez 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. Dans global.asax.cs Application_Start, ensemble d'événements DictionaryTempDataControllerFactory.

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

  ControllerBuilder.Current.SetControllerFactory(
   new DictionaryTempDataControllerFactory()
  );
}
3
takepara

Créer un nouveau contrôleur

Décorer le contrôleur avec [SessionState (SessionStateBehavior.Disabled)]

Code de refactorisation pour lequel vous voulez que la vue soit désactivée pour ce contrôleur

1
Diemar

Sur notre serveur, IIS ne connaît même pas les sessions - c'est la pile ASP.NET qui gère une requête par session à la fois. Les fichiers statiques, comme les images, ne sont jamais affectés.

Est-il possible que votre application ASP.NET serve les fichiers au lieu d'IIS?

1
orip