ASP.NET:为无烹饪会话实现ISessionIDManager
本文关键字:会话 实现 ISessionIDManager NET ASP | 更新日期: 2023-09-27 18:10:08
问题:
我正在编写一个自定义会话提供程序。到目前为止,它运行良好。我决定添加一个自定义的ISessionIDManager,以控制会话id。
它已经可以很好地用于cookie会话。但当我切换到无烹饪时,就像这样:
<sessionState mode="Custom" customProvider="custom_provider" cookieless="true" timeout="1"
sessionIDManagerType="Samples.AspNet.Session.MySessionIDManager"
sqlConnectionString="Data Source=localhost;Initial Catalog=TestDB;User Id=SomeUser;Password=SomePassword;"
sqlCommandTimeout="10"
>
<!-- timeout in minutes-->
<providers>
<add name="custom_provider" type="Test.WebSession.CustomSessionStoreProvider" />
</providers>
</sessionState>
然后重定向到:
http://localhost:52897/(77bb065f-d2e9-4cfc-8117-8b89a40e0d8(/default.aspx
这会抛出HTTP 404。
我理解为什么,因为没有这样的文件夹
但是,当您使用默认会话管理器(asp.net附带的会话管理器(并切换到cookieless时,URL如下所示:
http://localhost:52897/(S(sq2abm453wnasg45pvboee45((/DisplaySessionValues.aspx
并且没有HTTP 404…
我试着把(S和(添加到我的会话id中,放在url的括号里,但无济于事。
我错过了什么?
using System;
using System.Configuration;
using System.Web.Configuration;
using System.Web;
using System.Web.SessionState;
// http://allantech.blogspot.com/2011/04/cookieless-session-state-in-aspnet.html
// http://forums.asp.net/t/1082784.aspx/1
// http://stackoverflow.com/questions/4612310/implementing-a-custom-sessionidmanager
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager.aspx
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager(v=vs.80).aspx
namespace Samples.AspNet.Session
{
// Samples.AspNet.Session.MySessionIDManager
public class MySessionIDManager : IHttpModule, ISessionIDManager
{
protected SessionStateSection pConfig = null;
internal const string HeaderName = "AspFilterSessionId";
protected void InitializeModule()
{
// Obtain session-state configuration settings.
if (pConfig == null)
{
Configuration cfg =
WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");
} // End if (pConfig == null)
}
//
// IHttpModule Members
//
//
// IHttpModule.Init
//
public void Init(HttpApplication app)
{
//InitializeModule();
} // End Sub Init
//
// IHttpModule.Dispose
//
public void Dispose()
{
} // End Sub Dispose
//
// ISessionIDManager Members
//
//
// ISessionIDManager.Initialize
//
public void Initialize()
{
InitializeModule();
} // End Sub Initialize
//
// ISessionIDManager.InitializeRequest
//
public bool InitializeRequest(
HttpContext context,
bool suppressAutoDetectRedirect,
out bool supportSessionIDReissue
)
{
if (pConfig.Cookieless == HttpCookieMode.UseCookies)
{
supportSessionIDReissue = false;
return false;
}
else
{
supportSessionIDReissue = true;
return context.Response.IsRequestBeingRedirected;
}
} // End Function InitializeRequest
//
// ISessionIDManager.GetSessionID
//
public string GetSessionID(HttpContext context)
{
string id = null;
if (pConfig.Cookieless == HttpCookieMode.UseUri)
{
string tmp = context.Request.Headers[HeaderName];
if (tmp != null)
id = HttpUtility.UrlDecode(id);
// Retrieve the SessionID from the URI.
}
else
{
if (context.Request.Cookies.Count > 0)
{
id = context.Request.Cookies[pConfig.CookieName].Value;
id = HttpUtility.UrlDecode(id);
}
}
// Verify that the retrieved SessionID is valid. If not, return null.
if (!Validate(id))
id = null;
return id;
} // End Function GetSessionID
//
// ISessionIDManager.CreateSessionID
//
public string CreateSessionID(HttpContext context)
{
return System.Guid.NewGuid().ToString();
} // End Function CreateSessionID
//
// ISessionIDManager.RemoveSessionID
//
public void RemoveSessionID(HttpContext context)
{
context.Response.Cookies.Remove(pConfig.CookieName);
} // End Sub RemoveSessionID
public static string InsertSessionId(string id, string path)
{
string dir = GetDirectory(path);
if (!dir.EndsWith("/"))
dir += "/";
string appvpath = HttpRuntime.AppDomainAppVirtualPath;
if (!appvpath.EndsWith("/"))
appvpath += "/";
if (path.StartsWith(appvpath))
path = path.Substring(appvpath.Length);
if (path[0] == '/')
path = path.Length > 1 ? path.Substring(1) : "";
// //http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx
return Canonic(appvpath + "(" + id + ")/" + path);
//return Canonic(appvpath + "(S(" + id + "))/" + path);
}
public static bool IsRooted(string path)
{
if (path == null || path.Length == 0)
return true;
char c = path[0];
if (c == '/' || c == '''')
return true;
return false;
}
public static string Canonic(string path)
{
char[] path_sep = { '''', '/' };
bool isRooted = IsRooted(path);
bool endsWithSlash = path.EndsWith("/");
string[] parts = path.Split(path_sep);
int end = parts.Length;
int dest = 0;
for (int i = 0; i < end; i++)
{
string current = parts[i];
if (current.Length == 0)
continue;
if (current == ".")
continue;
if (current == "..")
{
dest--;
continue;
}
if (dest < 0)
if (!isRooted)
throw new HttpException("Invalid path.");
else
dest = 0;
parts[dest++] = current;
}
if (dest < 0)
throw new HttpException("Invalid path.");
if (dest == 0)
return "/";
string str = String.Join("/", parts, 0, dest);
str = RemoveDoubleSlashes(str);
if (isRooted)
str = "/" + str;
if (endsWithSlash)
str = str + "/";
return str;
}
public static string GetDirectory(string url)
{
url = url.Replace('''', '/');
int last = url.LastIndexOf('/');
if (last > 0)
{
if (last < url.Length)
last++;
return RemoveDoubleSlashes(url.Substring(0, last));
}
return "/";
}
public static string RemoveDoubleSlashes (string input)
{
// MS VirtualPathUtility removes duplicate '/'
int index = -1;
for (int i = 1; i < input.Length; i++)
if (input [i] == '/' && input [i - 1] == '/') {
index = i - 1;
break;
}
if (index == -1) // common case optimization
return input;
System.Text.StringBuilder sb = new System.Text.StringBuilder(input.Length);
sb.Append (input, 0, index);
for (int i = index; i < input.Length; i++) {
if (input [i] == '/') {
int next = i + 1;
if (next < input.Length && input [next] == '/')
continue;
sb.Append ('/');
}
else {
sb.Append (input [i]);
}
}
return sb.ToString ();
}
// http://www.dotnetfunda.com/articles/article1531-how-to-add-custom-headers-into-readonly-httprequest-object-using-httpmodule-.aspx
public void SetHeader(string strHeaderName, string strValue)
{
//get a reference
System.Collections.Specialized.NameValueCollection headers = HttpContext.Current.Request.Headers;
//get a type
Type t = headers.GetType();
//get the property
System.Reflection.PropertyInfo prop = t.GetProperty(
"IsReadOnly",
System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.IgnoreCase
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.FlattenHierarchy
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.FlattenHierarchy
);
//unset readonly
prop.SetValue(headers, false, null); // Set Read-Only to false
//add a header
//HttpContext.Current.Request.Headers.Add(strHeaderName, strValue);
//headers.Add(strHeaderName, strValue);
t.InvokeMember("BaseAdd",
System.Reflection.BindingFlags.InvokeMethod
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance,
null,
headers,
new object[] { strHeaderName, new System.Collections.ArrayList { strValue } }
);
prop.SetValue(headers, true, null); // Reset Read-Only to true
// Victory !
//string strCheckHeaders = string.Join(Environment.NewLine, HttpContext.Current.Request.Headers.AllKeys);
}
//
// ISessionIDManager.SaveSessionID
//
public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
if (!Validate(id))
throw new HttpException("Invalid session ID");
Type t = base.GetType();
redirected = false;
cookieAdded = false;
if (pConfig.Cookieless == HttpCookieMode.UseUri)
{
// Add the SessionID to the URI. Set the redirected variable as appropriate.
//context.Request.Headers.Add(HeaderName, id);
//context.Request.Headers.Set(HeaderName, id);
SetHeader(HeaderName, id);
cookieAdded = false;
redirected = true;
UriBuilder newUri = new UriBuilder(context.Request.Url);
newUri.Path = InsertSessionId(id, context.Request.FilePath);
//http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx
context.Response.Redirect(newUri.Uri.PathAndQuery, false);
context.ApplicationInstance.CompleteRequest(); // Important !
return;
}
else
{
context.Response.Cookies.Add(new HttpCookie(pConfig.CookieName, id));
cookieAdded = true;
}
} // End Sub SaveSessionID
//
// ISessionIDManager.Validate
//
public bool Validate(string id)
{
try
{
Guid testGuid = new Guid(id);
if (id == testGuid.ToString())
return true;
}
catch
{
}
return false;
} // End Function Validate
} // End Class MySessionIDManager : IHttpModule, ISessionIDManager
} // End Namespace Samples.AspNet.Session
从头开始创建自定义会话id管理器似乎工作量很大。从System.Web.SessionState.SessionIDManager类继承并重写CreateSessionID方法怎么样?
public class MySessionIDManager : SessionIDManager, ISessionIDManager
{
public override string CreateSessionID(HttpContext context)
{
return System.Guid.NewGuid().ToString("N");
}
}
当其他一切都失败时,用Reflector或ILSpy破解.NET实现,看看它们有什么不同。