guozhiqi / autofac

Automatically exported from code.google.com/p/autofac
Other
0 stars 0 forks source link

the Autofac,Signalr dependency resolver doesn't work #416

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi I have downloaded the autofac.signalr zip and it doesn't work, are there any 
plans to update it? or fix it?

Original issue reported on code.google.com by EnenDave...@gmail.com on 16 Mar 2013 at 10:57

GoogleCodeExporter commented 9 years ago
Can you please provide some details?

Original comment by alex.meyergleaves on 16 Mar 2013 at 12:40

GoogleCodeExporter commented 9 years ago
According to the Signalr web site:

https://github.com/SignalR/SignalR/wiki/Extensibility

I download the zip and install the .dll then do

http://code.google.com/p/autofac/downloads/detail?name=Autofac.SignalR.3.0.0.zip

public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
      var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            //Register Context
            builder.Register(c => new myContext()).As<IUnitOfWork>().InstancePerLifetimeScope();

            //Repositories
            builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerHttpRequest();           

            //Service Layer
            builder.RegisterType<PersonService>().As<IPersonService>().InstancePerHttpRequest();
//more services here

            builder.RegisterType<ChatHub>(); 

            var container = builder.Build();           

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));          

            GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container);
            RouteTable.Routes.MapHubs();
    }
}

but I get an error of

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in 
which the instance was requested. This generally indicates that a component 
registered as per-HTTP request is being requested by a SingleInstance() 
component (or a similar scenario.) Under the web integration always request 
dependencies from the DependencyResolver.Current or 
ILifetimeScopeProvider.RequestLifetime, never from the container itself.

I have tried changing 

builder.RegisterType<ChatHub>();

to 

builder.RegisterType<ChatHub>().InstancePerLifetimeScope(); 

But I get the same instance, if I dontt register the hub, and don't have a 
parameterless constructor then it simply doesn't do anything.

Original comment by EnenDave...@gmail.com on 16 Mar 2013 at 6:50

GoogleCodeExporter commented 9 years ago
I am guessing that the ChatHub must have dependencies that are registered as 
InstancePerHttpRequest. Unfortunately, it is not possible to create a lifetime 
scope per hub invocation (I have confirmed this with David Fowler), so no 
'AutofacWebRequest' lifetime scope is available to the hub. I am going to 
change the RegisterHubs method to register the hubs as ExternallyOwned to 
prevent the disposer in the root lifetime scope holding onto the instances. 
SignalR will call Dispose on the hub but you have to dispose any dependencies 
yourself because there will be no per-hub lifetime scope to do it for you.

Original comment by alex.meyergleaves on 17 Mar 2013 at 8:21

GoogleCodeExporter commented 9 years ago
Thanks for the info, so if I set it up now in the same way it will work but I 
need to sort out my own disposal? or when will the update happen?

Can I manually add instance of service to a paramaterless contructor something 
like:

private IPersonService;

public ChatHub()
{
IPersonService = //do something here to get an insatnce of my personservice 
using autofac
}

Original comment by EnenDave...@gmail.com on 18 Mar 2013 at 9:30

GoogleCodeExporter commented 9 years ago
You can still perform constructor injection but will need to perform your own 
disposal. Whether or not you need actual dispose the instance depends on how 
its lifetime is configured and would be easy to get wrong. Also, if you didn't 
mark the components are ExternallyOwned the disposer on the root lifetime scope 
would hold onto them.

An alternative option is to inject the ILifetimeScope into the constructor of 
the hub, and create a new child lifetime scope to resolve your components from. 
Then in the Dispose method of the hub, you can call the Dispose method on the 
child lifetime scope and clean up.

public class MyHub : Hub
{
    readonly ILifetimeScope _hubLifetimeScope;
    readonly IDependency _dependency;

    public MyHub(ILifetimeScope lifetimeScope)
    {
        _hubLifetimeScope = lifetimeScope.BeginLifetimeScope();
        _dependency = _hubLifetimeScope.Resolve<IDependency>();
    }

    // Use the dependency in a hub method.

    protected override void Dispose(bool disposing)
    {
        if (disposing && _hubLifetimeScope != null)
            _hubLifetimeScope.Dispose();

        base.Dispose(disposing);
    }
}

I will create a SignalR page on the wiki and add some notes. It would be nice 
if there was a better solution but SignalR currently doesn't have the hooks. I 
have commented on a SignalR issue that raises essentially the same concern. 
https://github.com/SignalR/SignalR/issues/863#issuecomment-15042473

Original comment by alex.meyergleaves on 18 Mar 2013 at 1:40

GoogleCodeExporter commented 9 years ago
Thanks, I am trying the second approach, I will hopefully wait for the new 
updates to resolve the issue until i do the full changes.

However I can't get it to work, I am assuming I need to register the hub, with 
in the container eg

protected void Application_Start(object sender, EventArgs e)
    {
      var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            //Register Context
            builder.Register(c => new myContext()).As<IUnitOfWork>().InstancePerLifetimeScope();

            //Repositories
            builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerHttpRequest();           

            //Service Layer
            builder.RegisterType<PersonService>().As<IPersonService>().InstancePerHttpRequest();
//more services here

            builder.RegisterType<ChatHub>(); 

            var container = builder.Build();           

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));          

                        RouteTable.Routes.MapHubs();
    }

However not matter what I set  builder.RegisterType<ChatHub>(); to, when I try 
and use the sub in a chat like send, nothing happens.  I have tried 
builder.RegisterType<ChatHub>().InstancePerLifetimeScope(); and everything else 
I can think of but still nothing.

Thanks for the help, and sorry for being such a noob

Original comment by EnenDave...@gmail.com on 18 Mar 2013 at 10:03

GoogleCodeExporter commented 9 years ago
There is a separate AutofacDependencyResolver for SignalR that needs to be 
assigned to GlobalHost.DependencyResolver. I added a wiki page that might help 
you get started.

https://code.google.com/p/autofac/wiki/SignalRIntegration

No problem with the help. I should have put some doco up earlier.

Original comment by alex.meyergleaves on 18 Mar 2013 at 11:56

GoogleCodeExporter commented 9 years ago
Thanks I am still really having troubles and getting the same errors, I am 
using ASP.NET MVC.

I have 1 question which might not help, but do I set up one build and container 
for the normal MVC project and a seperate one for the hubs? or should they be 
in the same one?

Also there is no extension method builder.RegisterHubs.

Original comment by EnenDave...@gmail.com on 20 Mar 2013 at 11:28

GoogleCodeExporter commented 9 years ago
Hi  Just to add thanks again for the help, I got it working, but in the info 
guide I think you need to make it clear this has to be a different setup for 
the hub, and the normal MVC dependecy injection otherwise you still end up with 
the same errors as the mix of .InstancePerHttpRequest() and .ExternallyOwned() 
causes errors, I am not sure if thats the correct way to do it, but it is 
working.

Original comment by EnenDave...@gmail.com on 20 Mar 2013 at 11:40

GoogleCodeExporter commented 9 years ago
Thanks for the update and I'm glad you got it working. I wish it possible to 
provide lifetime scopes in SignalR and things weren't so tricky right now. 
Keeping things separate is certainly a decent option. If I can't think of a 
cleaner option I'll update the wiki that recommendation.

Original comment by alex.meyergleaves on 20 Mar 2013 at 12:24

GoogleCodeExporter commented 9 years ago
Just wanted to say thanks again for the help :-)

Original comment by EnenDave...@gmail.com on 20 Mar 2013 at 1:15