.NET Aspire与Docker技术对比:云原生开发实战解析

本文详细对比了使用.NET Aspire和Docker为.NET项目添加PostgreSQL服务依赖的具体步骤,包括项目创建、依赖配置、数据库迁移和运行部署等完整流程,展示了两种技术方案在开发体验上的差异。

.NET Aspire vs Docker

这是我之前比较.NET Aspire与NuGet文章的后续。在那篇文章中,我承诺会跟进比较使用.NET Aspire与Docker为项目添加服务依赖的方法。看吧,这次我总算说到做到了!

这些示例的目标是查看使用.NET Aspire与使用Docker为.NET项目添加服务依赖需要多少"仪式性"步骤。虽然这可能不是"最佳"示例,但我选择了PostgreSql,因为它通常是我添加到新项目的第一个服务依赖。如果我选择除Postgres之外的另一个服务依赖,示例会更强大,但我想你也可以推断出来。而且我正在进行的另一个项目会有更多依赖。

我不会将安装先决条件工具作为"仪式"的一部分,因为这是一次性的事情。我将专注于将服务依赖添加到项目的步骤。

工具

我编写这篇文章是为了让你可以跟随并在自己的计算机上创建项目。如果你想跟随操作,需要安装以下工具:

  • .NET 8 SDK
  • Docker Desktop
  • .NET Aspire工具

安装这些后,还需要安装Aspire .NET工作负载:

1
2
dotnet workload update
dotnet workload install aspire

示例

本节包含两个分步演练,分别使用Docker和PostgreSql创建示例项目。

示例项目是一个简单的Blazor Web应用程序,带有PostgreSQL数据库。我将使用Entity Framework Core与数据库交互。我还将使用dotnet-ef命令行工具创建迁移。

由于我们要创建两次相同的项目,我将把需要的通用代码放在这里,因为两个演练都会引用它。

两个项目都将使用自定义的DbContext派生类和一个具有Id和Name的简单User实体。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
using Microsoft.EntityFrameworkCore;

namespace HaackDemo.Web;

public class DemoDbContext(DbContextOptions<DemoDbContext> options)
  : DbContext(options)
{
    public DbSet<User> Users { get; set; }
}

public class User
{
    public int Id { get; set; }

    public string Name { get; set; }
}

此外,两个项目都有几个在启动时运行的后台服务:

  • DemoDbInitializer - 在启动时运行迁移并种子化数据库
  • DemoDbInitializerHealthCheck - 设置健康检查以报告数据库初始化器的状态

我过去常在Program.cs中的启动时运行迁移,但我在Aspire示例中看到了这个示例,并决定尝试一下。我还复制了他们的健康检查初始化器。

这两个都需要在Program.cs中注册:

1
2
3
4
builder.Services.AddSingleton<DemoDbInitializer>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<DemoDbInitializer>());
builder.Services.AddHealthChecks()
    .AddCheck<DemoDbInitializerHealthCheck>("DbInitializer", null);

有了这些准备,让我们开始吧。

Docker

从你的根开发目录,以下命令将创建一个新的Blazor项目和解决方案:

1
2
3
4
md docker-efcore-postgres-demo && cd docker-efcore-postgres-demo
dotnet new blazor -n DockerDemo -o DockerDemo.Web
dotnet new sln --name DockerDemo
dotnet sln add DockerDemo.Web

Npgqsl是Entity Framework Core的PostgreSql提供程序。我们需要将其添加到Web项目:

1
2
cd DockerDemo.Web
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL

我们还需要EF Core Design包来支持我们将用于创建迁移的dotnet-ef命令行工具:

1
dotnet add package Microsoft.EntityFrameworkCore.Design

现在我们将docker文件添加到根目录:

1
2
cd ..
touch docker-compose.yml

并粘贴以下内容:

1
2
3
4
5
6
7
8
9
version: '3.7'

services:
  postgres:
    container_name: 'postgres'
    image: postgres
    environment:
      # change this for a "real" app!
      POSTGRES_PASSWORD: password

注意container_name可能与系统上的其他容器冲突。你可能需要将其更改为唯一的内容。

将postgres连接字符串添加到你的appsettings.json:

1
2
3
"ConnectionStrings": {
  "postgresdb": "User ID=postgres;Password=password;Server=postgres;Port=5432;Database=POSTGRES_USER;Integrated Security=true;Pooling=true;"
}

现在我们可以添加前面提到的自定义DbContext派生类和User实体。我们还需要如前所述在Program.cs中注册DemoDbInitializer和DemoDbInitializerHealthCheck。

接下来创建初始迁移:

1
2
cd ../DockerDemo.Web
dotnet ef migrations add InitialMigration

我们准备好运行应用程序了。首先,我们需要启动Postgres容器:

1
2
docker-compose build
docker-compose up

最后,我们可以在Visual Studio/Rider中按F5或在终端中运行dotnet run,在本地运行我们的应用程序。

Aspire

再次从你的根开发目录,以下命令将创建一个新的Blazor项目和解决方案。但这次,我们将使用Aspire启动模板:

1
2
md aspire-efcore-postgres-demo && cd aspire-efcore-postgres-demo
dotnet new aspire-starter -n AspireDemo -o .

这会创建三个项目:

  • AspireDemo.AppHost - 配置应用程序的主机项目
  • AspireDemo.Web - Web应用程序项目
  • AspireDemo.ApiService - 获取天气的示例Web服务

我们在这个示例中不需要AspireDemo.ApiService,所以可以删除它。

我们想做的第一件事是在AspireDemo.AppHost项目中配置PostgreSql服务。在某种程度上,这类似于我们在Docker示例中在docker-compose.yml文件中配置Postgres的方式。

切换到App Host项目并安装Aspire.Hosting.PostgreSQL包:

1
2
cd ../AspireDemo.AppHost
dotnet add package Aspire.Hosting.PostgreSQL

在Program.cs中创建构建器后添加此代码片段:

1
2
var postgres = builder.AddPostgres("postgres");
var postgresdb = postgres.AddDatabase("postgresdb");

这将创建一个名为postgres的Postgres服务和一个名为postgresdb的数据库。当我们在消费项目中想要连接到数据库时,将使用postgresdb引用。

最后,我们更新现有行以包含数据库引用:

1
2
3
builder.AddProject<Projects.AspireDemo_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(postgresdb);

这就完成了App Host项目中PostgreSql服务的配置。现在我们可以从我们的Web项目中使用它。

将PostgreSQL组件添加到消费项目,即Web应用程序:

1
2
cd ../AspireDemo.Web
dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL

我们还需要EF Core Design包来支持我们将用于创建迁移的ef命令行工具:

1
dotnet add package Microsoft.EntityFrameworkCore.Design

再次,我们将自定义DbContext派生类DemoDbContext与User实体一起添加到项目。完成后,我们在Program.cs文件中配置DemoDbContext。注意我们使用在App Host项目中创建的postgresdb引用:

1
builder.AddNpgsqlDbContext<DemoDbContext>("postgresdb");

然后我们可以使用dotnet-ef cli工具创建迁移:

1
2
cd ../AspireDemo.Web
dotnet ef migrations add InitialMigration

不要忘记将DemoDbInitializer和DemoDbInitializerHealthCheck添加到项目,并如前所述在Program.cs中注册它们。

现在要运行应用程序,我可以在Visual Studio/Rider中按F5或在终端中运行dotnet run。如果使用F5,请确保AppHost项目被选为运行项目。

结论

在两个演练的最后,我们最终得到了一个使用PostgreSQL数据库的简单Blazor Web应用程序。就个人而言,我喜欢.NET Aspire方法,因为我不需要处理连接字符串,并且保留了F5运行体验。

正如我之前提到的,我正在进行的另一个项目有更多依赖。当我完成该端口时,我认为这将是一个更好的示例,展示使用.NET Aspire时围绕云依赖的仪式性步骤。

无论如何,你可以在GitHub上查看我创建的这两个项目:

  • haacked/docker-efcore-postgres-demo
  • haacked/aspire-efcore-postgres-demo
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计