Search code examples
asp.net-coredocker-compose.net-8.0

Docker: Communication between two .NET APIs


I'm trying to communicate between two .BET APIs inside the docker container. I'm uploading both APIs plus the database through docker-compose, I can access both APIs individually but when I try to send data from one to the other through the route from "API A" to "API B" I get the error below.

2024-11-10 09:19:45 info: Microsoft.EntityFrameworkCore.Migrations[20405]
2024-11-10 09:19:45       No migrations were applied. The database is already up to date.
2024-11-10 09:19:45 info: Microsoft.Hosting.Lifetime[14]
2024-11-10 09:19:45       Now listening on: http://[::]:4000
2024-11-10 09:19:45 info: Microsoft.Hosting.Lifetime[14]
2024-11-10 09:19:45       Now listening on: https://[::]:4001
2024-11-10 09:19:45 info: Microsoft.Hosting.Lifetime[0]
2024-11-10 09:19:45       Application started. Press Ctrl+C to shut down.
2024-11-10 09:19:45 info: Microsoft.Hosting.Lifetime[0]
2024-11-10 09:19:45       Hosting environment: Development
2024-11-10 09:19:45 info: Microsoft.Hosting.Lifetime[0]
2024-11-10 09:19:45       Content root path: /app
2024-11-10 09:20:06 info: System.Net.Http.HttpClient.IItemRepository.LogicalHandler[100]
2024-11-10 09:20:06       Start processing HTTP request POST https://itemservice_api/api/Item
2024-11-10 09:20:06 info: System.Net.Http.HttpClient.IItemRepository.ClientHandler[100]
2024-11-10 09:20:06       Sending HTTP request POST https://itemservice_api/api/Item
2024-11-10 09:20:06 fail: Restaurante_Api.Middlewares.ErrorHandlingMiddleware[0]
2024-11-10 09:20:06       Internal Server Error ErrorMessage { Code = 01.00, Message = Erro interno do servidor. }
2024-11-10 09:20:06       System.Net.Http.HttpRequestException: Connection refused (itemservice_api:443)
2024-11-10 09:20:06        ---> System.Net.Sockets.SocketException (111): Connection refused
2024-11-10 09:20:06          at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
2024-11-10 09:20:06          at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          --- End of inner exception stack trace ---
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
2024-11-10 09:20:06          at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-11-10 09:20:06          at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.<SendCoreAsync>g__Core|5_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
2024-11-10 09:20:06          at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.<SendCoreAsync>g__Core|5_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
2024-11-10 09:20:06          at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
2024-11-10 09:20:06          at Restaurante_Repositories.Repositories.ItemRepository.Create(CreateItemRequest item) in /src/Restaurante_Repositories/Repositories/ItemRepository.cs:line 25
2024-11-10 09:20:06          at Restaurante_UseCases.UseCases.CreateItemUseCase.Execute(CreateItemRequest request) in /src/Restaurante_UseCases/UseCases/CreateItemUseCase.cs:line 20
2024-11-10 09:20:06          at Restaurante_Api.Controllers.ItemController.Create(CreateItemRequest request) in /src/Restaurante_Api/Controllers/ItemController.cs:line 21
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
2024-11-10 09:20:06          at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
2024-11-10 09:20:06          at Restaurante_Api.Middlewares.ErrorHandlingMiddleware.Invoke(HttpContext context, ILogger`1 logger) in /src/Restaurante_Api/Middlewares/ErrorHandlingMiddleware.cs:line 16

I built docker-compose as follows

services:
  restaurante_api:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=4000
      - ASPNETCORE_HTTPS_PORTS=4001
    container_name: restaurante_api
    hostname: restaurante_api
    image: ${DOCKER_REGISTRY-}restauranteapi
    build:
      context: .
      dockerfile: Restaurante_Api/Dockerfile
    ports:
      - "4000:4000"
      - "4001:4001"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
    networks:
      restaurante-bridge:
    depends_on:
      itemservice_api:
        condition: service_started
      sqlserver:
        condition: service_healthy

  sqlserver:
    image: mcr.microsoft.com/mssql/server:2022-preview-ubuntu-22.04
    container_name: sqlserver   
    hostname: sqlserver
    ports:
      - "1433:1433"
    environment:
      - SA_PASSWORD=leoQueres123
      - ACCEPT_EULA= Y       
    volumes:
      - ${APPDATA}/sqlserverrestaurante/data:/var/opt/mssql/data
      - ${APPDATA}/sqlserverrestaurante/log:/var/opt/mssql/log   
    networks:
      - restaurante-bridge
    healthcheck:
      test: /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "leoQueres123" -Q "SELECT 1" -b -o /dev/null
      interval: 10s
      timeout: 3s
      retries: 10
      start_period: 10s 
  
  itemservice_api: 
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=5000
      - ASPNETCORE_HTTPS_PORTS=5001
    container_name: itemservice_api
    hostname: itemservice_api
    image: ${DOCKER_REGISTRY-}itemserviceapi
    build:
      context: .
      dockerfile: ItemService_Api/Dockerfile
    ports:
      - "5000:5000"
      - "5001:5001"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
    networks:
      restaurante-bridge:
    depends_on:
      sqlserver:
        condition: service_healthy


networks:
  restaurante-bridge:    
    driver: bridge
    external: true

networks: restaurante-bridge: driver: bridge`

Dockerfile of each application

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 5000
EXPOSE 5001

# Esta fase é usada para compilar o projeto de serviço
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ItemService_Api/ItemService_Api.csproj", "ItemService_Api/"]
COPY ["ItemService_Borders/ItemService_Borders.csproj", "ItemService_Borders/"]
COPY ["ItemService_Repositories/ItemService_Repositories.csproj", "ItemService_Repositories/"]
COPY ["ItemService_UseCases/ItemService_UseCases.csproj", "ItemService_UseCases/"]
RUN dotnet restore "./ItemService_Api/ItemService_Api.csproj"
COPY . .
WORKDIR "/src/ItemService_Api"
RUN dotnet tool install --global dotnet-ef 
ENV PATH="$PATH:/root/.dotnet/tools"
RUN dotnet build "./ItemService_Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

# Esta fase é usada para publicar o projeto de serviço a ser copiado para a fase final
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./ItemService_Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Esta fase é usada na produção ou quando executada no VS no modo normal (padrão quando não está usando a configuração de Depuração)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT dotnet ef database update --environment Development --project src/ItemService_Repositories
ENTRYPOINT ["dotnet", "ItemService_Api.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 4000
EXPOSE 4001

# Esta fase é usada para compilar o projeto de serviço
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Restaurante_Api/Restaurante_Api.csproj", "Restaurante_Api/"]
COPY ["Restaurante_Borders/Restaurante_Borders.csproj", "Restaurante_Borders/"]
COPY ["Restaurante_Repositories/Restaurante_Repositories.csproj", "Restaurante_Repositories/"]
COPY ["Restaurante_UseCases/Restaurante_UseCases.csproj", "Restaurante_UseCases/"]
RUN dotnet restore "./Restaurante_Api/Restaurante_Api.csproj"
COPY . .
WORKDIR "/src/Restaurante_Api"
RUN dotnet tool install --global dotnet-ef 
ENV PATH="$PATH:/root/.dotnet/tools"
RUN dotnet build "./Restaurante_Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

# Esta fase é usada para publicar o projeto de serviço a ser copiado para a fase final
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Restaurante_Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Esta fase é usada na produção ou quando executada no VS no modo normal (padrão quando não está usando a configuração de Depuração)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT dotnet ef database update --environment Development --project src/Restaurante_Repositories
ENTRYPOINT ["dotnet", "Restaurante_Api.dll"]

Can someone help me understand this problem? I've done everything I could and I can't solve it.


Solution

  • After checking stacktrace below, then I tried to check the source code, and I noticed that you hardcoded the BaseUrl.

    2024-11-10 09:20:06          at Restaurante_Repositories.Repositories.ItemRepository.Create(CreateItemRequest item) in /src/Restaurante_Repositories/Repositories/ItemRepository.cs:line 25
    2024-11-10 09:20:06          at Restaurante_UseCases.UseCases.CreateItemUseCase.Execute(CreateItemRequest request) in /src/Restaurante_UseCases/UseCases/CreateItemUseCase.cs:line 20
    2024-11-10 09:20:06          at Restaurante_Api.Controllers.ItemController.Create(CreateItemRequest request) in /src/Restaurante_Api/Controllers/ItemController.cs:line 21
    

    enter image description here

    You should use https://itemservice_api:5001 like below.

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
    
      "ConnectionStrings": {
        "DefaultConnection": "Server=sqlserver,1433;Database=Restaurantes;User Id=SA;Password=leoQueres123;TrustServerCertificate=True"
      },
      "ItemService": {
        "BaseUrl": "https://itemservice_api:5001/api/Item"
      }
    }
    //host.docker.internal