Showing posts with label HttpContext. Show all posts
Showing posts with label HttpContext. Show all posts

SignalR OnDisconnected Task and Dependency Injection with Castle Windsor - Hybrid lifestyle to the rescue

Today I faced a Castle Windsor dependency injection problem in an ASP.NET MVC app. The problem happened when using SignalR.

While implementing some UI real time user interaction I needed to have my persistence facility (Database context) injected inside my SignalR Hub class.

I Googled and found this awesome and to the point post by Mira Javora:

SignalR-Dependency Injection using Castle.Windsor

With the code he provided I was able to configure SignalR’s dependency resolver and everything was working as expected as Mira showed in his post.

In my case two objects are being injected in the Hub class:

public class AssessmentHub : Hub
{
    private MyContext _database { get; set; }

    private ILogger _logger { get; set; }

    public AssessmentHub(MyContext database, ILogger logger)
    {
        _database = database;
        _logger = logger;
    }

...
}

They were being properly injected in my own Hub class methods but things started to go wrong when SignalR’s OnDisconnected method was being called:

public override Task OnDisconnected()
{
    try
    {
        Guid connectionId = Guid.Parse(Context.ConnectionId);
// Database was null here! Sad smile
var client = Database.HubConnections.Single(hc => hc.ConnectionId == connectionId); UnlockChapterAndUpdateClients(client); Database.HubConnections.Remove(client); Database.SaveChanges(); } catch (Exception ex) { Logger.Error(ex.Message, ex); } return base.OnDisconnected(); }

This was the error I was getting:

HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net.

The OnDisconnected method is an asynchronous method and as such it runs under a background thread ( not the one processing the request ). ASP.NET controls the threads and makes sure that only one thread is processing the request. This way HttpContext and as a consequence my _database injected object is null inside that method.

After some thinkering I remembered that I had my Persistence Facility registered PerWebRequest:

public class PersistenceFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<MyContext>().          
            LifeStyle.PerWebRequest);
    }
}

Then, I Googled a little bit more and found this StackOverflow question:

Castle.Windsor lifestyle depending on context?

User Cuong Le shared a great post by Mauricio Scheffer called:

Hybrid lifestyles in Windsor

His post describes exactly what I needed (an Hybrid lifestyle ), that is, a way of keeping using the PerWebRequest life style when HttpContext is available but then resort to Transient lifestyle when it’s not.

An hybrid lifestyle is one that actually blends two underlying lifestyles: a main lifestyle and a secondary lifestyle. The hybrid lifestyle first tries to use the main lifestyle; if it's unavailable for some reason, it uses the secondary lifestyle. This is commonly used with PerWebRequest as the main lifestyle: if the HTTP context is available, it's used as the scope for the component instance; otherwise the secondary lifestyle is used.

I then grabbed Mauricio’s NuGet package Castle.Windsor.Lifestyles and changed my Persistence Facility code to:

public class PersistenceFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<MyContext>().          
            LifeStyle.HybridPerWebRequestTransient());
    }
}

I’m back in business now. Call me