[英]How to implement an ILogger to send messages to a SignalR Hub?
I want to build a LogView which shows the latest log messages.我想构建一个显示最新日志消息的 LogView。 So I've built a really simple setup but I fail at Dependency Injection.
所以我建立了一个非常简单的设置,但我在依赖注入失败了。
Here's my attempt at an implementation.这是我对实现的尝试。 I've skipped the non-crucial parts.
我跳过了非关键部分。
public class SignalRLogger : ILogger
{
private readonly IHubContext<LogHub> _hub;
public SignalRLogger(IHubContext<LogHub> hub)
{
_hub = hub;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var msg = $"[{logLevel}] {formatter(state, exception)}";
_hub.Clients.All.SendAsync("ReceiveMessage", msg);
}
}
public class SignalrRLoggerProvider : ILoggerProvider
{
private SignalRLogger _logger;
public void Dispose()
{
_logger = null;
}
public ILogger CreateLogger(string categoryName)
{
if (_logger == null)
{
_logger = new SignalRLogger(????);
}
return _logger;
}
}
My problem basically is that I can't inject an IHubContext
and I'm not sure how to solve this issue我的问题基本上是我无法注入
IHubContext
,我不知道如何解决这个问题
The problem is that the LoggerProvider
is created before SignalR
hubs are registered.问题是
LoggerProvider
是在注册SignalR
集线器之前创建的。 So when the logger provider is created the IServiceProvider
has not been initialized to know about any IHubContext<T>
objects.因此,在创建记录器提供程序时,尚未初始化
IServiceProvider
以了解任何IHubContext<T>
对象。
The only way I can find to solve it is to provide the IServiceProvider
to your ILogger
and let it get an instance of the IHubContext
when it needs it.我能找到解决它的唯一方法是将
IServiceProvider
提供给您的ILogger
并让它在需要时获取IHubContext
的实例。
Your logger class needs to accept an IServiceProvider
in it's constructor and then use that object to retrieve the IHubContext
on demand:您的记录器类需要在其构造函数中接受
IServiceProvider
,然后使用该对象按需检索IHubContext
:
public class SignalRLogger : ILogger
{
private readonly IServiceProvider _sp;
public SignalRLogger(IServiceProvider sp)
{
_sp = sp;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var hub = _sp.GetService<IHubContext<LogHub>>();
if (hub != null)
{
var msg = $"[{logLevel}] {formatter(state, exception)}";
hub.Clients.All.SendAsync("ReceiveMessage", msg);
}
}
}
We need to check that the IHubContext
has been retrieved from the service provider as the logger can be called before the hub has been registered.我们需要检查
IHubContext
是否已从服务提供者处检索到,因为可以在注册集线器之前调用记录器。 And this is one of the downsides to using SignalR as a logger because you will miss some early messages before the HubContext
can be accessed (but this may be acceptable to you).这是使用 SignalR 作为记录器的缺点之一,因为在可以访问
HubContext
之前您会错过一些早期消息(但这对您来说可能是可以接受的)。
NOTE: You can improve this to store the hub instead of getting it on every log call - but I'll leave that for you to implement :-)注意:您可以改进它以存储集线器,而不是在每次日志调用时都获取它-但我将其留给您实现:-)
Now you need to change your provider to supply that parameter when it creates the logger:现在,您需要更改提供程序以在创建记录器时提供该参数:
public class SignalrRLoggerProvider : ILoggerProvider
{
private SignalRLogger _logger;
private readonly IServiceProvider _sp;
public SignalrRLoggerProvider(IServiceProvider sp)
{
_sp = sp;
}
public ILogger CreateLogger(string categoryName)
{
if (_logger == null)
{
_logger = new SignalRLogger(_sp);
}
return _logger;
}
}
Finally you need to provider the IServiceProvider
to the logger provider:最后,您需要将
IServiceProvider
给记录器提供者:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(builder =>
{
var sp = builder.Services.BuildServiceProvider();
builder.AddProvider(new SignalrRLoggerProvider(sp));
});
We need to call the BuildServiceProvider
method to create the interface we need as it's not available in ConfigureLogging
call - but it will give us the correct interface to use.我们需要调用
BuildServiceProvider
方法来创建我们需要的接口,因为它在ConfigureLogging
调用中不可用 - 但它会给我们正确的接口来使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.