如何实现 ILogger 将消息发送到 SignalR Hub?

2024-01-31

我想构建一个显示最新日志消息的 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方法来创建我们需要的接口,因为它在ConfigureLoggingcall - 但它会给我们正确的接口来使用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何实现 ILogger 将消息发送到 SignalR Hub? 的相关文章

随机推荐

  • 读取 txt 文件 fscanf 与 fread 与 textscan [重复]

    这个问题在这里已经有答案了 我有一个从 SQL 2005 生成的 txt 文件 ANSI 格式 我努力了textscan and fscanf 整个txt文件只有numeric data 在线资源表明 fscanf 比 textscan 更
  • 获取外部文件目录失败

    OnActivityCreated 我正在做 activity getExternalFilesDir Environment DIRECTORY PICTURES 在 logcat 中我得到 com package W ContextIm
  • 流过滤器的时间复杂度

    我有这样的代码 List
  • 如何在delphi中使用ToastGeneric创建toast通知

    我正在使用 delphi 在桌面上进行开发 我想使用 ToastGeneric 类型通知创建 toast 通知 LToastFactory CreateToastNotification LXMLTemplate 另外 我正在使用 xml
  • 通过“with”语句使用 Python 队列

    有没有使用Python的标准方法Queue in a with陈述 这就是我希望能够使用它的方式 import Queue myqueue Queue Queue with myqueue as nextItem doStuff nextI
  • Shell 脚本 - 在文件中智能替换并在第二个文件中查找

    我有两个文件 一个数据文件和一个查找文件 数据文件的一个字段必须由一个值更改 该值可以在查找文件中找到 数据文件如下所示 2013 04 24 1 0 1635 1 4135 2013 04 24 1 0 9135 1 4135 2013
  • javascript 正则表达式计算空白字符

    我可以使用 javascript 正则表达式来计算字符串中第一个文本字符之前的空白字符数吗 我只关心是否有0 1和2 我当前的工作解决方案是拥有三个正则表达式 仅使用 match 来确定 0 1 或 2 类别 每个类别都有单独的模式 但我正
  • Oracle SQL 中是否有类似于 SUM 函数的 PRODUCT 函数?

    我有一个同事正在寻找这个 但我不记得曾经遇到过类似的事情 有没有一种合理的技术可以让你模拟它 SELECT PRODUCT X FROM SELECT 3 X FROM DUAL UNION ALL SELECT 5 X FROM DUAL
  • 单线程/核心上的并行如何可能?

    现代编程语言为用户提供了一流的并行和并发机制 我了解并行算法是如何编程的 并且可以很好地想象多核CPU上的两个线程如何并行运行 然而 大多数这些平台还支持在单个线程上运行并行进程 这些进程真的并行运行吗 在汇编级别上 两个不同的例程如何在单
  • 为什么这段代码在 jsbin 中有效,但在 jsfiddle 中无效?

    我按照此处另一位用户的建议重新发布 重新表述此内容 下面的代码适用于jsbin http jsbin com osebov 1 edit但不在jsfiddle http jsfiddle net wNaEX 有人知道为什么吗 该问题源于我尝
  • 如何从内容页访问母版页中的用户控件?

    假设我在母版页中有一个标头用户控件 并且想要根据母版页内加载的内容页来更改用户控件的属性 我该怎么办 Thanks 您可以使用两种方法 第一个是通过使用Page Master FindControl controlID 然后您可以将其转换为
  • 查找嵌套 json 对象深处的对象

    我在下面的代码片段中有嵌套的 json 对象 想要查找所有出现的 schema 并将包含该架构值的整个对象保存到另一个对象中 我尝试使用 lodash 过滤器 但没有成功 有没有人有什么建议 element parseResult cont
  • 预授权不起作用

    我正在编写一个套接字服务器 无 Web 应用程序 应用程序 并希望使用基于方法的安全性来处理我的 ACL 需求 我按照我发现的一个小教程进行操作春季安全举例 http blog solidcraft eu 2011 03 spring se
  • 为什么我不能使用“scanf_s”同时读取字符和数字?

    这段代码崩溃了 scanf s c d ch x Run error 但这段代码有效 scanf s c ch scanf s d x Run succeed 我想知道为什么第一个代码片段是错误的 运行错误 的意思是 当我运行程序输入时 编
  • 返回 false 不停止表单提交

    我很确定这应该不会那么难 我有一个在提交时运行以下函数的表单 function FORMVALIDATE add rota entry var rota date rota date val var rota id rota id val
  • 自定义 Slack 机器人无法连接

    我一直在尝试制作一个 Slack 机器人 它可以回复简单的查询并做一些简单的事情来帮助办公室工作 该机器人工作正常 只是似乎无法从我们的代理后面连接到 Slack 当我从自己的移动互联网连接测试它时 它工作正常 但是当尝试在代理后面运行它时
  • Android 此功能需要 ASM7

    可能重复 https stackoverflow com questions 68709559 nestmember requires asm7 noredirect 1 我已将 Android Studio 更新为 Android Stu
  • 使用 automake 安装包含大量文件的数据目录树

    我有一个数据目录 我希望 automake 为其生成安装和卸载目标 本质上 我只想将此目录逐字复制到 DATA 目录 通常 我可能会单独列出所有文件 例如 dist whatever DATA dir subdir filea 但是当我的目
  • 如何在 spring Restapi 的 json 请求中的未知字段上抛出错误

    我有一个 spring Rest api 它获取 json 数据并绑定到 pojo GetData 每当我收到未知字段时 它都不会失败或抛出任何异常 我的要求是当它接收到 json 数据中的未知字段时应该抛出错误 public Respon
  • 如何实现 ILogger 将消息发送到 SignalR Hub?

    我想构建一个显示最新日志消息的 LogView 所以我构建了一个非常简单的设置 但在依赖注入方面失败了 这是我的实施尝试 我跳过了非关键部分 public class SignalRLogger ILogger private readon