仅通过接口注入SignalR Hub

发布于 2025-01-21 09:23:22 字数 2113 浏览 0 评论 0原文

因此,最近我以 ardalis清洁体系结构作为模板开始了一个项目,这一切都很好,但是当 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>();
    }

Web层:

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

我尝试在没有运气的情况下手动注册集线器,仍然相同的问题

So recently I started a project with Ardalis Clean Architecture as template it was all nice but when signalR came into my project i can't figure it. I'm trying to inject interface that my hub implements and call it's method, but everytime when it's called it throws NullReferenceException, it seems like all of the signalR components are null within this injected interface. Registered all hubs and registered it's interfaces using AutoFac. Trying to avoid situation when I'm forced to reference signalR package within core layer.

Core layer:

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

Infrastructure layer:

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

Web layer:

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

I was trying manually registering hubs with no luck, still same issue

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

灯下孤影 2025-01-28 09:23:22

好消息是Signalr已经实现iHubContext&lt; t&gt;在您的情况下,您无需注入itimerHub接口。如果您的TimerHub已经实现了Itimerhub,那么在您的情况下,它也已经足够好了

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

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

,您也没有显示您的startup.cs类。

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

如果

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

您真的愿意,我不建议[在这里查看它] [1]
在通用代码中使用iHubContext有一个示例。

我知道您正在尝试学习新知识。是的,很重要的是,将应用程序解次,这样您就可以朝着要实现的目标朝着正确的方向前进。但是,我不建议您采用这种方法。他的方法不适用于99%的项目。让我解释一下我的观点。不要被他的视频和博客中的流行语所吸引。重要的是要了解这些委托人对您的申请是主观的。

  1. 您没有15,000堂课,服务,视图和n层等...在您的应用中。

  2. 您不需要域驱动方法的灵活性。我已经看到了巨大的大规模项目,这是25岁,有数百万行代码的项目。让我告诉您,您并没有像他看起来一样互换所有Willy Nilly的数据层。在一个大项目上,没有“简单”的方法来做到这一点。将其放入存储库中,并且数据访问层并没有真正的帮助。您可以放入数据访问层或服务中。您仍然需要测试150,000行代码。对我来说,唯一有用的是,当我拥有4个数据源时,所有数据源都具有getby ...函数,需要从4个来源汇总信息。您也不需要单元测试。只需在单元测试中创建模拟变量即可模拟您的数据库连接。我发现,即使您的单元测试实际上是一个依赖性,实际上是有用的。

  3. 他自己说:“您可以使用极简主义的API并从那里努力工作”,这就是您应该做的。没有代码的项目中固体和存储库的重点是什么?例如,固体中的i是接口的实现。接口做2件事 -

。告诉您的应用程序应该和不应该做什么。那么,您正在执行什么可能打破或需要这种抽象?

B.将应用程序解除。基于类型,您在哪里有3个以上的不同类别的代码中注入一件代码() ?

他触摸只有在您进行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”> https:https://学习。 microsoft.com/en-us/aspnet/core/signalr/hubcontext?view = aspnetcore-6.0

The good news is SignalR already implements IHubContext<T> In your case you don't need to inject ITimerHub interface. If your TimerHub Already Implements ITimerHub that's good enough In your case it would look like this

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

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

Also you didn't show your startup.cs class.

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

and

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

If you really wanted to, which I don't recommend is [look at it here][1]
There is an example on using IHubContext in generic code.

I understand you're trying to learn something new. And yes, it's important to decouple application so you're headed in the right direction in what you want to achieve. However I wouldn't recommend this approach you are taking. His approach doesn't apply to 99% of the projects out there. Let me explain my point of view. Don't get pulled in by the buzz words in his videos and blogs. It's important to understand that these principals are SUBJECTIVE to your application.

  1. You don't have 15,000 classes, services, views, and N Layers etc... in your app.

  2. You don't need the flexibility of a domain driven approach. I've seen massive and I mean massive projects, ones that are 25 years old and have millions of lines of code. Let me tell you you're not swapping out your data layer all willy nilly like he makes it seem to be. On a big project there is no "it makes it easy" way to do that. Putting it in Repos and a data access layer doesn't really help. You can put in a data access layer, or in your services. You still need to test out 150,000 lines of code. The only time it's been useful for me is when I've had 4 data sources all having a getBy... function that needs to aggregate info from 4 sources. You don't need it for unit testing either. Just create a mock variable in your unit tests no need to mock your db connection. I find it more useful to have your unit tests actually hooked up to a database even though it's a dependency, it's actually useful.

  3. He said it himself "You can go with a minimalist API and work your way up from there" Which is what you should do. What's the point of SOLID and Repos in a project with no code? For example the I in solid is implementation of interfaces. Interfaces do 2 things -

A. Tell your application what it should and shouldn't do. so, what are you enforcing that could break or needs this kind of abstraction?

B. Decouple the application. Where do you have 3+ different classes being injected in one piece of code with the same DoSomething() based on the type?

He touches over other things that only apply when you have 500 different things going on, and his case it's still overkill.

If you want to break it up you can take a simple approach.

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

Then look at what he's doing and if you see you need it take it.
I can go on but this is getting long as is.
[1]: https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0

无声无音无过去 2025-01-28 09:23:22

这是对我有用的使用(轮毂和接口):

private readonly IHubContext<MessageHub,IMsgHub> HubContext;

public BMController(IHubContext<MessageHub, IMsgHub> ctx)
{
    HubContext = ctx;
}

This is what worked for me use (both Hub and Interface):

private readonly IHubContext<MessageHub,IMsgHub> HubContext;

public BMController(IHubContext<MessageHub, IMsgHub> ctx)
{
    HubContext = ctx;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文