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

ASP.NET:为无烹饪会话实现ISessionIDManager

从头开始创建自定义会话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实现,看看它们有什么不同。