ASP.NET Core 2.0 和 Docker 在 MacOS






4.92/5 (7投票s)
快速 walkthrough 在 MAC 上构建 ASP.NET Core 2.0 应用程序并在 Docker 容器中运行它
↵
引言
去年,我写了一篇关于“.NET Core 在 Mac 上 - 使用 Web API、EF、PostgreSQL 构建 ASP.NET Core 应用并将其运行在 Docker 中”的文章。该文章使用的是 .NET Core 1.1 版本,如果您按照文章中提到的相同步骤使用 .NET Core/ASP.NET Core 2.0,那么这些步骤将不再有效。
一年多以来,.NET Core 1.x 到 2.0 版本发生了一些变化。在本文中,我们将通过构建一个简单的 Web API 应用程序并将其部署到 Docker 容器中,来探索 ASP.NET Core 2.0 和 Docker。
引用注意:在继续阅读之前,请确保您对 ASP.NET Core 和 Docker 有基本的了解,因为我不会在本文中详细介绍每项技术。
必备组件
在动手之前,我们需要为我们在 MAC 环境中构建和运行应用程序更新/安装所需的工具和 SDK。请继续安装以下内容:
- 适用于 MAC 的 .NET SDK (撰写本文时使用的最新版本是 2.0.3)。
- 适用于 MAC 的 Visual Studio (Visual Studio 2017)
- 适用于 MAC 的 Docker (撰写本文时使用的最新版本是 17.06.2-ce)
.NET Core 2.0 和 ASP.NET Core 2.0 的 Docker 镜像
安装完所有必备软件后,我们需要从 Docker Hub 拉取 .NET Core 和 ASP.NET Core 所需的 Docker 镜像。请打开终端并分别运行以下命令:
- docker pull microsoft/dotnet:2.0.0-sdk
- docker pull microsoft/aspnetcore:2.0.0
- docker pull microsoft/aspnetcore-build:2.0.0
拉取 Docker 镜像后,可以通过运行以下命令进行验证:
$ docker images
上述命令应该会得到类似如下结果:

创建您的第一个 ASP.NET Core 2.0 项目
现在,启动 Visual Studio 2017 并创建一个空的 ASP.NET Core 项目,如下图所示:

点击“下一步”。在下一个屏幕上,选择 .NET Core 2.0 作为目标框架,然后点击“下一步”。现在应该会显示以下屏幕:

为简化演示,将项目命名为“aspnetcoredemo”,然后浏览到您想要创建项目的路径。点击“创建”让 Visual Studio 为您生成默认文件。您应该能看到类似下图的内容:

首次运行项目
点击“播放”按钮来构建和运行项目。当一切成功构建后,您的浏览器中应该会显示类似如下的内容:

就是这样!我们现在已经在 MAC 上运行了一个 ASP.NET Core 2.0 应用程序。
开始吧!
现在,为了让这个演示更有趣,我们将进一步创建一个简单的 Web API 来处理基本的 CRUD 操作,并使用 Postgres 作为我们的数据库。然后,我们将把应用程序和数据库运行在 Docker 容器中。
添加 Docker 文件
我们需要做的第一件事是在项目中创建一个 Docker 文件。Dockerfile 包含构建 Docker 镜像的指令。有关更多信息,请参阅 Dockerfile 参考。
在 Dockerfile 中添加以下命令:
FROM microsoft/aspnetcore-build:2.0.0 AS build
WORKDIR /code
COPY . .
RUN dotnet restore
RUN dotnet publish --output /output --configuration Release
FROM microsoft/aspnetcore:2.0.0
COPY --from=build /output /app
WORKDIR /app  
ENTRYPOINT ["dotnet", "aspnetcoredemo.dll"]
集成 EF Core 和 PostgreSql
切换回 Visual Studio 并安装以下最新的 Nuget 包:
- Npgsql.EntityFrameworkCore.PostgreSQL
- Microsoft.EntityFrameworkCore.Tools
- Microsoft.EntityFrameworkCore.Design
上述包使我们能够使用 EntityFramework Core 作为我们的数据访问机制。我们将使用 EF Core 来同步和更新 PosgreSql 数据库,然后使用 Web API 来处理数据请求。
Entity Framework Core 现在支持多种数据库提供程序。在本演示中,我们将把 PostgreSQL 集成到我们的 .NET Core 应用程序中。安装 Postgres 最简单的方法是使用 Homebrew,它应该包含在 .NET Core SDK 的安装中。现在运行以下命令来下载和安装 PostreSQL:
$ brew install postgresql
如果安装顺利,数据库管理器就会安装好。现在,通过运行以下命令来启动 PostgreSQL 服务容器:
$ docker run -d --name localdb -e POSTGRES_PASSWORD=supersecret postgres
-d 选项使容器在后台运行并打印容器 ID。--name 为容器分配一个名称,在本例中,我们将容器命名为“localdb”。-e 允许我们设置环境变量,在本例中,我们使用 POSTGRES_PASSWORD 变量为我们的 Postgres 镜像设置了密码“supersecret”。
运行上述命令将公开 postgres 端口 5432,从而使标准容器可以被链接的容器访问。initdb 也将生成默认用户和数据库。
要验证我们的 PostgresSQL Docker 容器是否已启动并正在运行,请执行:
$ docker ps
要测试连接,您可以执行:
$ docker run -it --rm --link pg-db:postgres postgres psql -h postgres -U postgres 
创建应用程序
现在我们的数据库已经在 Docker 容器中准备就绪,是时候构建应用程序了。
设置数据库连接字符串
添加一个新的空 .json 文件,并将其命名为“appsettings”,如下图所示:

然后,复制下面的设置:
"DbContextSettings": {
    "ConnectionString": "User ID=postgres;Password=supersecret;
     Server=postgres;Port=5432;Database=POSTGRES_USER;
     Integrated Security=true;Pooling=true;"
}
上述 connectionstring 将允许我们连接到之前运行的 PostgreSql 服务容器。
创建模型
在本演示中,我们将使用 EF Code-First 方法,这意味着我们将先创建模型,然后运行迁移,让 EF 根据我们的模型生成数据库/模式。
在项目根目录下创建一个新的类,并将文件命名为“Student”。复制下面的代码:
namespace aspnetcoredemo  
{
    public class Student
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}
定义 DbContext
EF Core Code-First 开发方法要求我们定义一个继承自 DbContext 类的数据访问上下文类。现在,在项目根目录下添加一个新的类。将文件命名为“StudentContext”,然后复制下面的代码:
using System;  
using Microsoft.EntityFrameworkCore;
namespace aspnetcoredemo  
{
    public class StudentContext: DbContext
    {
        public StudentContext
        (DbContextOptions<StudentContext> options)  
            : base(options)  
        { }
        public DbSet<Student> Students { get; set; }
    }
}
注册服务与依赖注入
接下来,我们需要将 DbContext 注册为服务,并启用 MVC 服务以启用 Web API。打开 startup.cs 并用以下代码替换现有代码:
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.AspNetCore.Http;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.Extensions.Configuration;  
using Microsoft.Extensions.DependencyInjection;
namespace aspnetcoredemo  
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName} .json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
        public IConfigurationRoot Configuration { get; }
        // 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)
        {
            services.AddMvc();
            var connectionString = 
                Configuration["DbContextSettings:ConnectionString"];
            services.AddDbContext<StudentContext>
                     (opts => opts.UseNpgsql(connectionString));
        }
        // This method gets called by the runtime. 
        // Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
        }
    }
}
让我们修改 Program.cs 以在启动时创建数据库。这是完整的代码:
using System;  
using Microsoft.AspNetCore;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Logging;
namespace aspnetcoredemo  
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
            var host = BuildWebHost(args);
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    services.GetService<StudentContext>().Database.Migrate();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }
            host.Run();
        }
        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}
EF Core 不会自动执行迁移,这就是为什么我们需要上述配置才能使用 Code-First 迁移。Database.Migrate() 方法负责两件事:
- 如果 PostgreSQL 中不存在,则创建数据库。
- 将数据库模式迁移到最新版本。
添加迁移
我们将使用 EF Core 工具来脚手架迁移并更新数据库。我们将使用命令行 (dotnet CLI) 来运行迁移。撰写本文时,由于以下错误,我们无法从 Nuget 添加 Microsoft.EntityFrameworkCore.Tools.DotNet 包:
“包 'Microsoft.EntityFrameworkCore.Tools.DotNet 2.0.0' 具有不受项目支持的 'DotnetCliTool' 包类型”
作为一种解决方法,我们可以编辑项目文件 (.csproj) 并添加以下配置:
<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" 
     Version="2.0.0" />
</ItemGroup>
现在打开终端到项目根目录所在的位置,然后执行:
$ dotnet ef migrations add InitialMigration
ef migration add 是添加迁移的命令。如果迁移成功,您应该会看到一个名为“Migrations”的新文件夹,其中包含迁移文件,如下图所示:

上面生成的文件将用于在首次运行时创建数据库。
创建 Web API 控制器
现在是时候创建简单的 Web API 方法来处理简单的 GET 和 POST 请求了。添加一个新的 Web API 控制器类并复制以下代码:
using System.Collections.Generic;  
using System.Linq;  
using Microsoft.AspNetCore.Mvc;
namespace aspnetcoredemo.API  
{
    [Route("api/[controller]")]
    public class StudentsController : Controller
    {
        private readonly StudentContext _context; 
        public StudentsController(StudentContext context)
        {
            _context = context;
        }
        // GET: api/students  
        public IEnumerable<Student> Get()  
        {  
            return _context.Students.ToList();  
        }  
        // GET api/students/1  
        [HttpGet("{id}")]  
        public Student Get(int id)  
        {  
            return _context.Students.FirstOrDefault(x => x.Id == id);  
        }  
        // POST api/students  
        [HttpPost]  
        public IActionResult Post([FromBody]Student value)  
        {  
            _context.Students.Add(value);  
            _context.SaveChanges();  
            return StatusCode(201, value);  
        }  
    }
}
那里没什么花哨的,上面的代码只包含几个与 StudentContext 通信的基本方法。请注意,我们在 Controller 的构造函数中注入了 StudentContext 的实例,以便我们可以与数据库进行交互,并用它来查询数据。
在 Docker 中运行应用程序
此时,我们已准备好将应用程序部署到 Docker。首先,让我们通过运行以下命令来构建应用程序:
$ docker build -t dockerdemo .
上面的命令将在我们的 Docker 机器中生成一个新映像实例。您可以通过在命令行中运行 docker images 来查看映像列表。
现在,运行以下命令以确保我们的 PostgreSQL 数据库映像已启动并正在运行:
$ docker ps 
现在,让我们使用以下命令运行我们的 ASP.NET Core 2.0 应用程序并链接我们创建的数据库:
$ docker run -it -p 5000:80 --link localdb:postgres dockerdemo
测试 Web API 端点
以下是使用 Postman 测试端点的结果截图:
POST

GET

GET/Id

就是这样!希望您觉得这篇文章有用。
参考文献
- .NET Core 在 Mac 上 - 使用 Web API、EF、PostgreSQL 构建 ASP.NET Core 应用并将其运行在 Docker 中
- 开始使用 Docker for Mac
- Docker 命令
- ASP.NET Core 简介
摘要
在本文中,我们学习了在 MAC 环境中设置 .NET Core 2 的基础知识,并学习了如何创建一个简单的 ASP.NET Core 2 应用程序,其中包含 Web API、EF、PostgreSQL,并将其运行在 Docker 中。
历史
- 2018 年 1 月 3 日:初始版本


