SignalR 2.0使用Ninject注入接口

5
我有一个简单的 Hub 类,用于使用注入的用户服务列出用户。还有一个使用 NinjectSignalRDependencyResolver 的启动类,以及非常简单的客户端脚本。

Hub

[HubName("dashboardHub")]
public class DashboardHub : Hub
{
    private readonly IUserService _users;

    public DashboardHub(IUserService users)
    {
        _users = users;
    }

    public void Initialize()
    {
        var users = _users.ListUsers();

        Clients.All.UpdateStatus(users);
    }
}

startup.cs

  var kernel = new StandardKernel();
  var resolver = new NinjectSignalRDependencyResolver(kernel);

  var config = new HubConfiguration()
  {
        Resolver = resolver,
  };

  app.MapSignalR(config);

NinjectSignalRDependencyResolver

public class NinjectSignalRDependencyResolver : DefaultDependencyResolver
{
    private readonly IKernel _kernel;

    public NinjectSignalRDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public override object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType) ?? base.GetService(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType).Concat(base.GetServices(serviceType));
    }
}

JavaScript

<script>
    $(function () {
        var dashboard = $.connection.dashboardHub;

        dashboard.client.updateStatus = function (users) {
            var elem= $('.userList');

            elem.html('');
            $.each(users, function (i, user) {
                parent.append("<p>" user.Name +  "<p>");
            });
        };

        $.connection.hub.start().done(function () {
            dashboard.server.initialize();
        });
    });
</script>

我在 RegisterServices 中以标准方式使用 Ninject 注册接口。

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IUserService >().To<UserService>().InSingletonScope();

    ...
}

当使用脚本打开客户端时,代码运行并且没有生成任何异常或脚本错误。虽然JavaScript中存在Dashboard对象和Initialize()方法,但它们都没有被调用,因此用户列表从未被填充,因为client.updateStatus从未被调用。
如果我在Hub类中添加一个默认构造函数,则该构造函数会被调用,Initialize方法也会被调用,但很明显由于私有的IUserService变量为空而失败。请注意,HTML标签已保留。
public DashboardHub()
{
}

如何配置SignalR 2.0和Ninject以允许Hub具有依赖注入的构造函数参数?

这可能会有所帮助:https://dev59.com/Rm7Xa4cB1Zd3GeqPlxae - Rui Jarimba
谢谢提供链接,但我已经在使用相同的依赖解析器和技术。 - Code Uniquely
你是如何初始化/设置解析器的?你是否像这样做:GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(kernel); - Rui Jarimba
我曾经试过将其放在 app.MapSignalR(config); 的前后,但无论哪种情况都没有产生影响。 - Code Uniquely
@Code Uniquely,您需要在startup.cs的Start方法中为IUserService创建一个绑定。以下链接可能会对您有所帮助:http://www.asp.net/signalr/overview/signalr-20/extensibility/dependency-injection - Lin
谢谢,但我已经有一个绑定了:kernel.Bind<IUserService>().To<UserService>().InSingletonScope()。后来我发现了一种更简单/更清晰的方法 - 请看我的答案。 - Code Uniquely
1个回答

10

最简单的方法是完全摆脱自定义依赖项解析器,而只使用一个非常简单的IHubActivator。

startup.cs

public void Configuration(IAppBuilder app)
{
    app.MapSignalR();
}

Hubactivator.cs

public class HubActivator : IHubActivator
{
    private readonly IKernel container;

    public HubActivator(IKernel container)
    {
        this.container = container;
    }

    public IHub Create(HubDescriptor descriptor)
    {
        return (IHub)container.GetInstance(descriptor.HubType);
    }
}

注册服务

private static void RegisterServices(IKernel kernel)
{
    GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new HubActivator(kernel));    

    kernel.Bind<IUserService >().To<UserService>().InSingletonScope();

    ...
}

就是这么简单 - 一切都正常工作,接口被注入到构造函数中,就像您所期望的那样...


6
非常棒的答案!不过我无法使用GetInstance。可能是因为库已经更新了,但是我可以使用return (IHub)container.GetService(descriptor.HubType)来解决我的信仰 (hub) 依赖问题。谢谢! - scniro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接