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!
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.
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.
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é
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));
}
}
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?
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.
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()
);
}
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
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?