如何使用 HttpClientFactory 和 PolicyRegistry 传递记录器?

How do you pass a logger using HttpClientFactory and a PolicyRegistry?

我一直在阅读 this,它似乎有办法做我想做的事。

我显然有类似的东西,但在 PolicyContextExtensions 中,context.TryGetValue 需要 PolicyContextItems。这对我来说显示为未定义的对象。

这是从哪里来的,怎么设置的?

此处供参考 PolicyContextExtensions class:

public static class PolicyContextExtensions
{
    public static bool TryGetLogger(this Context context, out ILogger logger)
    {
        if(context.TryGetValue(PolicyContextItems.Logger, out var loggerObject) && loggerObject is ILogger theLogger)
        {
            logger = theLogger;
            return true;
        }

        logger = null;
        return false;
    }
}

Polly 的 Context class 基本上是 Dictionary<string, object>.
这意味着您可以使用任意字符串注册任何类型的数据。

在教程中,斯蒂芬创建了一个新的上下文,如下所示:

var context = new Context($"GetSomeData-{Guid.NewGuid()}", new Dictionary<string, object>
{
    { PolicyContextItems.Logger, _logger }
});
  • 任意字符串为$"GetSomeData-{Guid.NewGuid()}"
  • 其中数据是 Dictionary<string, object>

于是,他又在字典里面又编了一本字典。为什么?因为有了这个,您可以根据方法对要传递的数据进行分组(如 GetSomeData...

在这种情况下,PolicyContextItems.Logger 只是 logger 的字符串常量:

public static class PolicyContextItems
{
    public const string Logger = "logger";
}

如果你想避免嵌套字典,但你想根据方法对它们进行分组,那么你可以简单地为键添加前缀并使用 Add 方法:

var context = new Context();
context.Add("GetSomeData-Logger", _logger);
context.Add("GetSomeData-XYZ", _xyz);

以上方案都是显式设置数据的key,容易出错。您不仅需要在策略创建期间知道该名称,而且还需要在您想要访问传递的数据时知道该名称。

一种更方便的方法是将密钥存储在 settergetter 方法旁边:

public static class ContextExtensions
{
    private static readonly string LoggerKey = "LoggerKey";

    public static Context WithLogger(this Context context, ILogger logger)
    {
        context[LoggerKey] = logger;
        return context;
    }

    public static ILogger GetLogger(this Context context)
    {
        if (context.TryGetValue(LoggerKey, out object logger))
        {
            return logger as ILogger;
        }
        return null;
    }
}

此示例取自 official documentation