.Net微服务,一步一步从零开始搭建 .Net6 + MongoDB + Docker Compose

我的开发环境:VS Code、Docker Desktop,都是目前的最新版本。

1.创建RESTful API

首先,我们新建一个文件夹,并用vs code打开该文件夹(我的文件夹名称叫"dotnet_docker")。
然后我们打开shell命令行,输入如下命令:

dotnet new webapi -o StudentApi
cd StudentApi

创建一个名为"StudentApi"的webapi项目,并切换到该项目的目录下。
如图1:

图1

添加mongodb驱动,输入如下命令:

dotnet add package MongoDB.Driver
  • 添加model
    创建一个文件夹名为"Models",然后在里面添加一个"Student"的class,代码如下:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace StudentApi.Models;

public class Student
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string? Id { get; set; }

    [BsonElement("name")]
    public string Name { get; set; } = null!;

    [BsonElement("age")]
    public int Age { get; set; }
}
  • 添加数据库配置
    修改开发环境配置文件appsettings.Development.json,添加"StudentStoreDatabase"节点,代码如下:
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "StudentStoreDatabase": {
    "ConnectionString": "mongodb://localhost:27017",
    "DatabaseName": "StudentStore",
    "StudentsCollectionName": "Students"
  }
}

在"Models"文件夹添加一个名为"StudentStoreDatabaseSettings"的model用来映射"StudentStoreDatabase节点,代码如下:

namespace StudentApi.Models;

public class StudentStoreDatabaseSettings
{
    public string ConnectionString { get; set; } = null!;

    public string DatabaseName { get; set; } = null!;

    public string StudentsCollectionName { get; set; } = null!;
}
  • 在Program.cs文件中,添加数据库映射
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.Configure(
    builder.Configuration.GetSection("StudentStoreDatabase")); //添加数据库映射

在最顶部添加StudentStoreDatabaseSettings的引用

using StudentApi.Models;
  • 添加增删改查CRUD service
    创建一个名为"Services"文件夹,并往里面添加"StudentsService"的class
using StudentApi.Models;
using Microsoft.Extensions.Options;
using MongoDB.Driver;

namespace StudentApi.Services;

public class StudentsService
{
    private readonly IMongoCollection _studentsCollection;

    public StudentsService(
        IOptions studentStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            studentStoreDatabaseSettings.Value.ConnectionString);

        var mongoDatabase = mongoClient.GetDatabase(
            studentStoreDatabaseSettings.Value.DatabaseName);

        _studentsCollection = mongoDatabase.GetCollection(
            studentStoreDatabaseSettings.Value.StudentsCollectionName);
    }

    public async Task> GetAsync() =>
        await _studentsCollection.Find(_ => true).ToListAsync();

    public async Task GetAsync(string id) =>
        await _studentsCollection.Find(x => x.Id == id).FirstOrDefaultAsync();

    public async Task CreateAsync(Student newStudent) =>
        await _studentsCollection.InsertOneAsync(newStudent);

    public async Task UpdateAsync(string id, Student updatedStudent) =>
        await _studentsCollection.ReplaceOneAsync(x => x.Id == id, updatedStudent);

    public async Task RemoveAsync(string id) =>
        await _studentsCollection.DeleteOneAsync(x => x.Id == id);
}

  • 添加单例模式依赖(singleton)
    这里用singleton而不是像之前的EF那样用scoped,因为根据官网文档它是直接依赖MongoClient。
    在Program.cs添加如下代码代码:
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.Configure(
    builder.Configuration.GetSection("StudentStoreDatabase"));//添加数据库映射
builder.Services.AddSingleton(); //添加单例模式依赖(singleton)
  • 添加controller
    在Controllers文件夹添加""的class文件:
using StudentApi.Models;
using StudentApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace StudentApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class StudentsController : ControllerBase
{
    private readonly StudentsService _studentsService;

    public StudentsController(StudentsService studentsService) =>
        _studentsService = studentsService;

    [HttpGet]
    public async Task> Get() =>
        await _studentsService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task> Get(string id)
    {
        var student = await _studentsService.GetAsync(id);

        if (student is null)
        {
            return NotFound();
        }

        return student;
    }

    [HttpPost]
    public async Task Post(Student newStudent)
    {
        await _studentsService.CreateAsync(newStudent);

        return CreatedAtAction(nameof(Get), new { id = newStudent.Id }, newStudent);
    }

    [HttpPut("{id:length(24)}")]
    public async Task Update(string id, Student updatedStudent)
    {
        var student = await _studentsService.GetAsync(id);

        if (student is null)
        {
            return NotFound();
        }

        updatedStudent.Id = student.Id;

        await _studentsService.UpdateAsync(id, updatedStudent);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task Delete(string id)
    {
        var student = await _studentsService.GetAsync(id);

        if (student is null)
        {
            return NotFound();
        }

        await _studentsService.RemoveAsync(id);

        return NoContent();
    }
}

另外,需要把https跳转关了,因为我们本地没有验证证书。
在Program.cs文件中,在注释"app.UseHttpsRedirection();"

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

//注释这里
// app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

至此,整体目录结构应该如图2:


图2
  • 测试web API
    打开shell命令行,输入如下命令运行项目:
 dotnet run

运行成功应该会如图3所示:


图3
  • 测试API
    这边我是用Postman来测试请求:
    图4,post添加数据:


    图4

图5,get请求所有数据:


图5

2.创建Dockerfile

Dockerfile就是把你目前的项目打包成已经镜像,然后用这个镜像进行部署。
我们先在shell命令行按 "control+c" 把运行中的项目停了,然后在项目目录(StudentApi)中添加一个名为"Dockerfile"的文件,注意不要加任何后续,如"txt"这些,并添加如下代码:

#第一阶段,利用sdk镜像环境生成发布dll,主要是运行"dotnet publish"这个命令;
#这个阶段也可以在外面用shell直接运行。
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-evn
WORKDIR /source

COPY . ./
RUN dotnet restore
RUN dotnet publish -c Release -o /out

#第二阶段,利用aspnet镜像运行第一阶段生成发布的dll,主要是"dotnet xxx.dll"这个命令,跟我们在linux运行.net一样
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app

COPY --from=build-evn /out .
ENTRYPOINT ["dotnet","StudentApi.dll"]

3.创建docker-compose.yml

有时候我们的docker run命令会很长很长,每次部署服务器时候都写一次十分不现实, docker-compose可以把你docker run命令写到一个文件中,而且默认是用同一个docker network,假如你安装的是docker desktop,则不需要额外安装docker-compose,如果你是linux服务器,除了安装docker engine外,还要自己手动安装docker-compose。
在项目目录(StudentApi)中添加一个名为"docker-compose.yml"的文件,并添加如下代码:

version: '3.6'
services:
  web:
    build: . #根目录下会找到我们之前的Dockerfile,并运行生成镜像
    ports:
      - "8080:80" #在docker容器中.net默认是80端口,可以通过environment指定
    depends_on:
      - db
  
  db: #这里名称会默认为网络的别名,这样我们web就可以不需要知道mongodb的ip,直接用这个名称代替ip
    image: mongo #我这里的mongodb没有指定用户密码,可以通过environment指定
    

注意,我这里没有用 volume,所以容器一旦关掉了数据都丢失了,我这里不是服务器,只是演示,所以我希望数据用完就丢失,假如有需要的同学可以加个volume

4.修改数据库连接

在1步中,我们用来连接数据的配置文件是"appsettings.Development.json",这文件在开发环境生效,
现在我们需要在"appsettings.json"添加mongodb的配置,添加"StudentStoreDatabase"节点,代码如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "StudentStoreDatabase": {
    "ConnectionString": "mongodb://db:27017",
    "DatabaseName": "StudentStore",
    "StudentsCollectionName": "Students"
  }
}

这里注意ConnectionString,在"appsettings.Development.json"中是"localhost",现在我们改成"db",db这个名字在"docker-compose.yml"文件中取。

5.打包镜像并运行

打开shell命令行,输入如下命令运行打包镜像并运行:

docker-compose up -d

运行成功应该会如图6:


图6

我们ps一下看看当前运行的镜像(图7):


图7

这两个就是我们刚才运行的运行的镜像。

6.测试

我们刚才在docker-compose.yml指定了映射8080端口,先在在Postman访问http://localhost:8080/api/students,get一下所有数据,如图7:

image.png

然后我们随便post加一条数据,如图8:
图8

我们再回过来get所有数据,如图9:
图9

进入mongo容器查看一下我们刚才数据:
在shell命令行ps一下拿到id并exec进去,并连接mongodb,如图10:
图10

找到我们创建的数据库,集,并查看数据,如图11:
图11

再一次提醒,这里数据因为我没有在docker-compose.yml加volume,所以容器关了就会丢失。

至此,完成。

你可能感兴趣的:(.Net微服务,一步一步从零开始搭建 .Net6 + MongoDB + Docker Compose)