I just upgraded my Web API application to .NET core 3.0, all works fine when running in debug mode in IIS Express, but context does not respond when running in docker container either on server or in VS debug. No error thrown, just never responds.
I tried deploying an updated image to server which is where I first noticed the issue. I then tried running as docker in vs to debug.
I have updated all NuGet packages and set frameworks to .NET Core 3.0 or .NET Standard 2.1.
I have inspected the context connection string in debug and it appears to be correct. I rolled back to an earlier image using .NET core 2.2 and all worked as expected using the same startup parameters.
I created a test method that does not use context and it returns correct values on server and in VS docker debug.
I tried changing the method to use synchronous call to context, but no change in behavior.
The test database is very small, only 3 records in the table being queried.
public async Task<List<SendingSystemInfoResponse>> getSendingSystemInfoList()
{
try
{
return await _context.EmailSendingSystem.Where(m => !m.Deleted && m.Active == true).Select(m => new SendingSystemInfoResponse
{
SystemId = m.EmailSendingSystemId,
SystemName = m.Title,
SystemDescription = m.Description
}).ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, string.Format("EmailDataAccess: Exception retrieving EmailSendingSystem List"));
throw;
}
}
If there were an error connecting to the SQL Server, or if the SQL request timed out, I would expect to hit the catch block code, but this never happens.
Here is the content of the docker file, I'm not sure if my targets for base and build images are correct. They seem to work, but might be the cause of my issue.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["EmailAutomation.API/EmailAutomation.API.csproj", "EmailAutomation.API/"]
COPY ["EmailAutomation.API/NuGet.Config", "/src"]
RUN dotnet restore "EmailAutomation.API/EmailAutomation.API.csproj"
COPY . .
WORKDIR "/src/EmailAutomation.API"
RUN dotnet build "EmailAutomation.API.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "EmailAutomation.API.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "EmailAutomation.API.dll"]
------Update-----
So, I've been working on this off and on today, and have a little more info that might help someone point me in the right direction.
I created a simple test Web API project with an EF connection to SQL Server running on my local PC using .NET core 3.0 and the latest NuGet packages, and enabled TCP/IP connections to SQL Server running locally. I was able to get it to connect to the database and return values.
Next, I created a copy of the test database on my local SQL Server. This also worked, the Web API in the original question running in Docker connected and returned data.
I then changed the connection string to point back to the test SQL Server and the process hangs in the same spot with no error.
Next, I tested it with the connection still pointed to the test SQL Server but running in IIS Express rather than Docker. Again, everything worked as expected.
I then tried running the previous release docker image which uses .NET Core 2.2, and it also returned data from the test SQL Server.
What could be the reason that I can not connect via IP to the test SQL Server using .NET Core 3.0 in Docker when all other combinations work just fine.
------Update 2-----
I created the necessary database for my new simple test Web API project on the Test SQL Server, and changed the simple Web API project connection string. This new, clean, simple, .NET Core 3 project also did not connect to the Test SQL Server when running as Docker, but worked fine when running on IIS Express. It also worked fine when running in Docker but connecting to my local DB by IP.
Something has changed with .NET Core 3 in Docker that is stopping it from connecting to the external database server. Anybody have any ideas on what I need to do to resolve this?
--UPDATE 3 -----
Thanks to MATT! After reading Matt's response, I wasn't able to get the RUN commands to work within the docker file, but changing my base image to bionic did work. I have also been working with Microsoft support who also pointed me to the link that Matt provided.
Maybe I just didn't place the RUN commands in the right location, so if anyone can provide a sample docker file using the RUN commands to resolve this issue, I would be grateful.
Here is an updated docker file from a simple test project:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-bionic AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
---Final Update -----
I tried the RUN commands in the docker file again, but got it right this time. Here is that version of the docker file.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app
RUN sed -i 's/DEFAULT#SECLEVEL=2/DEFAULT#SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT#SECLEVEL=2/DEFAULT#SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
I believe the issue you're running into is documented here: https://github.com/dotnet/SqlClient/issues/222. As you said, something did change with .NET Core 3 because those Docker images are based on Debian Buster by default. Buster is configured to use 1.2 as the minimum TLS protocol, a change from the previous version (see https://www.debian.org/releases/stable/amd64/release-notes/ch-information.en.html#openssl-defaults).
This can be temporarily fixed by adding the following to the Dockerfile:
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
This is not a great solution because it is essentially downgrading the version of TLS. The better long-term solution is to enable TLS 1.2 on the SQL Server (see https://support.microsoft.com/en-us/help/3135244/tls-1-2-support-for-microsoft-sql-server).
Related
I am trying to dockerize my .Net API and I cannot seem to get access to it after I create a container with it. I attempt to send a request using postman but I get a "Socket Hang Up" error. I believe this has to do with the ports I am using although I am not sure how to fix it. Below is all the information I could gather.
Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
COPY WebAPI.csproj .
RUN dotnet restore "WebAPI.csproj"
COPY . ./
RUN dotnet publish "WebAPI.csproj" -c Release -o /publish
RUN dotnet build
FROM build AS final
WORKDIR /app
COPY --from=build /publish .
EXPOSE 5000
ENTRYPOINT ["dotnet", "WebAPI.dll"]
Commands:
docker build -t webapi:latest .
docker run -p 5000:5000 webapi:latest
Postman Proxy:
127.0.0.1:5000
P.S I have tried changing the ports in multiple ways, changing proxy settings for postman and nothing seems to work
Microsoft has set the environment variable ASPNETCORE_URLS to http://+:80/ in the aspnet image, which makes your application listen on port 80.
So your run command should map port 80 like this
docker run -p 5000:80 webapi:latest
Then your API will be available on http://localhost:5000/
Note that Swagger is only available when your application runs in Development mode and the Docker environment is not considered development. So by default, Swagger won't be available.
Update: Since I don't have your program source code, I've created the following Dockerfile that runs dotnet new to create a fresh template webapi project.
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
RUN dotnet new webapi -n WebAPI -o .
RUN dotnet publish -c Release -o /publish
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /publish .
CMD ["dotnet", "WebAPI.dll"]
I then run the following commands to build, run and test the container
docker build -t test .
docker run --rm -d -p 5000:80 test
curl http://localhost:5000/WeatherForecast
and I get the expected result from the API.
I got stuck on this for quite some time and i don't know why it doesn't work.
I looked into posts similair to mine but i can't fix it, (tried checking the firewall settings, using different ports).
I have a Dockerfile that looks like this:
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY bin/Release/net6.0/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "MonitorApplication1.dll"]
The application is a simple REST API with C# .NET Core 6. The database is a MS SQL Server Database.
The image and container seem fine but when i try to view it in the browser (using Chrome as standard, but also tried Edge) i get the ERR_EMPTY_RESPONSE error.
The log of the container (using Docker Desktop) only shows this:
{"EventId":14,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Now listening on: http://[::]:80","State":{"Message":"Now listening on: http://[::]:80","address":"http://[::]:80","{OriginalFormat}":"Now listening on: {address}"}}
Update
I tried to create a new .NET 6 API with Docker Enabled but when i tried to run the container i still get the Error Empty Response.
I solved a similar problem by adding the ASPNETCORE_URLS environment variable, like this:
ENV ASPNETCORE_URLS=http://*:5000
I am working on an ASP.NET Core API project with docker support.
I was hoping I could add postgresql or mysql to my dockerfile and have it just work. Now, I don't have much experience with docker at all however I am happy with what it does and how it works (especially that my pc doesn't get cluttered with random programs that I don't need except for one project).
I have tried the example from https://docs.docker.com/engine/examples/postgresql_service/
However it doesn't really look like it should work to me and I like to know how my stuff works. So even if it works properly I'd rather have a solution where it looks more like this:
FROM postgresql:11.5
EXPOSE 5432
ENV <add password environment variable here>
The dockerfile I have before adding postgresql is
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["ModOs__Api/ModOs__Api.csproj", "ModOs__Api/"]
RUN dotnet restore "ModOs__Api/ModOs__Api.csproj"
COPY . .
WORKDIR "/src/ModOs__Api"
RUN dotnet build "ModOs__Api.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "ModOs__Api.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ModOs__Api.dll"]
When the postgres is added I'd like to simply be able to connect to it at the URL localhost:5432 in the c# code. Also, if possible it would be awesome if I can view the databases in my browser (However, if this makes things 10x more complicated please don't waste time on it).
What is the best or a great way of doing this?
Thanks in advance!
You don't. Although possible, I would advice against doing it like this. The philosophy with Docker is that each service runs in it's own container. If you follow this paradigm, things will be much easier for you. On the upside, there is a beaten path for this making this comfortable. Check out this simple docker compose file for example
version: '3'
services:
web:
build: .
ports:
- "80:80"
postgres:
image: "postgres:9.6"
Instead of connecting to localhost:5432 you connect to postgres:5432.
Spin everything up with docker-compose up
Created a simple application that connects to PostgreSQL but when I containerized it using Docker i cant seem to start it and no port/s were shown when i ran the container. What seems to be the problem?
The application works without the Docker but when I containerize it, that's where the problem arises.
docker build is successful and when I use docker run
it gives me a container but when I check it using docker ps -a no ports where shown
This is what I did on docker terminal
and this is my code when connecting to PostgreSQL db
class Program
{
static void Main(string[] args)
{
using (var connection = new NpgsqlConnection("Host=localhost;Username=postgres;Password=password;Database=user"))
{
connection.Open();
connection.Execute("Insert into customer (name) values ('Mikolasola');");
var value = connection.Query<string>("Select name from customer;");
Console.WriteLine(value.First());
}
Console.Read();
}
}
here's my docker file
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "webapplication1.dll"]
Edit: Changed my Docker file to this and somehow I can get the port now
FROM microsoft/dotnet:2-sdk AS build-env
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -r linux-x64 -o out
FROM microsoft/dotnet:2-runtime-deps
WORKDIR /app
COPY --from=build-env /app/out ./
ENTRYPOINT ["./webapplication1"]
But I can't run it. Here's the screenshot
Any help would be much appreciated. Thanks!
PS: im a newbie
If you're using Docker for Mac (or Docker for Windows), to access anything on the host, you need to use host.docker.internal. More on that here.
Read the connection string from config and environment variables. That will allow you to override it when running the container.
PS: im a newbie
Pro tip for you :p
You might not want to use -d on the container you're working, so you see it's logs right there. Had you not used it, you'd have seen the process exit and not wondered why there's no port shown there :)
UPDATE:
Use the Dockerfile from the original question (before the edit).
I suggested you run it without -d:
docker run -p 8080:80 --name test webapp1
This will show you the aspnet app crash. You'll see what's happening. In this case since I know what's happening I can help, but in general you want to know what's happening. You do that by not running it in a detached state for small things like this, and using docker logs when there's a lot to parse. Anyway...
... you want the container to access the database on the host, not on its localhost. You do that by using host.docker.internal as the host. Eg:
Host=host.docker.internal;Username=postgres;Password=password;Database=user
This only works if you're using Docker for Windows or Docker for Mac. Doesn't work on Docker Toolbox or on linux AFAIK.
Now you need to figure out a way your application to use host.docker.internal when running within docker and localhost otherwise. My suggestion was to read it from config.
I've a .net / c# aspnet core application which connects to a MongoDb Atlas Cloud database.
When running localy every thing works fine.
Now i put the application inside a alpine docker image the application the connection fails.
I got some various exceptions pointing out that the authentication doesn't work.
Here my DockerFile which builds and runs the application
FROM microsoft/dotnet:2.1-sdk-alpine AS builder
WORKDIR /
COPY . .
RUN dotnet publish Api/Api.csproj -o /dockerout/ -c Release
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime-alpine
WORKDIR /app
EXPOSE 80 5000
RUN apk update
COPY --from=builder /dockerout .
ENTRYPOINT ["dotnet", "Api.dll"]
After a lot of research I found an Issue pointing me to the root cause:
https://github.com/dotnet/corefx/issues/9608#issuecomment-401370142
Because it took me a lot of time I'll answer my own question hoping someone is saving the time.
There two possible solutions are
a) don't use a alpine image
b) update the openssl package when building the image by adding open ssl like this apk add --no-cache openssl
Full DockerFile that solved it for me:
FROM microsoft/dotnet:2.1-sdk-alpine AS builder
WORKDIR /
COPY . .
RUN dotnet publish Api/Api.csproj -o /dockerout/ -c Release
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime-alpine
WORKDIR /app
EXPOSE 80 5000
RUN apk update && apk add --no-cache openssl
COPY --from=builder /dockerout .
ENTRYPOINT ["dotnet", "Api.dll"]