SignalR structuremap dependency resolver ( specifi

2019-07-06 00:36发布

问题:

how can i resolve this error ?

versions

Microsoft.AspNet.SignalR.Core 2.2.0, structuremap 3.1.4.143

global.asax signalR dependency resolve

// SIGNALR DEPENDENCY RESOLVER
        GlobalHost.DependencyResolver = new StructureMapSignalRDependencyResolver(Container ?? ObjectFactory.Container);

StructureMapSignalRDependencyResolver

public class StructureMapSignalRDependencyResolver : DefaultDependencyResolver
{
    private readonly IContainer _container;
    public StructureMapSignalRDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public override object GetService(Type serviceType)
    {
        object service = null;
        //Below is a key difference between this StructureMap example, GetInstance is used for concrete classes.
        if (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
        {
            //If the type is a concrete type we get here...
            service = _container.GetInstance(serviceType);
        }
        else
        {
            // Non concrete resolution which uses the base dependency resolver if needed.
            service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
        }
        return service;
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        var objects = _container.GetAllInstances(serviceType).Cast<object>();
        return objects.Concat(base.GetServices(serviceType));
    }
}

erorr

No default Instance is registered and cannot be automatically determined for type 'Microsoft.AspNet.SignalR.Messaging.IMessageBus'

There is no configuration specified for Microsoft.AspNet.SignalR.Messaging.IMessageBus

1.) new AckSubscriber(Default of IMessageBus, Default of IAckHandler) 2.) Microsoft.AspNet.SignalR.Infrastructure.AckSubscriber 3.) Instance of Microsoft.AspNet.SignalR.Infrastructure.AckSubscriber 4.) Container.GetInstance(Microsoft.AspNet.SignalR.Infrastructure.AckSubscriber)

回答1:

Try to resolve from the base class first.

    public override object GetService(Type serviceType)
    {
        if (serviceType == null)
            return null;

        var service = base.GetService(serviceType);
        if (service != null) return service;

        return (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
            ? container.GetInstance(serviceType)
            : container.TryGetInstance(serviceType);
    }


回答2:

@ajm answer above bypassed the error for me, however I found that none of my client-side methods were being invoked.

It turned out that SignalR.Infrastructure.PrincipalUserIdProvider was being resolved instead of my custom IUserIdProvider so I had to modify his answer slightly by adding a container check first.

    public override object GetService(Type serviceType)
    {
        if (serviceType == null)
            return null;

        var service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
        if (service != null) return service;

        return (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
            ? _container.GetInstance(serviceType)
            : _container.TryGetInstance(serviceType);
    }

The secondary container checks are still necessary if you are not using StructureMap 3 as TryGetInstance() returns null for concrete types.



回答3:

I found temporary, but error continues.. how can i registry this {Name = "AckSubscriber" FullName = "Microsoft.AspNet.SignalR.Infrastructure.AckSubscriber"}

temporary solution is try catch, in catch return null

    public override object GetService(Type serviceType)
    {

        try
        {
            object service = null;
            //Below is a key difference between this StructureMap example, GetInstance is used for concrete classes.
            if (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
            {
                //If the type is a concrete type we get here...
                service = _container.GetInstance(serviceType);
            }
            else
            {
                // Non concrete resolution which uses the base dependency resolver if needed.
                service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
            }
            return service;
        }
        catch (Exception exc)
        {
            return null;
        }
    }


回答4:

I just had a similar problem using a Ninject based resolver. The solution in that case was to ensure that Ninject had a binding for IDependencyResolver, similar to this.

var resolver = new NinjectResolver(kernel);
kernel.Bind<IDependencyResolver>().ToConstant(resolver);
GlobalHost.DependencyResolver = resolver;

AckSubscriber has 2 constructors.

public AckSubscriber(IDependencyResolver resolver)
public AckSubscriber(IMessageBus messageBus, IAckHandler ackHandler)

It would appear that for some reason, rather than trying to create this class via a dependency resolver, it is trying to create this class via the underlying IOC container. Because the bindings for all of this classes are in the DefaultDependencyResolver, the container has no idea what they are and so errors. By specifying a binding for IDependencyResolver it is able to use the first constructor and work as intended.