我有以下课程。我需要创建此调用的实例,以便可以从我尝试过的静态方法中调用非静态方法
EstablishmentHub establishmenthub = new EstablishmentHub();
但是由于这一行而无法正常工作
public EstablishmentsHub(IHubContext<EstablishmentsHub> hubcontext)
{
HubContext = hubcontext;
}
反正我可以创建一个实例吗?
public class EstablishmentsHub : Hub
{
public readonly static System.Timers.Timer _Timer = new System.Timers.Timer();
public EstablishmentsHub(IHubContext<EstablishmentsHub> hubcontext)
{
HubContext = hubcontext;
}
private IHubContext<EstablishmentsHub> HubContext
{
get;
set;
}
}
我正在尝试使用以下方法在启动时启动计时器功能
static EstablishmentsHub()
{
_Timer.Interval = 10000;
_Timer.Elapsed += TimerElapsed;
_Timer.Start();
}
但抱怨TimeElapsed(非静态字段需要对象引用)
我不想将TimeElasped设为静态,因为它下面有一些非静态的函数
void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
broadcaststatus("ayl-3",10);
}
答案 0 :(得分:2)
使用ASP核心
似乎您正在将集线器与一些长期运行的东西(计时器)混合在一起。您不应该这样做,也不需要集线器内部的IHubContext,因为此IHubContext仅允许您访问集线器而实际上没有集线器实例。
您应该从Hub类中删除IHubContext,而应将IHubContext注入到长时间运行的Background任务中。您可以阅读有关实现后台任务here的更多信息。使用此系统,您将不会使用计时器,而会使用某种延迟(可能),但这并不难更改,因此不必为此担心。
在那之后,您只需要做一些事情就可以使其协同工作。
-将Hub-classname终止在Hub上(已完成)。
-将Hub-class放置在名为Hubs的文件夹中。
-从Hub类中删除IHubContext,然后将其添加到后台任务中,方法与您当前在Hub类中使用的方法相同。
您现在可以使用IServiceCollection.AddHostedService<YourBackgroundService>()
将后台任务添加到系统中。您可以在ConfigureServices
类的Startup
方法中执行此操作。
您现在可以在后台服务内部使用IHubContext访问集线器,它将能够执行所有基于超时/计时器的任务。在集线器本身周围有逻辑不应该放在集线器类中。
我希望这会有所帮助。如果您不使用ASP Core,那么我将继续删除此答案。
编辑:
您的后台服务可能看起来像这样:
public class SomeTimedService : Microsoft.Extensions.Hosting.BackgroundService
{
private IHubContext<EstablishmentsHub> _hubContext;
public SomeTimedService(IHubContext<EstablishmentsHub> hubcontext)
{
_hubContext = hubcontext;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _hubContext.Clients.All.BroadcastStatus("ayl-3", 10);
try
{
await Task.Delay(10000, stoppingToken);
}
catch (TaskCanceledException) {
return;
}
}
}
}
如果将stopToken取消,则将其添加到Task.Delay
会抛出TaskCanceledException
。只需停止循环并在发生这种情况时返回即可。
我还建议您使用strongly-typed hubs,因为它们有很多好处。
完整的解决方案(包括您编写的有关应用程序的所有内容)将如下所示:
// background service for sending a (currently hardcoded) status every 10 seconds to every client
public class EstablishmentsService : Microsoft.Extensions.Hosting.BackgroundService
{
private IHubContext<EstablishmentsHub, IEstablishmentsClient> _hubContext;
public EstablishmentsService(IHubContext<EstablishmentsHub, IEstablishmentsClient> hubcontext)
{
_hubContext = hubcontext;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _hubContext.Clients.All.ReceiveStatus("ayl-3", 10);
try
{
await Task.Delay(10000, stoppingToken);
}
catch (TaskCanceledException) {
return;
}
}
}
}
// the client of the hub. Here you place methods which should be called by the application.
public interface IEstablishmentsClient
{
Task ReceiveStatus(string someString, int someInt);
}
// the hub itself. You'd place methods here which should be called from the client
public class EstablishmentsHub : Hub<IEstablishmentsClient>
{
private readonly YourSQLThingy _sqlThingy;
public EstablishmentsHub(YourSQLThingy sQLThingy)
{
_sqlThingy = sQLThingy;
}
public SomeObject GetFirstObject()
{
return _sqlThingy.Whatever.First();
}
public void SomeHubMethod()
{
// do something here
}
}
在Startup.ConfigureServices(IServiceCollection services)
内,您需要致电:
services.AddHostedService<EstablishmentsService>();
当然,您也必须添加js。在我的项目中,我使用了一些代码在Startup类的Configure
方法中注册了signalR-url:
app.UseSignalR(routes =>
{
routes.MapHub<EstablishmentsHub>("/establishmentsSignalR");
});
在js中,您现在可以使用相同的url获取集线器(几乎可以肯定还有其他方法没有url,但我是这样做的):
var connection = new signalR.HubConnectionBuilder().withUrl("/establishmentsSignalR").build();
获得此连接后,可以对所有客户端方法使用connection.on(xxxx, ..)
,对所有集线器方法使用connection.xxxx(..)
。
在此示例中,您将执行以下操作:
connection.on("ReceiveStatus", function (someString, someInt) {
// do whatever with those two values
// if it's a bigger object it will simply be converted to a jsonObject
});
现在,您已经设置了客户端发生的事情。现在,您可以使用connection.start();
启动连接。
请注意,在js中,您只需使用connection.SomeHubMethod()
即可调用中心中定义的方法(我在完整解决方案中将该方法添加到了中心中)。如果您使用参数/返回值,它们都将在json和c#对象之间转换。
这就是您需要做的,而不是那么多:)。
我们要到达那里。现在,您已经删除了所有不应该用于远程处理的非公开方法,这非常好。这些方法与sql有关,因此您应该将它们放在一个单独的类中,该类的好名字告诉它是用于检索数据。
假设您已经定义并填充了您的课程。您现在需要做的是将其注册到DI系统。使用db-stuff,您通常需要一个单例,但如果不了解类包含/执行的操作,则无法决定。
您可以在Startup-class的ConfigureServices
方法内注册该类。 services.AddSingleton<YourSQLThingy>();
现在,DI系统知道您的班级,您只需将其注入到任何需要的地方即可。为此,将它放到Hubs构造函数中(我更新了“完整”解决方案”)。DI系统将在激活您的集线器时自动找到注册的类并将其注入。请注意,由于您在此处使用单例,它将永远是注入的同一实例!
答案 1 :(得分:0)
如果您使用的是ASP.NET Core,则可以使用依赖项注入来获取IHubContext的实例。
如果您使用的是ASP.NET 4.x,则可以通过GlobalHost访问IHubContext。
var hubContext = GlobalHost.ConnectionManager.GetHubContext<SomeHub>();