仅通过接口注入信号器集线器
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% 的项目。让我解释一下我的观点。不要被他的视频和博客中的流行语所吸引。请务必了解这些原则受您的应用程序的影响。
您的应用程序中没有 15,000 classes、服务、视图和 N 层等。
您不需要域驱动方法的灵活性。我见过大量的,我的意思是大量的项目,那些已有 25 年历史且拥有数百万行代码的项目。让我告诉你,你并没有像他所说的那样随意交换你的数据层。在一个大项目中,没有“这很容易”的方法来做到这一点。将它放在 Repos 和数据访问层中并没有真正的帮助。您可以放入数据访问层或您的服务。您仍然需要测试 150,000 行代码。它对我唯一有用的一次是当我有 4 个数据源都具有 getBy...
函数需要聚合来自 4 个源的信息时。您也不需要它进行单元测试。只需在单元测试中创建一个模拟变量,无需模拟数据库连接。我发现将单元测试实际连接到数据库更有用,即使它是一个依赖项,它实际上很有用。
他自己说过“你可以选择极简主义者 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
所以最近我开始了一个以 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% 的项目。让我解释一下我的观点。不要被他的视频和博客中的流行语所吸引。请务必了解这些原则受您的应用程序的影响。
您的应用程序中没有 15,000 classes、服务、视图和 N 层等。
您不需要域驱动方法的灵活性。我见过大量的,我的意思是大量的项目,那些已有 25 年历史且拥有数百万行代码的项目。让我告诉你,你并没有像他所说的那样随意交换你的数据层。在一个大项目中,没有“这很容易”的方法来做到这一点。将它放在 Repos 和数据访问层中并没有真正的帮助。您可以放入数据访问层或您的服务。您仍然需要测试 150,000 行代码。它对我唯一有用的一次是当我有 4 个数据源都具有
getBy...
函数需要聚合来自 4 个源的信息时。您也不需要它进行单元测试。只需在单元测试中创建一个模拟变量,无需模拟数据库连接。我发现将单元测试实际连接到数据库更有用,即使它是一个依赖项,它实际上很有用。他自己说过“你可以选择极简主义者 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