2009-09-23 35 views
38

Estoy creando un ActionResult en ASP.Net MVC para servir imágenes. Con el estado de sesión habilitado, IIS solo manejará una solicitud a la vez del mismo usuario. (Esto es cierto no solo en MVC.)Deshabilitar el estado de la sesión por solicitud en ASP.Net MVC

Por lo tanto, en una página con varias imágenes que llaman a esta Acción, solo se puede procesar una solicitud de imagen a la vez. Es sincrónico.

Me gustaría esta imagen Acción para ser asíncrona: me gustaría que se ejecuten varias solicitudes de imágenes para cada una de ellas sin necesidad de completar la anterior. (Si las imágenes eran solo archivos estáticos, IIS las publicaría de esta manera.)

Por lo tanto, me gustaría deshabilitar la Sesión solo para llamadas a esa Acción, o especificar que ciertas solicitudes no tienen el estado Sesión. Alguien sabe cómo se hace esto en MVC? ¡Gracias!

+0

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

Respuesta

33

En lugar de implementar un filtro de acción para esto, ¿por qué no implementa un RouteHandler?

Aquí está el trato - IRouteHandler tiene un método - GetHttpHandler. Cuando realiza una solicitud MVC de ASP.Net a un controlador, de forma predeterminada, el motor de enrutamiento maneja la solicitud creando una nueva instancia de MvcRouteHandler, que devuelve un MvcHandler. MvcHandler es una implementación de IHttpHandler que está marcada con la interfaz (sorpresa) IRequiresSessionState. Esta es la razón por la cual una solicitud normal usa Session.

Si you follow my blog post sobre cómo implementar una costumbre RouteHandler (en lugar de utilizar MvcRouteHandler) para servir encima de imágenes - se puede omitir el retorno de una sesión de etiquetado IHttpHandler.

Esto debería liberar a IIS de la imposición de la sincronicidad en usted. También es probable que sea más eficaz porque omite todas las capas del código MVC que trata sobre los filtros.

+0

wow, gran publicación de blog. parece que usando un controlador MVC estándar, la dependencia de la sesión sería inevitable ... –

+0

Sí. Afortunadamente, hicieron MVC tan extensible como sea posible, así que no es demasiado trabajo para eludir todo lo que no te gusta. – womp

+0

¡Gracias! Fue un dolor para mí cuando apago la sesión y la imagen que devolvió la acción se mezcló con los resultados (puede imágenes en la página usando esta acción). –

6

Trate de publicar imágenes de otro dominio. Así que algo así como images.mysite.com.

Esto le proporcionará dos beneficios: uno, las sesiones son rastreados por una cookie, por lo que images.mysite.com no tendrá la cookie. Dos, le dará dos solicitudes concurrentes adicionales para recuperar imágenes.

¿Ha considerado configurar un HttpHandler para servir sus imágenes?

+0

esa es una idea interesante.Podría deshabilitar el estado de la sesión en general para esa aplicación/sitio. También me gustaría saber si la opción por solicitud/acción también es posible. –

1

En nuestro servidor, IIS ni siquiera conoce las sesiones: es la pila ASP.NET que maneja una solicitud por sesión a la vez. Los archivos estáticos, como las imágenes, nunca se ven afectados.

¿Es posible que su aplicación ASP.NET esté sirviendo los archivos en lugar de IIS?

+0

es correcto, es ASP el que impone la sesión/cosas sincrónicas, no el propio IIS. la solución es ir más temprano en la tubería como womp descrito anteriormente. –

3

Cambie DefaultCOntrollerFactory a la clase Custom ControllerFactory. Default Controller.TempDataProvider usa SessionStateTempDataProvider. Tú puedes cambiarlo.

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

2.create clase 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 event set DictionaryTempDataControllerFactory.

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

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

Si alguno está en la situación en que estaba, donde su controlador de imagen realmente necesita acceso de solo lectura a la sesión, puede poner el atributo SessionState en su controlador

[SessionState(SessionStateBehavior.ReadOnly)] 

Ver http://msdn.microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx para obtener más información

Gracias a https://stackoverflow.com/a/4235006/372926

+0

Es un gran atributo, sin embargo solo funciona en MVC3 + – Kousha

+2

Atributo de sesión de nivel de acción https://technologyatfingertips.wordpress.com/2016/06/14/session-state-on-action/ – SeeTheC

4

atributo SessionState es bastante útil si el uso u MVC3. Cómo lograr esto con mvc2 necesita un poco más de codificación.

La idea es decirle al asp.net que la solicitud específica no usará el objeto de sesión.

Por lo tanto, crear un controlador de ruta personalizada para las solicitudes específicas

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

SessionStateBehavior enumeración tiene 4 miembros, debe utilizar los modos de "sólo lectura" "desactivado" o para obtener un comportamiento asíncrono.

Después de crear este controlador de ruta personalizado, asegúrese de que sus solicitudes específicas pasen por este controlador. Esto se puede hacer a través de la definición de nuevas rutas en Global.asax

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

La adición de esta ruta hace que todas sus peticiones para ser manejados por su clase de controlador de ruta personalizada. Puedes hacerlo específico definiendo diferentes rutas.

+1

Su solución es para mvc 3+ , ¿compartirías cómo hacerlo en mvc 2 mientras escribes que se podría lograr en mvc 2 con poco más de codificación? – adardesign

+0

Solo en caso de que sea de valor para cualquier persona, esto todavía funciona para mí en MVC 5.2.3.0. Sin embargo, tuve que cambiar el 'SessionStateBehaviour' a' Disabled' y agregar la ruta en 'RouteConfig.cs' (método' RegisterRoutes (RouteCollection) ') en lugar de' Global.asax'. – MeterLongCat

0

Crear nuevo controlador

controladora Decorar con [SessionState (SessionStateBehavior.Disabled)]

código

Refactor desea seesion declaró inhabilitado para a ese controlador

+0

no siempre es factible para una aplicación más grande – SeeTheC

3

También me encontré con el mismo problema y después de haciendo R & D este enlace trabajó para mí Referencia: https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/

  1. Crear atributo personalizado
  2. Reemplazar el método "GetControllerSessionBehavior" presente en la clase DefaultControllerFactory.
  3. registrarla en global.aspx

1>Crear atributo personalizada

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

2. Anulación

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. Registro de clase en Global.asax

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