Reputation: 45
I am migrating a large monolithic application, developed in ASP.NET MVC with .NET 4.8, to a micro services architecture and a SPA to the frontend.
As the application is very large, initially we will only migrate only the part corresponding to the backend to micro services, leaving the views for a second phase.
To manage HTTP requests, the dependency injection process was implemented to be able to use the HTTP Client Factory to manage the creation and disposal of clients.
Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
//services.AddHttpClient<IBaseServiceConfig, BaseServiceConfig>();
//services.AddHttpClient<IAuthClientService, AuthClientService>();
//services.AddHttpClient<IPontoEAusenciasClientService, PontoEAusenciasClientService>();
services.AddScoped<IBaseServiceConfig, BaseServiceConfig>();
services.AddScoped<IAuthClientService, AuthClientService>();
services.AddScoped<IPontoEAusenciasClientService, PontoEAusenciasClientService>();
services.AddControllersAsServices(typeof(Startup).Assembly
.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t) || t.Name.EndsWith("Controller", System.StringComparison.OrdinalIgnoreCase))
);
}
public void Configuration(IAppBuilder app)
{
// https://scottdorman.blog/2016/03/17/integrating-asp-net-core-dependency-injection-in-mvc-4/
var services = new ServiceCollection();
ConfigureServices(services);
var resolver = new Helpers.DependencyInjection.DefaultDependencyResolver(services.BuildServiceProvider());
DependencyResolver.SetResolver(resolver);
}
My baseService.cs
:
public class BaseServiceConfig : IBaseServiceConfig
{
private readonly IHttpClientFactory _httpClientFactory;
public BaseServiceConfig(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<ResponseModel> SendAsync(RequestModel requestDto)
{
try
{
HttpClient client = _httpClientFactory.CreateClient();
HttpRequestMessage message = new HttpRequestMessage();
if (requestDto.ContentType == HttpRequestContentTypeEnum.FormData)
{
message.Headers.Add("Accept", "*/*");
}
else if(requestDto.ContentType == HttpRequestContentTypeEnum.Json)
{
message.Headers.Add("Accept", "application/json");
}
if (requestDto.Authorization)
{
var token = _tokenProvider.GetToken();
if (token != null)
message.Headers.Add("Authorization", $"Bearer {token}");
}
message.RequestUri = new Uri(requestDto.Url);
if (requestDto.RequestType == HttpRequestTypeEnum.GET && requestDto.QueryParams != null && requestDto.QueryParams.Any())
{
var queryString = string.Join("&", requestDto.QueryParams.Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
message.RequestUri = new Uri($"{requestDto.Url}?{queryString}");
}
else if (requestDto.Body != null)
{
//message.Content = new StringContent(JsonConvert.SerializeObject(requestDto.Body), Encoding.UTF8, "application/json");
message.Content = new StringContent(requestDto.Body.ToString().Serialize2Json(), Encoding.UTF8, "application/json");
}
switch (requestDto.RequestType)
{
case HttpRequestTypeEnum.GET:
message.Method = HttpMethod.Get;
break;
case HttpRequestTypeEnum.POST:
message.Method = HttpMethod.Post;
break;
case HttpRequestTypeEnum.PUT:
message.Method = HttpMethod.Put;
break;
case HttpRequestTypeEnum.DELETE:
message.Method = HttpMethod.Delete;
break;
}
HttpResponseMessage apiResponse = null;
//apiResponse = client.SendAsync(message).GetAwaiter().GetResult();
apiResponse = await client.SendAsync(message);
switch (apiResponse.StatusCode)
{
case System.Net.HttpStatusCode.NotFound:
return new ResponseModel() { IsSuccess = false, Message = "Not Found" };
case System.Net.HttpStatusCode.Forbidden:
return new ResponseModel() { IsSuccess = false, Message = "Access Denied" };
case System.Net.HttpStatusCode.Unauthorized:
return new ResponseModel() { IsSuccess = false, Message = "Unauthorized" };
case System.Net.HttpStatusCode.InternalServerError:
return new ResponseModel() { IsSuccess = false, Message = "Internal Server Error" };
default: //Status Code OK
var apiContent = await apiResponse.Content.ReadAsStringAsync();
// var result = responseResult.Content.ReadAsStringAsync().Result;
//var apiResponseDto = JsonConvert.DeserializeObject<ResponseModel>(apiContent);
var apiResponseDto = apiContent.DeserializeFromJson<ResponseModel>();
return apiResponseDto;
}
}
catch (Exception ex)
{
var dto = new ResponseModel
{
IsSuccess = false,
Message = ex.Message,
};
return dto;
}
}
}
My Controller.cs
(simplified):
public class ControloAssiduidadeController : BaseController
{
private readonly IPontoEAusenciasClientService _pontoEAusenciasService;
public ControloAssiduidadeController(IPontoEAusenciasClientService pontoEAusenciasService)
{
_pontoEAusenciasService = pontoEAusenciasService;
}
public async Task<ActionResult> GetCbTipoAusenciaById(List<Guid> idList)
{
var ausenciasTipo = new List<AusenciasTipoClientDto>();
foreach(var id in idList)
{
var response = _pontoEAusenciasService.GetCbTipoAusenciaByIdAsync(id, (long)Gec.GrupoId, (long)Gec.EmpresaId, (long)Gec.CentroId).GetAwaiter().GetResult();
if (response != null && response.IsSuccess)
{
ausenciasTipo.Add(response.Result.DeserializeFromJson<AusenciasTipoClientDto>());
}
}
// ....
}
}
Everything was going well, when there was a single request to the micro services, however we ran into a problem, in a situation of a loop to a small list, but for each element there is a need to make a request to the micro service. What actually happens is that the first request reaches the micro service, it responds correctly, but the response does not reach the frontend client.
If you make the request synchronously, all requests are sent and responded without problems, however when the request is asynchronous the response never arrives.
This works:
apiResponse = client.SendAsync(message).GetAwaiter().GetResult();
This also works:
apiResponse = client.SendAsync(message).Result();
This does NOT work:
apiResponse = await client.SendAsync(message);
Can anyone help figure out what's going on? I didn't want to leave requests to the micro service synchronously.
If you need more details, please let me know.
Thanks
Upvotes: 0
Views: 255