【问题标题】:How to Inject dependencies in a Unity IoC container for SignalR hub?如何在 SignalR 集线器的 Unity IoC 容器中注入依赖项?
【发布时间】:2023-12-28 17:13:01
【问题描述】:

我有一个在 ASP.NET MVC 5 框架之上用 c# 编写的应用程序。我在我的项目中实现了Unity.Mvc。现在,我正在尝试将依赖项对象注入我的SignalR Hub

我创建了一个名为UnityHubActivator的类

我的班级是这样的

public class UnityHubActivator : IHubActivator
{
    private readonly IUnityContainer _container;

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

    public IHub Create(HubDescriptor descriptor)
    {
        return (IHub)_container.Resolve(descriptor.HubType);
    }
}

然后在我的UnityConfig 类中,我将以下内容添加到我的RegisterTypes 方法中

var unityHubActivator = new UnityHubActivator(container);

container.RegisterInstance<IHubActivator>(unityHubActivator);

我的中心是这样的

[Authorize]
public class ChatHub : Hub
{
    protected IUnitOfWork UnitOfWork { get; set; }

    public ChatHub(IUnitOfWork unitOfWork)
        : base()
    {
        UnitOfWork = unitOfWork;
    }

}

但是当我运行集线器时,构造函数永远不会被调用并且连接永远不会发生。

如何正确使用Unity 框架将依赖项注入我的集线器?

更新

我尝试像这样创建一个自定义容器

public class UnitySignalRDependencyResolver: DefaultDependencyResolver
{
    protected IUnityContainer Container;
    private bool IsDisposed = false;

    public UnitySignalRDependencyResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        Container = container.CreateChildContainer();
    }

    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);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

        if(IsDisposed)
        {
            return;
        }

        if(disposing)
        {
            Container.Dispose();
        }

        IsDisposed = true;
    }
} 

然后这是我在 Startup 类中配置集线器的方式

public class Startup
{
    public IUnityContainer Container { get; set; }
    public Startup(IUnityContainer container)
    {
        Container = container;
    }

    public void Configuration(IAppBuilder app)
    {
        app.Map("/signalr", map =>
        {
            var resolver = new UnitySignalRDependencyResolver(Container);

            var hubConfiguration = new HubConfiguration
            {
                Resolver = resolver
            };

            map.RunSignalR(hubConfiguration);
        });
    }
}

但现在仍在工作......集线器构造函数永远不会被调用。

这是我从客户端调用我的集线器的方式

<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>

$(function () {
    // Reference the auto-generated proxy for the hub.
    var app = $.connection.chatHub;
    console.log('Getting things ready....');

    app.client.outOfTasks = function () {
        console.log('Nothing to do here')
    };

    app.client.logError = function (message) {
        console.log(message)
    };

    app.client.logNote = function (message) {
        console.log(message)
    };

    app.client.assignTask = function (taskId) {
        app.server.taskReceived();
        console.log('task received!!!' + taskId);

    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        console.log('Connection Started....');
    });
});

</script>

【问题讨论】:

标签: c# dependency-injection asp.net-mvc-5 signalr unity-container


【解决方案1】:

UnitySignalRDependencyResolver 对于该容器来说似乎是准确的。

取自官方文档,

Dependency Injection in SignalR

尝试以下示例配置启动

public class Startup{    
    public void Configuration(IAppBuilder app) {
        IUnityContainer container = GetContainer(); 

        var resolver = new UnitySignalRDependencyResolver(container);

        var config = new HubConfiguration {
            Resolver = resolver
        };      
        app.MapSignalR("/signalr", config);
    }

    IUnityContainer GetContainer() {
        //...call the unity config related code.
        var container = UnityConfig.Container;
        //...any other code to populate container.

        return container;
    }
}

确保向容器注册必要的对象,包括集线器 (ChatHub),因为容器需要知道对象图才能解决必要的依赖关系。

【讨论】:

  • 对此进行调查,您的道路是正确的。我不得不从 Startup 类中删除构造函数并使用UnityConfig.GetConfiguredContainer()。我没有收到任何错误,但集线器的构造函数从未被调用。
  • @MikeA 您是否正在从客户端建立任何连接?
  • 是的外包。我刚刚用用于调用客户端的 JS 代码更新了我的问题。奇怪的是我在控制台中收到以下消息..Getting things ready... 然后Connection Started... 这听起来像是建立了连接但没有更多的通信并且构造函数从未被调用。
  • @MikeA 我没有看到从客户端调用的集线器中的操作示例。更新示例。也出于调试目的删除 Authorize 属性。
  • 通信从服务器开始。当客户端连接时,我在集线器中运行一些代码,调用此 Clients.User(GetIdentity.Name).assignTask(TaskId.Value) 这使用 assignTask 函数向客户端发送消息。收到后,客户端使用app.server.taskReceived(); 发送确认消息,但由于集线器构造函数甚至OnConnected 方法,服务器从不发送信号
最近更新 更多