dockerasp.net-coresignalrblazor

how to run StartAsync connection of signalr blazor client in docker image?


I created default blazor server side app. Then added Microsoft.AspNetCore.SignalR.Client and ChatHub class. Then edited startup.cs file (add services.AddSignalR() and endpoints.MapHub<ChatHub>("/chatHub")) and index.razor page. Then run by IIS express. it is okey.

Then added docker support and run Docker host. it is not working. Because only don't work hub connection StartAsync method. How to run it? Help me? Thank you very much guys.

Error is:

An unhandled exception occurred while processing the request. SocketException: Cannot assign requested address System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)

HttpRequestException: Cannot assign requested address System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)

index.razor code:

@code {
    private HubConnection _hubConnection;

    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri("/chatHub"))
            .Build();

        _hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            var encodedMsg = $"{user}: {message}";
            StateHasChanged();
        });

        await _hubConnection.StartAsync(); // **DON'T WORK IN DOCKER HOST.**
    }
}

Docker file:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BlazorApp1/BlazorApp1.csproj", "BlazorApp1/"]
RUN dotnet restore "BlazorApp1/BlazorApp1.csproj"
COPY . .
WORKDIR "/src/BlazorApp1"
RUN dotnet build "BlazorApp1.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "BlazorApp1.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BlazorApp1.dll"]

Solution

  • My best guess is your hub client is trying to connect to "the-public-url-out-of-docker/chatHub":

        _hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri("/chatHub"))
            .Build();
    

    NavigationManager.ToAbsoluteUri(...) will convert /chatHub to a public url which are exposed to the end user. For example, if you're using reverse proxy, it might be the domain name.

    Note there're url at three different levels:

      +----------------------------------+
      | HOST  (5000)                     |
      |   +                              |
      |   |Port Mapping---------------+  |
      |   >-->-->|Container (80)      |  |
      |          |                    |  |
      |          +--------------------+  |
      +-----^----------------------------+
            |  reverse proxy
    +-------+----------------------------+
    | nginx                              |
    |  https://www.myexample.com/chatHub
    |                                    |
    +-------^----------------------------+
            |
            |
            |
            |
    +-------+-----------+
    |                   |
    |   Browser         | (Brazor sees only the public url via NavgiationManager  )
    |                   |
    +-------------------+
    

    However, when running in docker, the host's network is not accessible from the container's network all the time.

    If that's case, there're several approaches that should work:

    1. Avoid using the public url like .WithUrl(NavigationManager.ToAbsoluteUri("/chatHub")). Hard-code it to the container ip&port. For example, if you container listens on 80, it should be http://localhost/chatHub.
    2. Configure a network for docker, or add a --network for when running docker. For more details, see this thread