仅通过接口注入信号器集线器

Inject signalr hub only by interface

所以最近我开始了一个以 Ardalis Clean Architecture 作为模板的项目,一切都很好,但是当 signalR 进入我的项目时,我可以算了吧。我正在尝试注入我的集线器实现的接口并调用它的方法,但每次调用它时都会抛出 NullReferenceException,似乎所有 signalR 组件在这个注入的接口中都是空的。使用 AutoFac 注册了所有集线器并注册了它的接口。试图避免我被迫在核心层中引用 signalR 包的情况。

核心层:

public class UpdateTimerNotificationHandler : INotificationHandler<UpdateTimerNotification>
{
    private readonly ITimerHub _timerHub;
    public UpdateTimerNotificationHandler(ITimerHub timerHub)
    {
        _timerHub = timerHub;
    }

    public Task Handle(UpdateTimerNotification notification, CancellationToken cancellationToken)
    {
        return _timerHub.UpdateTimerAsync(notification);
    }
}
public interface ITimerHub
{
    Task UpdateTimerAsync(UpdateTimerNotification updateTimerNotification);
}

基础设施层:

public class TimerHub : Microsoft.AspNetCore.SignalR.Hub, ITimerHub
{
    private readonly IAccountRepository _accountRepository;
    public TimerHub(IAccountRepository accountRepository)
    {
        _accountRepository = accountRepository;
    }

    public Task UpdateTimerAsync(UpdateTimerNotification updateTimerNotification)
    {
        return Clients.All.SendAsync("UpdateTimer", updateTimerNotification);
    }
}
private void RegisterHubs(ContainerBuilder builder)
    {
        foreach (var assembly in _assemblies)
        {
            builder.RegisterHubs(assembly);
        }
        builder.RegisterType<TimerHub>().As<ITimerHub>();
    }

网络层:

builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
    containerBuilder.RegisterModule(new DefaultCoreModule());
    containerBuilder.RegisterModule(
        new DefaultInfrastructureModule(builder.Environment.EnvironmentName == "Development"));
});

builder.Logging.ClearProviders();
builder.Logging.AddConsole();

var app = builder.Build();
GlobalHost.DependencyResolver = new AutofacDependencyResolver(app.Services.GetAutofacRoot());

我曾尝试手动注册集线器,但没有成功,仍然是同样的问题

好消息是 SignalR 已经实现了 IHubContext<T> 在你的情况下你不需要注入 ITimerHub 接口。如果您的 TimerHub 已经实现 ITimerHub 就足够了在您的情况下它看起来像这样

public class HomeController : Controller
{
    private readonly IHubContext<TimerHub> _hubContext;

    public HomeController(IHubContext<TimerHub> hubContext)
    {
        _hubContext = hubContext;
    }
}

你也没有显示你的 startup.cs class.

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSignalR();
        ...
    }

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
     ...
     app.MapHub<TimerHub>("/yourEndPointGoesHere");
 }

如果你真的想要,我不推荐的是[看这里][1] 有一个在通用代码中使用 IHubContext 的示例。

我了解到您正在尝试学习新知识。是的,解耦应用程序很重要,这样您就可以朝着正确的方向前进,实现您想要实现的目标。但是,我不推荐您采用的这种方法。他的方法不适用于 99% 的项目。让我解释一下我的观点。不要被他的视频和博客中的流行语所吸引。请务必了解这些原则受您的应用程序的影响。

  1. 您的应用程序中没有 15,000 classes、服务、视图和 N 层等。

  2. 您不需要域驱动方法的灵活性。我见过大量的,我的意思是大量的项目,那些已有 25 年历史且拥有数百万行代码的项目。让我告诉你,你并没有像他所说的那样随意交换你的数据层。在一个大项目中,没有“这很容易”的方法来做到这一点。将它放在 Repos 和数据访问层中并没有真正的帮助。您可以放入数据访问层或您的服务。您仍然需要测试 150,000 行代码。它对我唯一有用的一次是当我有 4 个数据源都具有 getBy... 函数需要聚合来自 4 个源的信息时。您也不需要它进行单元测试。只需在单元测试中创建一个模拟变量,无需模拟数据库连接。我发现将单元测试实际连接到数据库更有用,即使它是一个依赖项,它实际上很有用。

  3. 他自己说过“你可以选择极简主义者 API 然后从那里开始努力”这是你应该做的。在没有代码的项目中,SOLID 和 Repos 有什么意义?例如 solid 中的 I 是接口的实现。接口做两件事 -

一个。告诉您的应用程序它应该做什么和不应该做什么。那么,您执行的是什么可能会破坏或需要这种抽象?

乙。解耦应用程序。你在哪里有 3+ 不同的 classes 被注入到一段代码中,根据类型具有相同的 DoSomething()

他谈到了其他只有当你有 500 种不同的事情发生时才适用的事情,而他的情况仍然有点过头了。

如果你想分解它,你可以采取一个简单的方法。

-MainApiProject
-ServicesProject (you can also put interfaces in here)
-InterfacesProject(if you need them between multiple projects and have a lot of them)
-UtilitiesProject

然后看看他在做什么,如果你看到你需要它就接受它。 我可以继续,但这会越来越长。 [1]: https://docs.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0