Создаем свое первое ASP.NET Core приложение с использованием Docker
                        
                    Docker уже де-факто стал стандартом для приложений, пора разобрать то, как использовать свои ASP.NET Core приложения в докере.

Создаем проект с помощью CLI
Для начала создадим solution. Для этого как матерые ребята воспользуемся .net CLI.
Открываем папку, где хотим создать решение и выполняем следующую команду в cmd:
dotnet new sln

После создадим пустой веб проект с помощью команды:
dotnet new web -n WebApi

Теперь добавим новый проект, который мы создали в наш sln
dotnet sln IpLookup.sln add WebApi/WebApi.csproj

Конфигурация приложения
Когда все готово, откроем наш проект с помощью VS Code. Создадим наш первый контроллер, для этого добавим папку:

И добавим апи контроллер:
namespace WebApi.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class IpController : ControllerBase
    {
        [HttpGet("{ip}")]
        public ActionResult Get(string ip)
        {
            return NoContent();
        }
    }
}
Давайте теперь запустим код, с помощью .net cli. для этого нужно выполнить следующий код:
dotnet run --project webapi/WebApi.csproj

Как видим, с записей в консоли, проект успешно запущен на 5000 порту, давайте откроем его в браузере:

Браузер нам вывел Hello World! на экран
Почему?
Если мы посмотрим в стандартный Startup класс, который сгенерировал CLI
public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
То увидим, что у нас есть стандартная обработка / роута.
Окей, теперь нам нужно оживить наш проект, давайте добавим использование AddMvcCore сервиса.
Остановим наш аппликейшин, для этого достаточно нажать ctrl + c в терминале VS Code

Подключим нужные nuget пакеты, а именно Microsoft.AspNetCore.All, Microsoft.AspNetCore.Mvc.NewtonsoftJson
И добавим фильтр для автоматической проверки ModelState и возврата BadRequest, в случае если ModelState.IsValid = false.
public class ModelStateValidationActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
            var modelState = context.ModelState;
            if (!modelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(modelState);
            }
        }
    }
Модифицируем Program класс
 public class Program
    {
        public static void Main(string[] args)
        {
            WebHost.CreateDefaultBuilder(args)
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>().Build().Run();
        }
    }
И Startup.cs, который будет выглядеть следующим образом:
public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddResponseCompression();
            services.Configure<GzipCompressionProviderOptions>(options =>
            {
                options.Level = CompressionLevel.Fastest;
            });
            services.AddMvcCore(options =>
            {
                options.Filters.Add(new ApiControllerAttribute());
                options.Filters.Add(new ModelStateValidationActionFilterAttribute());
                options.EnableEndpointRouting = false;
            })
                .AddFormatterMappings()
                .AddCors(options =>
                {
                    options.AddPolicy("AllowAll",
                        builder =>
                        {
                            builder
                                .AllowAnyMethod()
                                .AllowAnyHeader()
                                .AllowCredentials();
                        });
                }).AddApiExplorer()
                .AddNewtonsoftJson()
                .AddDataAnnotations()
                .AddAuthorization().SetCompatibilityVersion(CompatibilityVersion.Latest);
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", true, true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true);
            var configuration = builder.Build();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseResponseCompression();
            app.UseDefaultFiles();
            app.UseStaticFiles();
            app.UseCors("AllowAll");
            app.UseAuthentication();
            app.UseMvc();
        }
    }
}
Запускаем проект и тестируем наш API. Для этого откроем postman и сделаем запрос на наш Endpoint:

Отлично. как видите. мы получили ответ с нужным статус кодом.
Docker

Теперь давайте "обернем" наш проект в докер контейнер.
Для этого создадим DockerFile с следующим содержимым:
FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# copy everything else and build app
COPY /. ./
WORKDIR /app/
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0 AS runtime
WORKDIR /app
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "WebApi.dll"]
Так как мы будем запускать контейнеры в Linux, убедитесь, что вы перевели ваш docker в линукc режим
Теперь сбилдим наше локальное приложение с помощью команды
docker build -t iplookup .
(или docker build -t iplookup ./webapi если вы находитесь в корневой папке)
Обратите внимание, точка указывает на то, что Dockerfile находиться в той же директории, где вы запускаете команду. Когда я первый раз работал с докером, не мог понять, что же не так с командой, оказалось что я просто удалял эту точку, когда копировал команду, думая что она не нужна.
Теперь запустим наше приложение и выполним команду для просмотра активных контейнеров
docker run -d -p 8080:80 --name IpLookup iplookup
docker ps
После выполнения команд, должна появиться следующая информация в консоли:

И если мы откроем Docker плагин в VS code, то увидим что должен появиться новый контейнер и image:

Теперь протестируем тот же API, но через Docker контейнер, для этого нужно сделать на этот http://localhost:8080/api/ip/231321 эндпоинт

Как видим, результат тот же, как и в случае с обычным дебагом через dotnet run
Проект, который использовался в статье можно скачать тут.
В следующей статье мы рассматриваем как подключить MongoDB к нашему проекту и разберемся что такое docker compose.