Question

I'm trying to share the elements in cache between ServiceStack OOB ICacheClient and a SignalR Hub, but I'm getting the following error when I try to get the user session in the OnDisconnected event

Only ASP.NET Requests accessible via Singletons are supported

I have no issues accessing the session in the OnConnected event, so far this is what I've done:

public class HubService:Hub
{
    private readonly IUserRepository _userRepository;
    private readonly ICacheClient _cacheClient;

    public HubService(IUserRepository userRepository,ICacheClient cacheClient)
    {
        _userRepository = userRepository;
        _cacheClient = cacheClient;
    }

    public override System.Threading.Tasks.Task OnConnected()
    {
        var session = _cacheClient.SessionAs<AuthUserSession>();
        //Some Code, but No error here
        return base.OnConnected();
    }

    public override System.Threading.Tasks.Task OnDisconnected()
    {
        var session = _cacheClient.SessionAs<AuthUserSession>();
        return base.OnDisconnected();
    }
}

I'm using simple injector and my ICacheClient is registered as singleton:

 Container.RegisterSingle<ICacheClient>(()=>new MemoryCacheClient());

the question is how do I register requests as singletons in SS? what am I missing on SignalR event?

Edit:

what I tried to expain for register requests in SS is because if there's a possibility to register SS IHttpRequest using a container and set the lifestyle as singleton due to the exception message, it seems like httpContext and IHttprequest are null by the OnDisconnected event

the SS code is the following:

public static string GetSessionId(IHttpRequest httpReq = null)
{
    if (httpReq == null && HttpContext.Current == null)
        throw new NotImplementedException(OnlyAspNet); //message
        httpReq = httpReq ?? HttpContext.Current.Request.ToRequest();
        return httpReq.GetSessionId();
}

what I'm trying to do is to store a list of connected users using ICacheClient and I just want to remove the connectionID from the list when a user get disconnected.

Edit: it seems like according to danludwig post

"There is an interesting thing about SignalR... when a client disconnects from a hub (for example by closing their browser window), it will create a new instance of the Hub class in order to invoke OnDisconnected(). When this happens, HttpContext.Current is null. So if this Hub has any dependencies that are >registered per-web-request, something will probably go wrong."

the description above perfectly match my situation

Was it helpful?

Solution

I am no SingalR expert, but based on my experience with it and simple injector, I don't think you can get at Session (or Request, or HttpContext for that matter) during OnDisconnected. It kind of makes sense if you think about it though -- when a client disconnects from a hub, SignalR no longer has access to a session ID, there is no request, there is no more communication with the client. OnDisconnected is basically telling you "here, do something with this ConnectionId because the client it belonged to has gone away." Granted the user may come back, and then you can get access to the web goodies (session, request, etc, as long as you are IIS hosted) during OnReconnected.

I was having similar problems getting some simpleinjector dependencies to have correct lifetime scope during these 3 Hub connection events. There was 1 dependency that I wanted to register per http request, and it worked for everything except OnDisconnected. So I had to fenagle the SI container to use http requests when it could, but use a new lifetime scope when the dependency was needed during an OnDisconnected event. If you care to read it, I have a post here that describes my experiences. Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top