0
votes

I'm using Unity as my DI Container and I haven't been able to get it to work when resolving my SignalR hubs. Has anyone had success with this? I've tried the following:

    public class UnityDependencyResolver : DefaultDependencyResolver
    {
        private readonly IUnityContainer _Container;



     public UnityDependencyResolver (IUnityContainer container)
            {
                _Container = container;
                //edit to add
                container.RegisterInstance<IJavaScriptMinifier>(NullJavaScriptMinifier.Instance);

            }

        public override object GetService(Type serviceType)
        {
            return base.GetService(serviceType) ?? _Container.Resolve(serviceType);
        }

        public override IEnumerable<object> GetServices(Type serviceType)
        {
            return base.GetServices(serviceType) ?? _Container.ResolveAll(serviceType);
        }

    }

but I'm getting an error indicating it can't resolve SignalR.Infrastructure.IJavaScriptMinifier

3
Did you register in implementation of IJavaScriptMinifier with Unity?Sebastian Weber
I tried that after I posted this but it felt like a hack. (I'll edit the post to show how). I'm not using explicitly using it and it's a SignalR interface.timDunham
Maybe you don't explicitely use it in your application. But if your infrastructure depends on it and SignalR uses the DependencyResolver to get an implementation of the IJavaScriptMinifier you need to register it in your container. I would not register it inside the constructor of the resolver but together with all your other dependencies in the application root of your app.Sebastian Weber
SignalR needs a lot of things and the DefaultDependencyResolver includes those (e.g IHubLocator, IHubFactory, and many others). I don't have to register those. I'm thinking it may just be a bug. I really appreciate your comments though :)timDunham
Sorry I overlooked that you only use Unity as a fallback when the DefaultDependencyResolver is not able to serve a given service. Is there any kind of Initialize routine in the default resolver that does not get called by your custom resolver?Sebastian Weber

3 Answers

0
votes

I am a little confused as to why you try to do the base resolution first and then the unity resolver second. Typically if you are going to replace base implementations with your own, both will resolve but yours should be first so that an instance of your overriding class is returned. For instance, say you want to override the IConnectionIdFactory in SignalR. You could create your own class that inherits from the given interface and then register it with Unity. Then your dependency resolver should be able to resolve the given dependency and return, never touching the SignalR resolver. I put together a little test application and my dependency resolver looks like this:

Dependancy Resolver:

public class UnityResolver : DefaultDependencyResolver
{
    private readonly IUnityContainer _container;
    public UnityResolver(IUnityContainer container)
    {
        _container = container;
    }

    public override object GetService(Type serviceType)
    {
        if (_container.IsRegistered(serviceType))
        {
            return _container.Resolve(serviceType);
        }
        return base.GetService(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        if (_container.IsRegistered(serviceType))
        {
            return _container.ResolveAll(serviceType);
        }
        return base.GetServices(serviceType);
    }
}

It is important with unity to test whether or not we have a resolution path as Resolve will throw an exception if one does not exist.

For completeness sake here is the implementation:

ConnectionIDFactory:

public class ConnectionIdFactory : IConnectionIdFactory
{                
    public string CreateConnectionId(IRequest request)
    {            
        return Guid.NewGuid().ToString();
    }
}

Registration:

public class Bootstrapper
{
    public static void Pre_Start()
    {
        Container.DefaultContainer.Instance.RegisterType(
            typeof(IConnectionIdFactory), 
            typeof(Repositories.ConnectionIdFactory), 
            null, 
            new Microsoft.Practices.Unity.ContainerControlledLifetimeManager());

        AspNetHost.SetResolver(new Resolvers.UnityResolver(Container.DefaultContainer.Instance));
    }
}
0
votes

Yesterday i solved this issue in the following way:

Registering the container:

    AspNetHost.SetResolver(dependencyResolver);
    DependencyResolver.SetResolver(dependencyResolver);

Resolver:

    public class UnityDependencyResolver : DefaultDependencyResolver, IDependencyResolver
    {
        private readonly IUnityContainer _container;

        public UnityDependencyResolver(IUnityContainer container)
        {
            _container = container;
        }

        #region IDependencyResolver Members

        public override object GetService(Type serviceType)
        {
            try
            {
                return _container.Resolve(serviceType);
            }
            catch
            {
                return base.GetService(serviceType);
            }
        }

        public override IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return _container.ResolveAll(serviceType);
            }
            catch
            {
                return base.GetServices(serviceType);
            }
        }

        #endregion
    }

Hub:

    public class Chat : Hub
    {
        [Dependency]
        public UserService _userService { get; set; }

        public void Send(string message)
        {                
            _userService.SomeMethod();                
        }
    }

Works perfectly!

0
votes

One more way to inject unity container in your Hub is create your own HubActivator Try this. https://stackoverflow.com/a/30887576/3000736