153 lines
5.5 KiB
C#
153 lines
5.5 KiB
C#
using Indotalent.ConfigBackEnd.Interfaces;
|
|
using Indotalent.Features.Account.Login.Cqrs;
|
|
using Indotalent.Infrastructure.Authentication.Identity;
|
|
using Indotalent.Shared.Models;
|
|
using Microsoft.AspNetCore.Components;
|
|
using MudBlazor;
|
|
using RestSharp;
|
|
using System.Net;
|
|
|
|
namespace Indotalent.ConfigFrontEnd.Common;
|
|
|
|
public abstract class BaseService
|
|
{
|
|
protected readonly IHttpClientFactory ClientFactory;
|
|
protected readonly NavigationManager Nav;
|
|
protected readonly ISnackbar Snackbar;
|
|
protected readonly ICurrentUserService CurrentUserService;
|
|
protected readonly TokenProvider TokenProvider;
|
|
|
|
public BaseService(
|
|
IHttpClientFactory clientFactory,
|
|
NavigationManager nav,
|
|
ISnackbar snackbar,
|
|
ICurrentUserService currentUserService,
|
|
TokenProvider tokenProvider)
|
|
{
|
|
ClientFactory = clientFactory;
|
|
Nav = nav;
|
|
Snackbar = snackbar;
|
|
CurrentUserService = currentUserService;
|
|
TokenProvider = tokenProvider;
|
|
}
|
|
|
|
protected HttpClient CreateClient()
|
|
{
|
|
var client = ClientFactory.CreateClient();
|
|
if (client.BaseAddress == null)
|
|
{
|
|
client.BaseAddress = new Uri(Nav.BaseUri);
|
|
}
|
|
return client;
|
|
}
|
|
|
|
protected async Task<ApiResponse<T>?> ExecuteWithResponseAsync<T>(RestClient client, RestRequest request)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(TokenProvider.Token))
|
|
request.AddOrUpdateHeader("Authorization", $"Bearer {TokenProvider.Token}");
|
|
|
|
if (!string.IsNullOrEmpty(TokenProvider.RefreshToken))
|
|
request.AddOrUpdateHeader("X-Refresh-Token", TokenProvider.RefreshToken);
|
|
|
|
if (!string.IsNullOrEmpty(CurrentUserService.UserId))
|
|
{
|
|
request.AddOrUpdateHeader("X-UserId", CurrentUserService.UserId);
|
|
request.AddOrUpdateHeader("X-UserName", CurrentUserService.UserName ?? string.Empty);
|
|
request.AddOrUpdateHeader("X-Email", CurrentUserService.Email ?? string.Empty);
|
|
request.AddOrUpdateHeader("X-FullName", CurrentUserService.FullName ?? string.Empty);
|
|
}
|
|
|
|
var response = await client.ExecuteAsync<ApiResponse<T>>(request);
|
|
|
|
|
|
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
|
{
|
|
var httpClient = CreateClient();
|
|
|
|
var refreshRequestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/account/refresh-token");
|
|
|
|
if (!string.IsNullOrEmpty(TokenProvider.RefreshToken))
|
|
{
|
|
refreshRequestMessage.Headers.Add("X-Refresh-Token", TokenProvider.RefreshToken);
|
|
}
|
|
|
|
var refreshResponse = await httpClient.SendAsync(refreshRequestMessage);
|
|
|
|
if (refreshResponse.IsSuccessStatusCode)
|
|
{
|
|
var result = await refreshResponse.Content.ReadFromJsonAsync<LoginResponse>();
|
|
if (result != null && !string.IsNullOrEmpty(result.Token))
|
|
{
|
|
TokenProvider.Token = result.Token;
|
|
|
|
request.AddOrUpdateHeader("Authorization", $"Bearer {TokenProvider.Token}");
|
|
response = await client.ExecuteAsync<ApiResponse<T>>(request);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Nav.NavigateTo("/account/login");
|
|
return default;
|
|
}
|
|
}
|
|
|
|
if (response.Data != null)
|
|
{
|
|
if (!response.Data.IsSuccess)
|
|
{
|
|
HandleApiError(response.Data);
|
|
}
|
|
return response.Data;
|
|
}
|
|
|
|
var fallbackMessage = GetFriendlyInfrastructureErrorMessage(response);
|
|
Snackbar.Add(fallbackMessage, Severity.Error);
|
|
|
|
return new ApiResponse<T>
|
|
{
|
|
IsSuccess = false,
|
|
StatusCode = (int)response.StatusCode,
|
|
Message = fallbackMessage
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var systemError = $"Client System Error: {ex.Message}";
|
|
Snackbar.Add(systemError, Severity.Error);
|
|
return new ApiResponse<T> { IsSuccess = false, Message = systemError };
|
|
}
|
|
}
|
|
|
|
private void HandleApiError<T>(ApiResponse<T> response)
|
|
{
|
|
var mainMessage = response.Message ?? "Operation failed";
|
|
if (response.Errors != null && response.Errors.Any())
|
|
{
|
|
var combinedErrors = string.Join(Environment.NewLine, response.Errors.Select(e => $"• {e}"));
|
|
Snackbar.Add(combinedErrors, Severity.Error, config =>
|
|
{
|
|
config.ShowCloseIcon = true;
|
|
config.VisibleStateDuration = 3000;
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add(mainMessage, Severity.Error);
|
|
}
|
|
}
|
|
|
|
private string GetFriendlyInfrastructureErrorMessage(RestResponse response)
|
|
{
|
|
return response.StatusCode switch
|
|
{
|
|
HttpStatusCode.ServiceUnavailable => "Server is currently under maintenance.",
|
|
HttpStatusCode.GatewayTimeout => "Server took too long to respond.",
|
|
HttpStatusCode.Unauthorized => "Session expired. Please login again.",
|
|
HttpStatusCode.Forbidden => "You do not have permission to access this resource.",
|
|
HttpStatusCode.InternalServerError => "A critical error occurred on the server.",
|
|
_ => "Unable to reach the server. Please check your connection."
|
|
};
|
|
}
|
|
} |