1

I use Autofac as my IoC container of choice. The rest of this question refers to SignalR in conjunction with SignalR, but no real SignalR knowledge is needed to answer; this is a problem rooted in Autofac.

As part of using Autofac as the dependency resolver for SignalR, I want to provide my own IJsonSerializer instance configured how I like it. I don't, however, want to have that IJsonSerializer instance shared throughout the rest of the software.

To accomplish this, I created a new lifetime scope with the additional registration, and provided that scope to the dependency resolver. This is when my problems started.

What I didn't realize is by doing this, instance-per-lifetime-scope dependencies requested from SignalR which had previously been retrieved from the root container are now being requested from a lifetime scope, and thus are shared across the entirety of SignalR. This is not good. For example, short-lived database sessions are now shared for the lifetime of my application.

How can I cause my instance-per-lifetime-scope dependencies to basically pretend that the lifetime scope I pass to SignalR should not be used to cause those dependencies to be reused? Alternatively how can I avoid creating the lifetime scope altogether?

David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
  • Just a question, how is resolving from the new lifetime scope any different from resolving from the root? You would have the same problem with instances resolved from root being shared "across the entirety of SignalR"... – Peter Lillevold Feb 02 '13 at 16:04
  • @PeterLillevold Since there's no lifetime scope, lifetime-scoped registrations act as instance per dependency. – David Pfeffer Feb 02 '13 at 16:26
  • David, that statement is wrong. The root is in itself a lifetime scope. Any lifetime-scoped registrations will be single instances within each scope, also in root. Just wrote a unit test with Autofac3 which confirms this. – Peter Lillevold Feb 04 '13 at 11:50

3 Answers3

1

I ended up rewriting the Autofac integration for SignalR to support creating a lifetime scope per HTTP context, by taking a dependency on Autofac MVC support:

https://github.com/bytenik/Autofac.Integration.Mvc.SignalR

(Note this is Autofac.Integration.Mvc.SignalR, rather than Autofac.Integration.SignalR.)

David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
1

Question is a few months old but I thought I would share with you the method I used (perhaps someone can improve on it).

I added an event to my hub, to fire once the hub was disposing. (Actually through a base hub as I had some common logic already in place anyway)

public event Action OnDisposing;

protected override void Dispose(bool disposing)
{
    if (OnDisposing != null) OnDisposing.Invoke();
}

With this in place I then modified how autofac registers this hub. When resolving, a new lifetime scope is created and the scope's dispose method is set to fire when the hub is disposed.

builder.Register(x =>
{
    ILifetimeScope scope = x.Resolve<ILifetimeScope>().BeginLifetimeScope();
    MyHub hub = new MyHub(scope.Resolve<IMyDependency>());
    hub.OnDisposing += scope.Dispose;
    return hub;
})
.As<MyHub>().InstancePerDependency();
Dan Saltmer
  • 2,145
  • 13
  • 15
  • Found a problem with this method I previously posted. Registering like this appears to prevent the hub from working with any pipelinemodules. – Dan Saltmer Apr 29 '13 at 12:13
0

You could consider setting up your preferred IJsonSerializer implementation as a Named or Keyed registration, to be requested specifically by the components that depend on it. I don't know enough about SignalR to tell you how or where that might be accomplished, but it might help you find a workable solution.

For more details: http://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices

James Nail
  • 1,541
  • 1
  • 14
  • 23
  • Unfortunately, I can't (to my knowledge) do that here. SignalR's integration is basically the same as MVC's, in that I just create an instance of `AutofacDependencyResolver` that implements SignalR's `IDependencyResolver`, so I wouldn't have an opportunity to do that. – David Pfeffer Feb 01 '13 at 17:36
  • Ah yeah, I see what you mean... it ends up being resolved via service location, not necessarily constructor injection. Can you elaborate on your criteria for deciding which IJsonSerializer implementation you want it to resolve? – James Nail Feb 01 '13 at 17:56
  • Easy - SignalR gets one, everyone else gets another. – David Pfeffer Feb 01 '13 at 21:13