我的开发环境:VS Code、Docker Desktop,都是目前的最新版本。
1.创建RESTful API
首先,我们新建一个文件夹,并用vs code打开该文件夹(我的文件夹名称叫"dotnet_docker")。
然后我们打开shell命令行,输入如下命令:
dotnet new webapi -o StudentApi
cd StudentApi
创建一个名为"StudentApi"的webapi项目,并切换到该项目的目录下。
如图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<StudentStoreDatabaseSettings>(
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<Student> _studentsCollection;
public StudentsService(
IOptions<StudentStoreDatabaseSettings> studentStoreDatabaseSettings)
{
var mongoClient = new MongoClient(
studentStoreDatabaseSettings.Value.ConnectionString);
var mongoDatabase = mongoClient.GetDatabase(
studentStoreDatabaseSettings.Value.DatabaseName);
_studentsCollection = mongoDatabase.GetCollection<Student>(
studentStoreDatabaseSettings.Value.StudentsCollectionName);
}
public async Task<List<Student>> GetAsync() =>
await _studentsCollection.Find(_ => true).ToListAsync();
public async Task<Student?> 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<StudentStoreDatabaseSettings>(
builder.Configuration.GetSection("StudentStoreDatabase"));//添加数据库映射
builder.Services.AddSingleton<StudentsService>(); //添加单例模式依赖(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<List<Student>> Get() =>
await _studentsService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Student>> Get(string id)
{
var student = await _studentsService.GetAsync(id);
if (student is null)
{
return NotFound();
}
return student;
}
[HttpPost]
public async Task<IActionResult> Post(Student newStudent)
{
await _studentsService.CreateAsync(newStudent);
return CreatedAtAction(nameof(Get), new { id = newStudent.Id }, newStudent);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> 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<IActionResult> 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:
- 测试web API
打开shell命令行,输入如下命令运行项目:
dotnet run
运行成功应该会如图3所示:
-
测试API
这边我是用Postman来测试请求:
图4,post添加数据:
图5,get请求所有数据:
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:
我们ps一下看看当前运行的镜像(图7):
这两个就是我们刚才运行的运行的镜像。
6.测试
我们刚才在docker-compose.yml指定了映射8080端口,先在在Postman访问http://localhost:8080/api/students,get一下所有数据,如图7:
然后我们随便post加一条数据,如图8:
我们再回过来get所有数据,如图9:
进入mongo容器查看一下我们刚才数据:
在shell命令行ps一下拿到id并exec进去,并连接mongodb,如图10:
找到我们创建的数据库,集,并查看数据,如图11:
再一次提醒,这里数据因为我没有在docker-compose.yml加volume,所以容器关了就会丢失。
至此,完成。