sr28
sr28

Reputation: 5136

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

I've been reading this which seems to have a way of doing what I want.

I've got something similar obviously, but within the PolicyContextExtensions the context.TryGetValue takes PolicyContextItems. This shows as an undefined object for me.

Where does this come from and how is this set?

For reference here is the 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;
    }
}

Upvotes: 3

Views: 625

Answers (1)

Peter Csala
Peter Csala

Reputation: 22829

The Polly's Context class is basically a Dictionary<string, object>.
Which means you can register any kind of data with an arbitrary string.

In the tutorial Stephen has created a new context like this:

var context = new Context($"GetSomeData-{Guid.NewGuid()}", new Dictionary<string, object>
{
    { PolicyContextItems.Logger, _logger }
});
  • The arbitrary string is $"GetSomeData-{Guid.NewGuid()}"
  • Where as the data is a Dictionary<string, object>

So, he had created a yet another dictionary inside the dictionary. Why? Because with this you can group the to be passed data on a method basis (like GetSomeData...)

In this case the PolicyContextItems.Logger is just a string constant for logger:

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

If you want to avoid nesting dictionaries but you want to group them on a method basis then you can simply prefix the keys and use the Add method:

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

All the above solutions are explicitly setting the key of the data, which is error-prone. You need to know the name not just during the Policy creation but whenever you want to access the passed data as well.

A more convenient approach is to store the key next to the setter and getter methods:

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;
    }
}

This example was taken from the official documentation.

Upvotes: 2

Related Questions