最近项目用到了RedisSessionStateProvider来保存session,发现比内存session慢,后来慢慢了解,发现asp.net session是有锁的。我在文章 你的项目真的需要Session吗? redis保存session性能怎么样?也提到一些观点,本来打算在那篇文章补充一些类容,后来想了一下,还是重写一个短文吧。有关session 管道流程大家 可以参考 Asp.net Session认识加强-Session究竟是如何存储你知道吗?

我们的mvc程序都是有路由信息,那么就离不开UrlRoutingModule 该code如下:

namespace System.Web.Routing {
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Web.Security; [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class UrlRoutingModule : IHttpModule {
private static readonly object _contextKey = new Object();
private static readonly object _requestDataKey = new Object();
private RouteCollection _routeCollection; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
Justification = "This needs to be settable for unit tests.")]
public RouteCollection RouteCollection {
get {
if (_routeCollection == null) {
_routeCollection = RouteTable.Routes;
}
return _routeCollection;
}
set {
_routeCollection = value;
}
} protected virtual void Dispose() {
} protected virtual void Init(HttpApplication application) { //////////////////////////////////////////////////////////////////
// Check if this module has been already addded
if (application.Context.Items[_contextKey] != null) {
return; // already added to the pipeline
}
application.Context.Items[_contextKey] = _contextKey; // Ideally we would use the MapRequestHandler event. However, MapRequestHandler is not available
// in II6 or IIS7 ISAPI Mode. Instead, we use PostResolveRequestCache, which is the event immediately
// before MapRequestHandler. This allows use to use one common codepath for all versions of IIS.
application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
} private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
HttpContextBase context = new HttpContextWrapper(app.Context);
PostResolveRequestCache(context);
} [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
public virtual void PostMapRequestHandler(HttpContextBase context) {
// Backwards compat with 3.5 which used to have code here to Rewrite the URL
} public virtual void PostResolveRequestCache(HttpContextBase context) {
// Match the incoming URL against the route table
RouteData routeData = RouteCollection.GetRouteData(context); // Do nothing if no route found
if (routeData == null) {
return;
} // If a route was found, get an IHttpHandler from the route's RouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
SR.GetString(SR.UrlRoutingModule_NoRouteHandler)));
} // This is a special IRouteHandler that tells the routing module to stop processing
// routes and to let the fallback handler handle the request.
if (routeHandler is StopRoutingHandler) {
return;
} RequestContext requestContext = new RequestContext(context, routeData); // Dev10 766875 Adding RouteData to HttpContext
context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
SR.GetString(SR.UrlRoutingModule_NoHttpHandler),
routeHandler.GetType()));
} if (httpHandler is UrlAuthFailureHandler) {
if (FormsAuthenticationModule.FormsAuthRequired) {
UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
return;
}
else {
throw new HttpException(, SR.GetString(SR.Assess_Denied_Description3));
}
} // Remap IIS7 to our handler
context.RemapHandler(httpHandler);
} #region IHttpModule Members
void IHttpModule.Dispose() {
Dispose();
} void IHttpModule.Init(HttpApplication application) {
Init(application);
}
#endregion
}
}

在PostResolveRequestCache方法中   IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 这么一句。这里的routeHandler其实默认是MvcRouteHandler,所以智力其实是调用MvcRouteHandler的GetHttpHandler方法。

MvcRouteHandler的code:

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

using System.Web.Mvc.Properties;
using System.Web.Routing;
using System.Web.SessionState; namespace System.Web.Mvc
{
public class MvcRouteHandler : IRouteHandler
{
private IControllerFactory _controllerFactory; public MvcRouteHandler()
{
} public MvcRouteHandler(IControllerFactory controllerFactory)
{
_controllerFactory = controllerFactory;
} protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
} protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
{
string controllerName = (string)requestContext.RouteData.Values["controller"];
if (String.IsNullOrWhiteSpace(controllerName))
{
throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
} IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
} #region IRouteHandler Members IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return GetHttpHandler(requestContext);
} #endregion
}
}

在MvcRouteHandler中GetHttpHandler设置SessionStateBehavior:

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}

SessionStateBehavior的值默认来源于DefaultControllerFactory的GetControllerSessionBehavior方法,有SessionStateAttribute特性就取其值,否者默认的SessionStateBehavior.Default

 SessionStateBehavior IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (String.IsNullOrEmpty(controllerName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
} Type controllerType = GetControllerType(requestContext, controllerName);
return GetControllerSessionBehavior(requestContext, controllerType);
} protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return SessionStateBehavior.Default;
} return _sessionStateCache.GetOrAdd(
controllerType,
type =>
{
var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)
.OfType<SessionStateAttribute>()
.FirstOrDefault(); return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;
});
}

那么HttpContext.SetSessionStateBehavior方法又是如何实现的:

  internal SessionStateBehavior SessionStateBehavior { get; set; }

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
Justification = "An internal property already exists. This method does additional work.")]
public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior) {
if (_notificationContext != null && _notificationContext.CurrentNotification >= RequestNotification.AcquireRequestState) {
throw new InvalidOperationException(SR.GetString(SR.Invoke_before_pipeline_event, "HttpContext.SetSessionStateBehavior", "HttpApplication.AcquireRequestState"));
} SessionStateBehavior = sessionStateBehavior;
}

其实很简单,就是设置了一个属性,这里还有一个ReadOnlySessionState属性很重要,他需要读取SessionStateBehavior属性。由于MvcHandler 默认继承了IRequiresSessionState接口但是没有继承IReadOnlySessionState,

所以默认RequiresSessionState为true,ReadOnlySessionState为false。

public IHttpHandler Handler {
get { return _handler;}
set {
_handler = value;
_requiresSessionStateFromHandler = false;
_readOnlySessionStateFromHandler = false;
InAspCompatMode = false;
if (_handler != null) {
if (_handler is IRequiresSessionState) {
_requiresSessionStateFromHandler = true;
}
if (_handler is IReadOnlySessionState) {
_readOnlySessionStateFromHandler = true;
}
Page page = _handler as Page;
if (page != null && page.IsInAspCompatMode) {
InAspCompatMode = true;
}
}
}
} // session state support
private bool _requiresSessionStateFromHandler;
internal bool RequiresSessionState {
get {
switch (SessionStateBehavior) {
case SessionStateBehavior.Required:
case SessionStateBehavior.ReadOnly:
return true;
case SessionStateBehavior.Disabled:
return false;
case SessionStateBehavior.Default:
default:
return _requiresSessionStateFromHandler;
}
}
} private bool _readOnlySessionStateFromHandler;
internal bool ReadOnlySessionState {
get {
switch (SessionStateBehavior) {
case SessionStateBehavior.ReadOnly:
return true;
case SessionStateBehavior.Required:
case SessionStateBehavior.Disabled:
return false;
case SessionStateBehavior.Default:
default:
return _readOnlySessionStateFromHandler;
}
}
}

在SessionStateModule的GetSessionStateItem方法里面有如下code:

这里我们用的是RedisSessionStateProvider,其code如下:

//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// using System;
using System.Web;
using System.Web.SessionState; namespace Microsoft.Web.Redis
{
public class RedisSessionStateProvider : SessionStateStoreProviderBase
{
// We want to release lock (if exists) during EndRequest, to do that we need session-id and lockId but EndRequest do not have these parameter passed to it.
// So we are going to store 'sessionId' and 'lockId' when we acquire lock. so that EndRequest can release lock at the end.
// If we removed the lock before that than we will clear these by our self so that EndRequest won't do that again (only Release item exclusive does that).
internal string sessionId;
internal object sessionLockId;
private const int FROM_MIN_TO_SEC = ; internal static ProviderConfiguration configuration;
internal static object configurationCreationLock = new object();
internal ICacheConnection cache; private static object _lastException = new object(); /// <summary>
/// We do not want to throw exception from session state provider because this will break customer application and they can't get chance to handel it.
/// So if exception occurs because of some problem we store it in HttpContext using a key that we know and return null to customer. Now, when customer
/// get null from any of session operation they should call this method to identify if there was any exception and because of that got null.
/// </summary>
public static Exception LastException
{
get
{
if (HttpContext.Current != null)
{
return (Exception) HttpContext.Current.Items[_lastException];
}
return null;
} set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[_lastException] = value;
}
}
} private void GetAccessToStore(string id)
{
if (cache == null)
{
cache = new RedisConnectionWrapper(configuration, id);
}
else
{
cache.Keys.RegenerateKeyStringIfIdModified(id, configuration.ApplicationName);
}
} public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
if (config == null)
{
throw new ArgumentNullException("config");
} if (name == null || name.Length == )
{
name = "MyCacheStore";
} if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "Redis as a session data store");
} base.Initialize(name, config); // If configuration exists then use it otherwise read from config file and create one
if (configuration == null)
{
lock (configurationCreationLock)
{
if (configuration == null)
{
configuration = ProviderConfiguration.ProviderConfigurationForSessionState(config);
}
}
}
} public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
{
//We don't receive notifications when cache items expire, so we can't support Session_OnEnd.
return false;
} public override void InitializeRequest(HttpContext context)
{
//Not need. Initializing in 'Initialize method'.
} public override void Dispose()
{
//Not needed. Cleanup is done in 'EndRequest'.
} public override void EndRequest(HttpContext context)
{
try
{
// This check is required for unit tests to work
int sessionTimeoutInSeconds;
if (context != null && context.Session != null)
{
sessionTimeoutInSeconds = context.Session.Timeout * FROM_MIN_TO_SEC;
}
else
{
sessionTimeoutInSeconds = (int)configuration.SessionTimeout.TotalSeconds;
} if (sessionId != null && sessionLockId != null)
{
GetAccessToStore(sessionId);
cache.TryReleaseLockIfLockIdMatch(sessionLockId, sessionTimeoutInSeconds);
LogUtility.LogInfo("EndRequest => Session Id: {0}, Session provider object: {1} => Lock Released with lockId {2}.", sessionId, this.GetHashCode(), sessionLockId);
sessionId = null;
sessionLockId = null;
}
cache = null;
}
catch (Exception e)
{
LogUtility.LogError("EndRequest => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
} public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
{
//Creating empty session store data and return it.
LogUtility.LogInfo("CreateNewStoreData => Session provider object: {0}.", this.GetHashCode());
return new SessionStateStoreData(new ChangeTrackingSessionStateItemCollection(), new HttpStaticObjectsCollection(), timeout);
} public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
try
{
if (LastException == null)
{
LogUtility.LogInfo("CreateUninitializedItem => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
ISessionStateItemCollection sessionData = new ChangeTrackingSessionStateItemCollection();
sessionData["SessionStateActions"] = SessionStateActions.InitializeItem;
GetAccessToStore(id);
// Converting timout from min to sec
cache.Set(sessionData, (timeout * FROM_MIN_TO_SEC));
}
}
catch (Exception e)
{
LogUtility.LogError("CreateUninitializedItem => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
} public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
LogUtility.LogInfo("GetItem => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
return GetItemFromSessionStore(false, context, id, out locked, out lockAge, out lockId, out actions);
} public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
LogUtility.LogInfo("GetItemExclusive => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
return GetItemFromSessionStore(true, context, id, out locked, out lockAge, out lockId, out actions);
} private SessionStateStoreData GetItemFromSessionStore(bool isWriteLockRequired, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
try
{
SessionStateStoreData sessionStateStoreData = null;
locked = false;
lockAge = TimeSpan.Zero;
lockId = ;
actions = SessionStateActions.None;
if (id == null)
{
return null;
}
GetAccessToStore(id);
ISessionStateItemCollection sessionData = null; int sessionTimeout;
bool isLockTaken = false;
//Take read or write lock and if locking successful than get data in sessionData and also update session timeout
if (isWriteLockRequired)
{
isLockTaken = cache.TryTakeWriteLockAndGetData(DateTime.Now, (int)configuration.RequestTimeout.TotalSeconds, out lockId, out sessionData, out sessionTimeout);
sessionId = id; // signal that we have to remove lock in EndRequest
sessionLockId = lockId; // save lockId for EndRequest
}
else
{
isLockTaken = cache.TryCheckWriteLockAndGetData(out lockId, out sessionData, out sessionTimeout);
} if (isLockTaken)
{
locked = false;
LogUtility.LogInfo("GetItemFromSessionStore => Session Id: {0}, Session provider object: {1} => Lock taken with lockId: {2}", id, this.GetHashCode(), lockId);
}
else
{
sessionId = null;
sessionLockId = null;
locked = true;
LogUtility.LogInfo("GetItemFromSessionStore => Session Id: {0}, Session provider object: {1} => Can not lock, Someone else has lock and lockId is {2}", id, this.GetHashCode(), lockId);
} // If locking is not successful then do not return any result just return lockAge, locked=true and lockId.
// ASP.NET tries to acquire lock again in 0.5 sec by calling this method again. Using lockAge it finds if
// lock has been taken more than http request timeout than ASP.NET calls ReleaseItemExclusive and calls this method again to get lock.
if (locked)
{
lockAge = cache.GetLockAge(lockId);
return null;
} if (sessionData == null)
{
// If session data do not exists means it might be exipred and removed. So return null so that asp.net can call CreateUninitializedItem and start again.
// But we just locked the record so first release it
ReleaseItemExclusive(context, id, lockId);
return null;
} // Restore action flag from session data
if (sessionData["SessionStateActions"] != null)
{
actions = (SessionStateActions)Enum.Parse(typeof(SessionStateActions), sessionData["SessionStateActions"].ToString());
} //Get data related to this session from sessionDataDictionary and populate session items
sessionData.Dirty = false;
sessionStateStoreData = new SessionStateStoreData(sessionData, new HttpStaticObjectsCollection(), sessionTimeout);
return sessionStateStoreData;
}
catch (Exception e)
{
LogUtility.LogError("GetItemFromSessionStore => {0}", e.ToString());
locked = false;
lockId = null;
lockAge = TimeSpan.Zero;
actions = ;
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
return null;
}
} public override void ResetItemTimeout(HttpContext context, string id)
{
try
{
if (LastException == null)
{
LogUtility.LogInfo("ResetItemTimeout => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
GetAccessToStore(id);
cache.UpdateExpiryTime((int)configuration.SessionTimeout.TotalSeconds);
cache = null;
}
}
catch (Exception e)
{
LogUtility.LogError("ResetItemTimeout => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
} public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
{
try
{
if (LastException == null && lockId != null)
{
LogUtility.LogInfo("RemoveItem => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
GetAccessToStore(id);
cache.TryRemoveAndReleaseLockIfLockIdMatch(lockId);
}
}
catch (Exception e)
{
LogUtility.LogError("RemoveItem => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
} public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
{
try
{
// This check is required for unit tests to work
int sessionTimeoutInSeconds;
if (context != null && context.Session != null)
{
sessionTimeoutInSeconds = context.Session.Timeout * FROM_MIN_TO_SEC;
}
else
{
sessionTimeoutInSeconds = (int)configuration.SessionTimeout.TotalSeconds;
} if (LastException == null && lockId != null)
{
LogUtility.LogInfo("ReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => For lockId: {2}.", id, this.GetHashCode(), lockId);
GetAccessToStore(id);
cache.TryReleaseLockIfLockIdMatch(lockId, sessionTimeoutInSeconds);
// Either already released lock successfully inside above if block
// Or we do not hold lock so we should not release it.
sessionId = null;
sessionLockId = null;
}
}
catch (Exception e)
{
LogUtility.LogError("ReleaseItemExclusive => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
} public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
{
try
{
if (LastException == null)
{
GetAccessToStore(id);
// If it is new record
if (newItem)
{
ISessionStateItemCollection sessionItems = null;
if (item != null && item.Items != null)
{
sessionItems = item.Items;
}
else
{
sessionItems = new ChangeTrackingSessionStateItemCollection();
} if (sessionItems["SessionStateActions"] != null)
{
sessionItems.Remove("SessionStateActions");
} // Converting timout from min to sec
cache.Set(sessionItems, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => created new item in session.", id, this.GetHashCode());
} // If update if lock matches
else
{
if (item != null && item.Items != null)
{
if (item.Items["SessionStateActions"] != null)
{
item.Items.Remove("SessionStateActions");
}
// Converting timout from min to sec
cache.TryUpdateAndReleaseLockIfLockIdMatch(lockId, item.Items, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => updated item in session.", id, this.GetHashCode());
}
}
}
}
catch (Exception e)
{
LogUtility.LogError("SetAndReleaseItemExclusive => {0}", e.ToString());
LastException = e;
if (configuration.ThrowOnError)
{
throw;
}
}
}
}
}

其中GetItem和GetItemExclusive都是调用GetItemFromSessionStore方法,如果入口是GetItem调用TryCheckWriteLockAndGetData方法(不会发生锁),入口时GetItemExclusive调用TryTakeWriteLockAndGetData方法(会有锁),但是这2个方法都会修改Session的SessionTimeout值。

TryTakeWriteLockAndGetData方法的实现如下:

运行结果如下:

TryCheckWriteLockAndGetData的实现如下:

在GetItemFromSessionStore方法中如果获取ISessionStateItemCollection实例为null,我们调用 ReleaseItemExclusive(context, id, lockId)方法来释放锁(前提是前面调用TryTakeWriteLockAndGetData已经获取lockId),一般这个方法都不会执行的,现在我们知道默认情况下载装在session的时候就会锁,如果session实例为null我们会释放我们的锁。

那么这个锁又是是么时候释放的了?在 app.ReleaseRequestState += new EventHandler(this.OnReleaseState);会调用我们这里的SetAndReleaseItemExclusive方法,默认情况下它会释放我们的锁。

运行该方法结果如下:

其实现code如下:

RedisSessionStateProvider为了保证性能,在EndRequest里面还会尝试 释放锁。

到现在我们知道默认加载Session数据的时候会加锁,在ReleaseRequestState事件默认解锁。

asp.net mvc Session RedisSessionStateProvider锁的实现的更多相关文章

  1. asp.net mvc session锁问题

    一.会话状态Session Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端) ...

  2. asp.net mvc session锁问题 (转载)

    一.会话状态Session Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端) ...

  3. [转]菜鸟程序员之Asp.net MVC Session过期异常的处理

    本文转自:http://www.cnblogs.com/JustRun1983/p/3377652.html 小赵是刚毕业的计算机专业方面的大学生,4年的大学时间里面,他读过了很多编程方面的数据,也动 ...

  4. 菜鸟程序员之Asp.net MVC Session过期异常的处理

    小赵是刚毕业的计算机专业方面的大学生,4年的大学时间里面,他读过了很多编程方面的数据,也动手也了很多代码.现在毕业了,他如愿的加入了T公司,开始了自己的程序员生涯.他信心满满,相信自己4年的学习到的东 ...

  5. Ajax异步请求阻塞情况的解决办法(asp.net MVC Session锁的问题)

    讨论今天这个问题之前,我们先来看下浏览器公布的资源并发数限制个数,如下图 不难看出,目前主流浏览器支持都是最多6个并发 需要注意的是,浏览器的并发请求数目限制是针对同一域名的 意即,同一时间针对同一域 ...

  6. asp.net MVC Session锁的问题

    一直在用Session,对Session锁并没有太多的关注,可能是平时没有注意.前段时间突然发现,一个Ajax Get请求,直接访问地址,只需要几十ms,但是在页面中加载,却需要2s.最后定位到Ses ...

  7. Asp.Net MVC session跨域

    目的 在公司项目的某个特定场景中,需要在站点B的后端伪造请求,获取站点A的登录状态,抓取站点A的页面内容,因此要用实现session的跨域.以注册功能为例. 步骤 原理 简单地说,对于ASP.Net应 ...

  8. ASP.NET MVC Session 过期验证跳转至登入页面

    一.在要检查登入的控制器上继承 CheckLoginController 类 2. CheckLoginController 类的写法 using System; using System.Colle ...

  9. Asp.net MVC Session过期异常的处理

    一.使用MVC中的Filter来对Session进行验证 (1)方法1: public class MyAuthorizeAttribute : FilterAttribute, IAuthoriza ...

随机推荐

  1. 缓存之EHCache(一)

    源文: http://blog.csdn.net/l271640625/article/details/20528573 一.简介 非常简单,而且易用.     ehcache 是一个非常轻量级的缓存 ...

  2. 性能测试十二:jmeter进阶之java请求参数化

    如项目中的ip.端口号之类的,都可以在此代码中定义 public Arguments getDefaultParameters() { // TODO Auto-generated method st ...

  3. python 全栈开发,Day24(复习,__str__和__repr__,__format__,__call__,__eq__,__del__,__new__,item系列)

    反射: 使用字符串数据类型的变量名来使用变量 wwwh即what,where,why,how  这4点是一种学习方法 反射 :使用字符串数据类型的变量名来使用变量 1.文件中存储的都是字符串 2.网络 ...

  4. 《转》Pragma: no-cache 对性能的影响

    做了下go和java的http性能的简单比较服务端直接输出字符串使用JMeterwindows下  2000的并发,测试结果很出乎意料,go不会这么差吧 研究了半小时,原因如下tomcat的servl ...

  5. win7 64 下 VS2008 调试、退出时错误的解决

    最近调试老程序的时候发现原来的VS2008会偶尔在调试C++程序的时候出现程序未响应的情况,开始还以为是个案,后来出现的频率越来越高完全影响心情啊!! 准备花时间解决一下这个问题.网上搜索没有发现任何 ...

  6. ElasticSearch - How to search for a part of a word with ElasticSearch

    Search a part of word with ElasticSearch 来自stackoverflow https://stackoverflow.com/questions/6467067 ...

  7. openstack时间不同步问题

    一.出现的问题 我们在安装openstack的时候如果没有设置计算节点和控制节点的的时间同步,当你虚拟机开机之后会存在控制节点和计算节点的时间 不一样,导致opstack无法登陆,报如下错误: 二.设 ...

  8. 安装及配置sublime

    纯个人笔记,粗略编写,有时间再修改 参考:关于Sublime text3 配置及插件整理 参考:https://github.com/boontime/sublime-text3-config 参考: ...

  9. 是否可从一个static方法内发出对非static方法的调用?

    不可以.因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用.也就是说,当一个static方法被调用时, ...

  10. bzoj1563: [NOI2009]诗人小G 决策单调性(1D1D)

    目录 题目链接 题解 代码 题目链接 bzoj1563: [NOI2009]诗人小G 题解 \(n^2\) 的dp长这样 \(f_i = min(f_j + (sum_i - sum_j - 1 - ...