[英]How to implement an ILogger to send messages to a SignalR Hub?
我想構建一個顯示最新日志消息的 LogView。 所以我建立了一個非常簡單的設置,但我在依賴注入失敗了。
這是我對實現的嘗試。 我跳過了非關鍵部分。
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;
}
}
我的問題基本上是我無法注入IHubContext
,我不知道如何解決這個問題
問題是LoggerProvider
是在注冊SignalR
集線器之前創建的。 因此,在創建記錄器提供程序時,尚未初始化IServiceProvider
以了解任何IHubContext<T>
對象。
我能找到解決它的唯一方法是將IServiceProvider
提供給您的ILogger
並讓它在需要時獲取IHubContext
的實例。
您的記錄器類需要在其構造函數中接受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);
}
}
}
我們需要檢查IHubContext
是否已從服務提供者處檢索到,因為可以在注冊集線器之前調用記錄器。 這是使用 SignalR 作為記錄器的缺點之一,因為在可以訪問HubContext
之前您會錯過一些早期消息(但這對您來說可能是可以接受的)。
注意:您可以改進它以存儲集線器,而不是在每次日志調用時都獲取它-但我將其留給您實現:-)
現在,您需要更改提供程序以在創建記錄器時提供該參數:
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;
}
}
最后,您需要將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));
});
我們需要調用BuildServiceProvider
方法來創建我們需要的接口,因為它在ConfigureLogging
調用中不可用 - 但它會給我們正確的接口來使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.