Docker Community Forums

Share and learn in the Docker community.

Containerized in Docker

I have very simple n-tier monolithic ASP.NET core project and try to setup in docker container but somehow it’s kept on failing and i have researched quite a bit unfortunately could not understand the docker file setup structure or process, it is quite interesting to see how project behave very strange.
Let me outline my project structure. A WebMVC project uses SQL Server as a database therefore localdb does not work in dockerize environment hence i had to pull sql sever container image from docker hub.

Dockerfile in MVC Project Root:-

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
COPY ["src/Web/WebUI/WebUI.csproj", "src/Web/WebUI/"]
COPY ["src/Core/Application/Application.csproj", "src/Core/Application/"]
COPY ["src/Infrastructure/Persistence/Persistence.csproj", "src/Infrastructure/Persistence/"]
RUN dotnet restore "src/Web/WebUI/WebUI.csproj"
COPY . .
WORKDIR "/src/src/Web/WebUI"
RUN dotnet build "WebUI.csproj" -c Release -o /app

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

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

docker-compose.yml file structure:

version: '3.4'

services:

  sqlserver.data:
    image: mcr.microsoft.com/mssql/server:2017-latest    

  webui:
    image: ${DOCKER_REGISTRY-}webui
    build: 
      context: .
      dockerfile: src/Web/WebUI/Dockerfile
    depends_on:
      - sqlserver.data

docker-compose-override.yml file structure:-

version: '3.4'

services:

  sqlserver.data:
   environment:
    - ACCEPT_EULA=Y
    - SA_PASSWORD=Pass@word

   ports:
     - "5433:1433"
  webui:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
      - Connection=Server=sqlserver.data;Database=eWebShopDatabase;User=sa;Password=Pass@word
     
    ports:
      - "5107:80"

appsetting.json file to serve database connection:-

{
 "Connection": "Server=sqlserver.data;Database=eWebShopDatabase;User=sa;Password=Pass@word;"
}

Sql Server database service registration:-

public static IServiceCollection AddSqlServerDatabase(this IServiceCollection services, IConfiguration configure)
        {
            services.AddEntityFrameworkSqlServer()
                   .AddDbContext<CatalogContext>(options =>
                   {
                       options.UseSqlServer(configure["Connection"],
                           sqlServerOptionsAction: resilient =>
                           {
                               //resilient.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
                               resilient.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
                           });

                   }, ServiceLifetime.Scoped);

            services.AddEntityFrameworkSqlServer()
                    .AddDbContext<AppIdentityDbContext>(options =>
                    {
                        options.UseSqlServer(configure["Connection"],
                        sqlServerOptionsAction: resilient =>
                        {
                            resilient.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
                        });
                    }, ServiceLifetime.Scoped);

            services.AddIdentity<ApplicationUser, IdentityRole>()
                    .AddEntityFrameworkStores<AppIdentityDbContext>()
                    .AddDefaultTokenProviders();

            return services;
        }

I have two dbcontext files and generated migrations accordingly, folder structures of these two migration files.BTW these two folders are located in Infrastructure layer of the project:-

Infrastructure
1. Auth
   1. Migrations
      1. Identitydbcontext

2. Migrations
   2. Catalogdbcontext

Program:-

public async static Task Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    await Policy.Handle<Exception>()
                          .WaitAndRetry(9, r => TimeSpan.FromSeconds(5), (ex, ts) =>
                          {
                              Log.Error("Error connecting to SQL Server. Retrying in 5 sec.");
                          }).Execute(async () =>
                          {
                              var logger = services.GetService<ILogger<CatalogContextSeed>>();
                              var catalogContext = services.GetRequiredService<CatalogContext>();
                              await CatalogContextSeed.SeedAsync(catalogContext, logger);

                              var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
                              var contextLogger = services.GetService<ILogger<AppIdentityDbContextSeed>>();
                              await AppIdentityDbContextSeed.SeedAsync(userManager, contextLogger);
                          });
                   
                }
                catch (Exception ex)
                {
                    var logger = services.GetService<ILogger<Program>>();
                    logger.LogError("Program could not seed the data and terminated unexpectedly", ex.Message);
                }
            }
            host.Run();
        }      

Problem descriptions:-

docker-compose build : succeeded.
docker-compose up: could not create webui container from the image, however sql-server container running but docker compose showing error that webui could not connect to the sql server database which it depends on, therefore it seems to fail to create a container.

Now interesting part is:- open a new command prompt and try to run “docker-compose up” again and this time it connects to the database and created a database and seed the initial data into the database, but…It fails to create an identitydbcontext table in the database. This works fine when I connect it to local SQL Server Database. Therefore I assume it is a problem with docker-compose file setup. I tried researched on it quite a bit but could not understand docker-compose setup.

Now my questions is:-

  1. Why mvc project is not been able to connect to the sql database at first place, since it depends on SQL, I understand it takes time to spin up the database therefore i have setup initialized database resilient policy?
  2. Why another migration file is not been read to generate/create table into the database? specifically this Infrastructure/Auth/Migrations/Identitydbcontext, by the way it does not matter where the file is located, since i have changed the directory and it’s seem problem.

I am confused, since there was no problem running locally, therefore i suspect or assume it is something to do with docker-compose file setup, but i have watched/researched on this from Docker documentation and Microsoft docs as well but could not find any answers on this issue.

I am hoping someone from the community would help me.