我希望这个图像Action是异步的 - 我希望多个图像请求可以每个执行而不需要前一个完成。(如果这些图像只是静态文件,则IIS将以这种方式提供它们。)
因此,我想禁用那个Action的会话,或指定某些请求没有会话状态。有人知道在MVC中如何实现吗?谢谢!
[SessionState(SessionStateBehavior.ReadOnly)]
了解更多信息,请参见http://msdn.microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx。
不要为此实现一个动作筛选器,为什么不实现一个 RouteHandler
呢?
这里的问题是 - IRouteHandler
只有一个方法 - GetHttpHandler
。当你向控制器发送一个 ASP.Net MVC 请求时,默认情况下,路由引擎通过创建 MvcRouteHandler
的新实例来处理请求,该实例返回一个 MvcHandler
。 MvcHandler
是标记有(惊喜!)IRequiresSessionState
接口的 IHttpHandler
实现。这就是为什么普通请求使用 Session 的原因。
如果按照我的博客文章实现用于提供图像的自定义 RouteHandler
(而不是使用 MvcRouteHandler)- 你可以跳过返回带有 Session 标签的 IHttpHandler
。
这应该使 IIS 不再强加同步功能于你。 这也可能更高效,因为它跳过了处理过滤器的所有 MVC 代码的层。
1> 创建自定义属性
public sealed class ActionSessionStateAttribute : Attribute
{
public SessionStateBehavior SessionBehavior { get; private set; }
public ActionSessionStateAttribute(SessionStateBehavior sessionBehavior)
{
SessionBehavior = sessioBehavior;
}
}
2. 覆盖
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. 在 Global.asax 中注册类
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// --- other code ---
ControllerBuilder.Current.SetControllerFactory(typeof(SessionControllerFactory));
}
}
如果您使用mvc3,SessionState属性非常有用。如何在mvc2中实现这一点需要更多的编码。
想法是告诉asp.net特定请求不会使用会话对象。
因此,为特定请求创建自定义路由处理程序。
public class CustomRouteHandler : IRouteHandler
{
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly);
return new MvcHandler(requestContext);
}
}
SessionStateBehavior 枚举有4个成员,您应该使用“disabled”或“readonly”模式来获取异步行为。
创建这个自定义路由处理程序后,请确保您的特定请求经过此处理程序。这可以通过在 Global.asax 中定义新路由来实现。
routes.Add("Default", new Route(
"{controller}/{action}",
new RouteValueDictionary(new { controller = "Home", action = "Index"}),
new CustomRouteHandler()
));
添加此路由可以使所有请求都由您的自定义路由处理程序类处理。您可以通过定义不同的路由使其具体化。
SessionStateBehaviour
更改为Disabled
并将路由添加到RouteConfig.cs
(方法RegisterRoutes(RouteCollection)
)中,而不是在Global.asax
中。 - MeterLongCat将DefaultControllerFactory更改为自定义的ControllerFactory类。默认Controller.TempDataProvider使用SessionStateTempDataProvider,您可以更改它。
1.设置web.config/system.web/sessionState:mode="Off"。
2.创建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. 创建 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. 在 global.asax.cs 的 Application_Start 事件中设置 DictionaryTempDataControllerFactory。
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(
new DictionaryTempDataControllerFactory()
);
}
public class AspNetSessionFilterModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostMapRequestHandler += OnPostMapRequestHandler;
}
private void OnPostMapRequestHandler(object sender, EventArgs e)
{
var context = (sender as HttpApplication).Context;
DisableSessionForSomeRequests(context);
}
private void DisableSessionForSomeRequests(HttpContext context)
{
if ("~/Services/MyService.svc".Equals(context.Request.AppRelativeCurrentExecutionFilePath, StringComparison.InvariantCultureIgnoreCase))
{
context.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Disabled);
}
}
public void Dispose()
{ }
}