Pergunta

I implemented a custom web handler (ashx) page in my existing ASP.NET project which uses the Session object to know which user is requests pages. The web handler works except for one major draw back. The Session object is not available to my Websocket handler task.

I tried calling HttpContext.Current.Session but it is null.

Any suggestions?

Update

Thanks to Karl Anderson's response, I was able to make some head way, however the issue still stands. My code in the handler is as follows:

public class WSHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            string s = context.Session["UserName"]; // This works now!
            context.AcceptWebSocketRequest(ProcessWebSocket);
        }
    }

    public bool IsReusable { get { return false; } }

    private async Task ProcessWebSocket(AspNetWebSocketContext context)
    {
        string s = HttpContext.Current.Session["UserName"]; // This still doesn't.  The Session property is null
        ...
    }
}
Foi útil?

Solução 3

The best that I was able to come up with was to create a method which invokes a web form to get/set session data. I understand that this isn't very efficient however I don't see any other way to do this.

Edit: In order for this to work you need to enable Cookieless sessions in the Web.Config file. This could be a big security risk for most sites so remember to implement logic to prevent session hijacking! I am currently using IP verification along with browser fingerprint checking.

I created a class that I use in my WebSocket handler (WSHandler.ashx):

public class SessionData
{
    AspNetWebSocketContext _WebSocketContext = null;

    public SessionData(AspNetWebSocketContext WebSocketContext)
    {
        _WebSocketContext = WebSocketContext;
    }

    public string GetSessionValue(string name)
    {
        string value = "";

        using (WebClient wc = new WebClient())
        {
            string Url = _WebSocketContext.Origin + _WebSocketContext.RawUrl.Replace("WSHandler.ashx", "UpdateSession.aspx");
            Url += "?a=1";
            Url += "&n=" + name;
            value = wc.DownloadString(Url);
        }

        return value;
    }

    public void PutSessionValue(string name, string value)
    {
        using (WebClient wc = new WebClient())
        {
            string Url = _WebSocketContext.Origin + _WebSocketContext.RawUrl.Replace("WSHandler.ashx", "UpdateSession.aspx");
            Url += "?a=2";
            Url += "&n=" + name;
            Url += "&v=" + value;
            wc.DownloadString(Url);
        }
    }

}

Below is the form for the web form UpdateSession.aspx:

public partial class UpdateSession : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string action = Page.Request.QueryString["a"];
        string name = Page.Request.QueryString["n"];
        string value = Page.Request.QueryString["v"];

        Page.Response.Clear();

        if (string.IsNullOrEmpty(name) == true)
        {
            return;
        }

        switch (action)
        {
            case "1":
                if (Session[name] != null)
                {
                    Page.Response.Write(Session[name].ToString());
                }
                break;

            case "2":
                Session[name] = value;
                break;
        }

        Page.Response.End();

    }
}

Outras dicas

If you only need to read from the Session object, then you need to implement IReadOnlySessionState in your HTTP Handler code, like this:

public class YourHandler : IHttpHandler, IReadOnlySessionState
{
    public void ProcessRequest(HttpContext theContext)
    {
        theContext.Response.Write(theContext.Session["YOUR_VALUE_HERE"]);
    }

    public bool IsReusable { get { return true; } }
}

If you want to be able to read from and write to the Session object, then you need to implement the IRequiresSessionState in your HTTP Handler code.

Session is intentionally not made available to the WebSocket handling loop since Session has a default two-minute timeout and WebSocket connections could theoretically last forever.

If you need to read data from Session, read the individual objects ahead of time (in the main ProcessRequest method) and squirrel it away somewhere, like in a private field. If you need to write data back to Session, you'll need to use a different mechanism (such as an actual database table) rather than using Session itself.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top