Создаем свое первое 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.