Search code examples
c#asp.netsignalrautofacsignalr-hub

autofac with signalr no parameterless constructor defined for this object


I'm using autofac on my current Asp project and everything works fine until i decided to use dependancy injection in a signalR Hub

here's my startup class

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        var builder = new ContainerBuilder();
        builder.RegisterControllers(Assembly.GetExecutingAssembly());
        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
        builder.RegisterType<DbFactory>().As<IDbFactory>().InstancePerLifetimeScope();
        //builder.RegisterHubs(Assembly.GetExecutingAssembly());
        builder.RegisterType<DiscussionHub>();
        // Repositories
        builder.RegisterAssemblyTypes(typeof(LanguagesRepository).Assembly)
            .Where(t => t.Name.EndsWith("Repository"))
            .AsImplementedInterfaces().InstancePerRequest();
        // Services
        builder.RegisterAssemblyTypes(typeof(LanguageService).Assembly)
           .Where(t => t.Name.EndsWith("Service"))
           .AsImplementedInterfaces().InstancePerRequest();

        IContainer container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        var config = new HubConfiguration
        {
            Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container)
        };
        app.UseAutofacMiddleware(container);
        AutoMapperConfiguration.Configure();
        app.MapSignalR("/signalr",config);
    }
}

and here's my Hub

public class DiscussionHub : Hub
{
    private readonly IDiscussionService _discussionService;
    public DiscussionHub(IDiscussionService discussionService)
    {
        _discussionService = discussionService;
    }}

the error is that i'm getting no parameterless constructor on my Hub? any suggestion ?!


Solution

  • You should register your hub ExternallyOwned it should manage lifetimescope by itself. That's mean autofac will not disposed them.

    Second, everything will be resolved from root container in your hub. That's mean Per Dependency or Per LifeTimeScope will live with your hub(forever with app). So you should manage lifetime in your hub.

    Even if we manage life time in your hub, Per Request will not be supported. Because of this, when we create new lifetimescope, we will create it with AutofacWebRequest tag. That way, we can resolve your Per Request instance. But pay attention this instance will be totaly different with other instance in normal request lifetimescope.

    Your Hub should be like this:

    public class DiscussionHub  : Hub
    {
      private readonly ILifetimeScope _hubLifetimeScope;
      private readonly IDiscussionService  _discussionService;
    
      public MyHub(ILifetimeScope lifetimeScope)
      {
        // Create a lifetime scope for the hub.
        _hubLifetimeScope = lifetimeScope.BeginLifetimeScope("AutofacWebRequest");
    
        // Resolve dependencies from the hub lifetime scope.
        _discussionService = _hubLifetimeScope.Resolve<IDiscussionService>();
      }
    
      protected override void Dispose(bool disposing)
      {
        // Dipose the hub lifetime scope when the hub is disposed.
        if (disposing && _hubLifetimeScope != null)
        {
          _hubLifetimeScope.Dispose();
        }
        base.Dispose(disposing);
      }
    }
    

    Your register should be like this:

      .
      .
      builder.RegisterType<DiscussionHub>().ExternallyOwned();
      var container = builder.Build();
      GlobalHost.DependencyResolver = new   Autofac.Integration.SignalR.AutofacDependencyResolver(container);
      .
      .
    

    Owin Integration:

    public void Configuration(IAppBuilder app)
      {
        var builder = new ContainerBuilder();
    
        // STANDARD SIGNALR SETUP:
    
        // Get your HubConfiguration. In OWIN, you'll create one
        // rather than using GlobalHost.
        var config = new HubConfiguration();
    
        // Register your SignalR hubs.
        builder.RegisterHubs(Assembly.GetExecutingAssembly());
    
        // Set the dependency resolver to be Autofac.
        var container = builder.Build();
        config.Resolver = new AutofacDependencyResolver(container);
    
        // OWIN SIGNALR SETUP:
    
        // Register the Autofac middleware FIRST, then the standard SignalR middleware.
        app.UseAutofacMiddleware(container);
        app.MapSignalR("/signalr", config);
      }
    

    Check more detail.