Skip to content

Instantly share code, notes, and snippets.

@felipebaltazar
Created September 10, 2020 18:51
Show Gist options
  • Save felipebaltazar/199030fee98a7d990f7eed75bad47ae4 to your computer and use it in GitHub Desktop.
Save felipebaltazar/199030fee98a7d990f7eed75bad47ae4 to your computer and use it in GitHub Desktop.
internal sealed class MeuServico : ObjectWithPolicy {
#region Fields
//Api refit
private readonly IApiClient _apiClient;
#endregion
#region Constructors
public MeuServico(string baseUrl) {
_apiClient = RestService.
.For<IPontoCloudApiClient>(baseUrl);
}
#endregion
#region IUserResource
public async Task<UserToken> LoginAsync(UserInfo userInfo) {
var loginResult = await RequestWithPolicy(() => _apiClient.LoginAsync(userInfo)).ConfigureAwait(false);
return loginResult;
}
public async Task<UserToken> RefreshLoginAsync(string refreshToken) {
var loginResult = await RequestWithPolicy(() => _apiClient.RefreshLoginAsync(refreshToken)).ConfigureAwait(false);
return loginResult;
}
public async Task<UserToken> SignInAsync(UserInfo userInfo) {
var signinResult = await RequestWithPolicy(() => _apiClient.SignInAsync(userInfo)).ConfigureAwait(false);
return signinResult;
}
#endregion
}
internal abstract class ObjectWithPolicy {
#region Fields
private const int MAX_REFRESH_TOKEN_ATTEMPTS = 1;
private const int MAX_RETRY_ATTEMPTS = 3;
private readonly IAsyncPolicy _authPolicy;
private readonly IAsyncPolicy _asyncPolicy;
#endregion
#region Constructors
protected ObjectWithPolicy() : this(null) { }
protected ObjectWithPolicy(int? numberOfRetries) {
_authPolicy = Policy
.HandleInner<ApiException>(AuthStatusCodeFilter)
.RetryAsync(MAX_REFRESH_TOKEN_ATTEMPTS, RefreshAuthorizationAsync);
_asyncPolicy = Policy
.Handle<ApiException>(StatusCodeFilter)
.WaitAndRetryAsync(numberOfRetries ?? MAX_RETRY_ATTEMPTS, SleepDuration);
}
#endregion
#region Protected Methods
/// <summary>
/// Executa a requisição usando uma politica de resiliência
/// </summary>
/// <typeparam name="T">Resultado da requisição</typeparam>
/// <param name="func">Função de requisição</param>
/// <returns>Resultado da requisição</returns>
protected async Task<T> RequestWithPolicy<T>(Func<Task<T>> func) =>
await _asyncPolicy.WrapAsync(_authPolicy).ExecuteAsync(func).ConfigureAwait(false);
/// <summary>
/// Executa a requisição usando uma politica de resiliência
/// </summary>
/// <param name="func">Função de requisição</param>
protected async Task RequestWithPolicy<T>(Func<Task> func) =>
await _asyncPolicy.WrapAsync(_authPolicy).ExecuteAsync(func).ConfigureAwait(false);
/// <summary>
/// Executa uma requisição para atualizar token de autorização
/// </summary>
/// <param name="error"></param>
/// <param name="attempt"></param>
/// <returns></returns>
protected virtual Task RefreshAuthorizationAsync(Exception error, int attempt) =>
Task.CompletedTask;
#endregion
#region Private Methods
private static bool StatusCodeFilter(ApiException ex) =>
ex.StatusCode != HttpStatusCode.NotFound && ex.StatusCode != HttpStatusCode.Forbidden;
private static bool AuthStatusCodeFilter(ApiException ex) =>
ex.StatusCode == HttpStatusCode.Unauthorized;
private static TimeSpan SleepDuration(int attempt) =>
TimeSpan.FromSeconds(Math.Pow(2, attempt));
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment