Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How could I configure Polly in a lubrary that is in a class library instead of the main application? #1072

Closed
ComptonAlvaro opened this issue Mar 20, 2023 · 2 comments · Fixed by #1322
Labels
v8 Issues related to the new version 8 of the Polly library.
Milestone

Comments

@ComptonAlvaro
Copy link

I would like to use Polly to handle the retries in some cases.

By the moment, I have a class library with the gRPC client, is this:

public class MyClient : IClient
{

    IClientService _client;




    public MyClient(string paramAddress, int paramPort, string? paramTokenJwt = null)
    {
        SocketsHttpHandler miHttpHandler = new SocketsHttpHandler();
        //To validate self sifned certificate from the server. By the moment it returns only true for test purposes.
        miHttpHandler.SslOptions.RemoteCertificateValidationCallback = ValidateServerCertificate;

        //To can add credentials or JWT token.
        //is there a better option to add credentials with a factory???
        HttpClient miHttpClient = new HttpClient(miHttpHandler);


        //The options of the channel. It will have the JWT token for authentication and another connection settings.
        GrpcChannelOptions myChannelOptions = new GrpcChannelOptions()
        {
            MaxReceiveMessageSize = 62914560,
            MaxSendMessageSize = 62914560,
            HttpClient = httpClient,
        };

        //I add the token to the channel if it is given. If not, the channel will can be used to call the login
        //method of the service, that doesn't need authentication.
        if (string.IsNullOrWhiteSpace(paramStrTokenJwt) == false)
        {
            CallCredentials myCredentials = CallCredentials.FromInterceptor((c, m) =>
            {
                m.Add(HeaderNames.Authorization, $"Bearer {paramStrTokenJwt}");
                return Task.CompletedTask;
            });

            myChannelOptions.Credentials = ChannelCredentials.Create(new SslCredentials(), myCredentials);
        }


        //Create the channel
        Uri miUri = new Uri("{paramAddress}:{paramPort.ToString()}");
        GrpcChannel myChannel = GrpcChannel.ForAddress(miUri, myChannelOptions);


        //Create the client
        _client = GrpcClientFactory.CreateGrpcService<IMyService>(myChannel);
    }
}

This is a code that I have seen to use Polly:

var retryPolicy = HttpPolicyExtensions
                .HandleTransientHttpError() // HttpRequestException, 5XX and 408
                .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

services.AddHttpClient<ISuperHeroService, SuperHeroService>(o => 
                            o.BaseAddress = new Uri(Configuration["SuperHeroApiConfig:BaseUrl"]))
                .AddPolicyHandler(retryPolicy);

They are using Services.AddHttpClient to register the client. Services, if I am not wrong, it is availalble at application level (console application, WPF... and so on) but it is not available at class library level, that it is where I am creating the client.

I have seen in the documentation that I can create a policy in each method and the use the method Excute() to run the method:

var policy = Policy
    .Handle<SomeExceptionType>()
    .Retry(3, (exception, retryCount, context) =>
    {
        object methodThatRaisedException = context["methodName"];
        Log(exception, methodThatRaisedException)
    });

But it seems that it is needed to repeat more code and int less transparent.

If I don't misundertand the example code in which is used the serices.AddHttpClient, just the policy is added to the AddHttpClient and every method of this client will use the policy, it is not needed to wrap the method in the Execute() method.

So I was wondering if it is possible to use policies in a way that is not needed to wrap the method in the Excute() method.

Thanks.

@PeterCsalaHbo
Copy link

PeterCsalaHbo commented Mar 22, 2023

If I understand you correctly you want to use a polly decorated typed client which is defined in a class library.

There are multiple ways to solve your problem, let me present here the two most common solutions.

Provide a self-registration function

It is quite common to expose a method from your library against IServiceCollection

public static IServiceCollection AddMyClient(this IServiceCollection services, Uri baseUrl) 
{
    services.AddHttpClient<ISuperHeroService, SuperHeroService>(o => o.BaseAddress = baseUrl)
                   .AddPolicyHandler(GetRetryPolicy());
    return services;
}

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() 
{
   ...
}

This allows you to provide a single registration function which wires up all components correctly ~ like a factory method

Using directly the PolicyHttpMessageHandler

As I can see you are explicitly creating an HttpClient instance inside the MyClient. Here you can provide multiple handlers by chaining them (via InnerHandler).

Polly exposes a handler called PolicyHttpMessageHandler which allows you register any policy
(Side note: The AddPolicyHandler uses exactly this handler)

var pollyHandler = new PolicyHttpMessageHandler(retryPolicy);
pollyHandler.InnerHandler = miHttpHandler;

var miHttpClient = new HttpClient(pollyHandler);

For more details please check this SO thread.

@martintmk
Copy link
Contributor

Polly V8 also allows overriding the resilience strategies that are defined by library. See the #1322.

@martincostello martincostello added the v8 Issues related to the new version 8 of the Polly library. label Jun 19, 2023
@martincostello martincostello added this to the v8.0.0 milestone Jun 19, 2023
@github-project-automation github-project-automation bot moved this to Done in Polly v8 Jun 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v8 Issues related to the new version 8 of the Polly library.
Projects
No open projects
Status: Done
Development

Successfully merging a pull request may close this issue.

4 participants