I just discovered why all ASP.Net websites are slow, and I am trying to work out what to do about it

前端 未结 10 770
情话喂你
情话喂你 2020-11-22 07:53

I just discovered that every request in an ASP.Net web application gets a Session lock at the beginning of a request, and then releases it at the end of the request!

10条回答
  •  独厮守ぢ
    2020-11-22 08:27

    For ASPNET MVC, we did the following:

    1. By default, set SessionStateBehavior.ReadOnly on all controller's action by overriding DefaultControllerFactory
    2. On controller actions that need writing to session state, mark with attribute to set it to SessionStateBehavior.Required

    Create custom ControllerFactory and override GetControllerSessionBehavior.

        protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
        {
            var DefaultSessionStateBehaviour = SessionStateBehaviour.ReadOnly;
    
            if (controllerType == null)
                return DefaultSessionStateBehaviour;
    
            var isRequireSessionWrite =
                controllerType.GetCustomAttributes(inherit: true).FirstOrDefault() != null;
    
            if (isRequireSessionWrite)
                return SessionStateBehavior.Required;
    
            var actionName = requestContext.RouteData.Values["action"].ToString();
            MethodInfo actionMethodInfo;
    
            try
            {
                actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            }
            catch (AmbiguousMatchException)
            {
                var httpRequestTypeAttr = GetHttpRequestTypeAttr(requestContext.HttpContext.Request.HttpMethod);
    
                actionMethodInfo =
                    controllerType.GetMethods().FirstOrDefault(
                        mi => mi.Name.Equals(actionName, StringComparison.CurrentCultureIgnoreCase) && mi.GetCustomAttributes(httpRequestTypeAttr, false).Length > 0);
            }
    
            if (actionMethodInfo == null)
                return DefaultSessionStateBehaviour;
    
            isRequireSessionWrite = actionMethodInfo.GetCustomAttributes(inherit: false).FirstOrDefault() != null;
    
             return isRequireSessionWrite ? SessionStateBehavior.Required : DefaultSessionStateBehaviour;
        }
    
        private static Type GetHttpRequestTypeAttr(string httpMethod) 
        {
            switch (httpMethod)
            {
                case "GET":
                    return typeof(HttpGetAttribute);
                case "POST":
                    return typeof(HttpPostAttribute);
                case "PUT":
                    return typeof(HttpPutAttribute);
                case "DELETE":
                    return typeof(HttpDeleteAttribute);
                case "HEAD":
                    return typeof(HttpHeadAttribute);
                case "PATCH":
                    return typeof(HttpPatchAttribute);
                case "OPTIONS":
                    return typeof(HttpOptionsAttribute);
            }
    
            throw new NotSupportedException("unable to determine http method");
        }
    

    AcquireSessionLockAttribute

    [AttributeUsage(AttributeTargets.Method)]
    public sealed class AcquireSessionLock : Attribute
    { }
    

    Hook up the created controller factory in global.asax.cs

    ControllerBuilder.Current.SetControllerFactory(typeof(DefaultReadOnlySessionStateControllerFactory));
    

    Now, we can have both read-only and read-write session state in a single Controller.

    public class TestController : Controller 
    {
        [AcquireSessionLock]
        public ActionResult WriteSession()
        {
            var timeNow = DateTimeOffset.UtcNow.ToString();
            Session["key"] = timeNow;
            return Json(timeNow, JsonRequestBehavior.AllowGet);
        }
    
        public ActionResult ReadSession()
        {
            var timeNow = Session["key"];
            return Json(timeNow ?? "empty", JsonRequestBehavior.AllowGet);
        }
    }
    

    Note: ASPNET session state can still be written to even in readonly mode and will not throw any form of exception (It just doesn't lock to guarantee consistency) so we have to be careful to mark AcquireSessionLock in controller's actions that require writing session state.

提交回复
热议问题