ASP .NET Core gives System.Net.Sockets.SocketException error on Heroku ASP .NET Core gives System.Net.Sockets.SocketException error on Heroku heroku heroku

ASP .NET Core gives System.Net.Sockets.SocketException error on Heroku


I've just solved this problem thanks to Chis' answer and this blogpost.

It turns out that Heroku really wants to take care of the ports for you (probably for security reasons).

With boilerplate asp core template, with docker suport added you start with:

Program.cs:

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;namespace TestWebApp{    public class Program    {        public static void Main(string[] args)        {            CreateHostBuilder(args).Build().Run();        }        public static IHostBuilder CreateHostBuilder(string[] args) =>            Host.CreateDefaultBuilder(args)                .ConfigureWebHostDefaults(webBuilder =>                {                    webBuilder.UseStartup<Startup>();                });    }}

Dockerfile:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS baseWORKDIR /appEXPOSE 80EXPOSE 443FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS buildWORKDIR /srcCOPY ["TestWebApp/TestWebApp.csproj", "TestWebApp/"]RUN dotnet restore "TestWebApp/TestWebApp.csproj"COPY . .WORKDIR "/src/TestWebApp"RUN dotnet build "TestWebApp.csproj" -c Release -o /app/buildFROM build AS publishRUN dotnet publish "TestWebApp.csproj" -c Release -o /app/publishFROM base AS finalWORKDIR /appCOPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "TestWebApp.dll"]

Heroku expects your app to run on the port Heroku gives you in PORT environment variable. It'll expose 80 (HTTP) and 443 (HTTPS) ports for you. So what you have to do is:

Remove these lines form your Dockerfile:

EXPOSE 80EXPOSE 443

Then you have to make your application listen on that port. To make it work, you have to change your Program.cs file:

        public static IHostBuilder CreateHostBuilder(string[] args) =>            Host.CreateDefaultBuilder(args)                .ConfigureWebHostDefaults(webBuilder =>                {                    var port = Environment.GetEnvironmentVariable("PORT");                    webBuilder.UseStartup<Startup>()                    .UseUrls("http://*:" + port);                });

Then Heroku does it's magic and your app still gets HTTPS support.

Hint:

The default Dockerfile won't work out of the box with Heroku CLI. The generated Dockerfile is supposed to be ran from the solution level (not project level). I was unable to force heroku CLI to use a Dockerfile form a nested direcotry. The way I made id work was:

  1. Go to your solution directory
  2. Create Dockerfile
  3. Paste modified content:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS baseWORKDIR /appFROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS buildWORKDIR /srcCOPY ["TestWebApp/TestWebApp.csproj", "TestWebApp/"]RUN dotnet restore "TestWebApp/TestWebApp.csproj"COPY ./TestWebApp ./TestWebAppWORKDIR "/src/TestWebApp"RUN dotnet build "TestWebApp.csproj" -c Release -o /app/buildFROM build AS publishRUN dotnet publish "TestWebApp.csproj" -c Release -o /app/publishFROM base AS finalWORKDIR /appCOPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "TestWebApp.dll"]
  1. heroku login
  2. heroku container:login
  3. heroku container:push web --app your-app & heroku container:release web --app your-app


This probably isn't really about your ENTRYPOINT, but rather the ASPNETCORE_URLS environment variable that you use with CMD:

CMD ASPNETCORE_URLS=http://*:$PORT dotnet dotnetcoreapi.dll

Here you run your application setting ASPNETCORE_URLS to a single URL using the PORT given to you by Heroku.

In the second Dockerfile, you don't provide that environment variable and you get a socket error. It's very likely that your application is trying to listen for both HTTP and HTTPS (or maybe just HTTPS) connections.

Heroku provides a single port for you to use, and your application should listen for HTTP (not HTTPS) connections on that Port. Heroku will take care of the HTTPS part.

Try this:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS runtimeWORKDIR /appCOPY /out ./ENV ASPNETCORE_URLS http://*:$PORTENTRYPOINT ["dotnet","dotnetcoreapi.dll"]