WebAPI项目示例
创建WebAPI
建立一个Net6-with-MongoDB.Demo的WebAPI项目。
通过NuGet安装MongoDB.Driver:
Install-Package MongoDB.DriverInstall-Package AutoMapperInstall-Package AutoMapper.Extensions.Microsoft.DependencyInjection
一般来说,我们操作MongoDB都会选择这个官方的Driver。
配置MongoDB
首先,请参照之前的文章安装部署好一个MongoDB节点或集群。
然后,手动创建一个数据库BookStoreDB 和 一个集合 Books。
use BookStoreDBdb.CreateCollection('Books')
或者打开Mongo Express,http://localhost:8081/

最后,预先插入两条测试数据:
db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson','CreatedDate':ISODate("2012-10-02T07:58:51Z"),'UpdatedDate':ISODate("2012-10-02T07:58:51Z")},{'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin','CreatedDate':ISODate("2012-10-02T07:58:51Z"),'UpdatedDate':ISODate("2012-10-02T07:58:51Z")}])
需要注意的是:这里的连接字符串指向的是一个没有设置用户名密码的MongoDB节点。如果你的MongoDB节点设置了用户名密码 或者 复制集分片集 之类的,请修改为匹配的连接字符串。
然后,创建一个配置项类,也放到Models目录中:
namespace Net6.with.MongoDB.Demo.Models;public class DatabaseSettings : IDatabaseSettings{public string BooksCollectionName { get; set; }public string ConnectionString { get; set; }public string DatabaseName { get; set; }}public interface IDatabaseSettings{string BooksCollectionName { get; set; }string ConnectionString { get; set; }string DatabaseName { get; set; }}
最后,将其加入到IoC容器中控制:
using Microsoft.Extensions.Options;using Net6.with.MongoDB.Demo.Models;using Net6.with.MongoDB.Demo.Services;var builder = WebApplication.CreateBuilder(args);// AutoMapper Settingsbuilder.Services.AddAutoMapper(typeof(MappingConfigs));var appSetting = new AppSetting();builder.Configuration.GetSection("AppSetting").Bind(appSetting);//把AppSetting实体注入到容器,方便在构造函数里使用IOptionsSnapshot<AppSetting> optionsbuilder.Services.Configure<AppSetting>(builder.Configuration.GetSection("AppSetting"));// MongoDB Settingsbuilder.Services.Configure<AppSetting>(builder.Configuration.GetSection(nameof(AppSetting)));builder.Services.AddSingleton<IAppSetting>(sp =>sp.GetRequiredService<IOptions<AppSetting>>().Value);// Add services to the container.builder.Services.AddSingleton<IBookService, BookService>();builder.Services.AddControllers();builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();var app = builder.Build();// Configure the HTTP request pipeline.app.UseSwagger();app.UseSwaggerUI();app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();
这里,IBookstoreDatabaseSettings 接口使用单一实例服务生存期在 DI 中注册。在注入时,接口实例时将解析为 BookStoreDatabaseSettings 对象。
添加配置模型
首先,在appSettings.json中添加以下数据库配置:
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","AppSetting": {"SqlServerSetting": {"Connection": "Server=192.168.3.40;Database=webdemo;User=sa;Password=longfuchu;"},"MysqlSetting": {"Connection": "server=192.168.3.40;port=3306;user=root;password=123456;database=webdemo;charset=utf8;Allow Zero Datetime=true;sslmode=none;Old Guids=true;Allow User Variables=True"},"RedisSetting": {"Connection": "192.168.3.40:6379,password=","Database": "test"},"RabbitMQSetting": {"HostName": "localhost","UserName": "admin","Password": "admin","Port": 5672},"MongoDbSetting": {"Connection": "mongodb://192.168.3.40:2717", ///?replicaSet=rs0"Database": "BookStoreDB","CollectionName": "Books"}}}
namespace Net6.with.MongoDB.Demo.Models;/// <summary>/// mongodb setting/// </summary>public interface IAppSetting{/// <summary>/// SqlServerSetting/// </summary>SqlServerSetting SqlServerSetting { get; set; }/// <summary>/// MysqlSetting/// </summary>MysqlSetting MysqlSetting { get; set; }/// <summary>/// RedisSetting/// </summary>RedisSetting RedisSetting { get; set; }/// <summary>/// RabbitMQSetting/// </summary>RabbitMQSetting RabbitMQSetting { get; set; }/// <summary>/// MongoDbSetting/// </summary>MongoDbSetting MongoDbSetting { get; set; }/// <summary>/// KafkaSetting/// </summary>KafkaSetting KafkaSetting { get; set; }}/// <summary>/// mongodb setting/// </summary>public class AppSetting: IAppSetting{/// <summary>/// SqlServerSetting/// </summary>public SqlServerSetting SqlServerSetting { get; set; }/// <summary>/// MysqlSetting/// </summary>public MysqlSetting MysqlSetting { get; set; }/// <summary>/// RedisSetting/// </summary>public RedisSetting RedisSetting { get; set; }/// <summary>/// RabbitMQSetting/// </summary>public RabbitMQSetting RabbitMQSetting { get; set; }/// <summary>/// MongoDbSetting/// </summary>public MongoDbSetting MongoDbSetting { get; set; }/// <summary>/// KafkaSetting/// </summary>public KafkaSetting KafkaSetting { get; set; }}public class RabbitMQSetting{/// <summary>/// HostName/// </summary>public string HostName { get; set; } = "localhost";/// <summary>/// Password/// </summary>public string Password { get; set; }/// <summary>/// Username/// </summary>public string UserName { get; set; }/// <summary>/// The port to connect on./// </summary>public int Port { get; set; } = 5672;}public class RedisSetting{/// <summary>/// connection string/// </summary>public string Connection { get; set; }/// <summary>/// database name/// </summary>public string Database { get; set; }}public class MongoDbSetting{/// <summary>/// connection string/// </summary>public string Connection { get; set; }/// <summary>/// database name/// </summary>public string Database { get; set; }/// <summary>/// CollectionName/// </summary>public string CollectionName { get; set; }}public class SqlServerSetting{/// <summary>/// connection string/// </summary>public string Connection { get; set; }}public class MysqlSetting{/// <summary>/// connection string/// </summary>public string Connection { get; set; }}public class KafkaSetting{/// <summary>/// Servers/// </summary>public string Servers { get; set; }}
添加实体模型
在WebAPI项目中添加Models目录,并增加 Book 实体类:
using MongoDB.Bson.Serialization.Attributes;using MongoDB.Bson;namespace Net6.with.MongoDB.Demo.Models;public class Book : MongoDocBase{[BsonElement("Name")]public string BookName { get; set; }public decimal Price { get; set; }public string Category { get; set; }public string Author { get; set; }}public class MongoDocBase{[BsonId][BsonRepresentation(BsonType.ObjectId)]public string Id { get; set; }[BsonDateTimeOptions(Kind = DateTimeKind.Local)]public DateTime? CreatedDate { get; set; }[BsonDateTimeOptions(Kind = DateTimeKind.Local)]public DateTime? UpdatedDate { get; set; }}
需要注意的是:MongoDB存储时间类型数据时,都是先转换为UTC时间,然后存储到数据库中。当我们取出存储的时间时,就会出现时差的问题。因此,一般我们会给文档中的日期类型加上如下所示的注解,将它转换为本地时间传输:
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
在实际应用中,我们会给实体类创建一些DTO,然后在应用层进行DTO向DO的转换。因此,这里我们假设会进行 创建Book 和 修改Book 的操作,创建两个DTO类:
(1)CreateBookDto
using System.Text.Json.Serialization;namespace Net6.with.MongoDB.Demo.Models;public class CreateBookDto{public string BookName { get; set; }public decimal Price { get; set; }public string Category { get; set; }public string Author { get; set; }[JsonIgnore]public DateTime CreatedDate { get; set; } = DateTime.Now;}
(2)UpdateBookDto
using System.Text.Json.Serialization;namespace Net6.with.MongoDB.Demo.Models;public class UpdateBookDto : CreateBookDto{public string Id { get; set; }[JsonIgnore]public DateTime UpdatedDate { get; set; } = DateTime.Now;}
创建映射规则配置:
using AutoMapper;namespace Net6.with.MongoDB.Demo.Models;public class MappingConfigs : Profile{public MappingConfigs(){CreateMap<CreateBookDto, Book>().ReverseMap();CreateMap<UpdateBookDto, Book>().ForMember(dest => dest.CreatedDate, opt => opt.Ignore()).ReverseMap();}}
添加CRUD服务
在Services目录下,创建IBookService接口:
using Net6.with.MongoDB.Demo.Models;namespace Net6.with.MongoDB.Demo.Services;public interface IBookService{IList<Book> Get();Task<IList<Book>> GetAsync();Book Get(string id);Task<Book> GetAsync(string id);Book Create(Book book);Task<Book> CreateAsync(Book book);void Update(string id, Book bookIn);Task UpdateAsync(string id, Book bookIn);void Remove(string id);Task RemoveAsync(string id);}
然后,创建BookService 实现 IBookService 接口。
using Microsoft.Extensions.Options;using MongoDB.Driver;using Net6.with.MongoDB.Demo.Models;namespace Net6.with.MongoDB.Demo.Services;public class BookService : IBookService{private readonly IMongoCollection<Book> _books;public BookService(IAppSetting settings){var mongoClient = new MongoClient(settings.MongoDbSetting.Connection);var mongoDatabase = mongoClient.GetDatabase(settings.MongoDbSetting.Database);_books = mongoDatabase.GetCollection<Book>(settings.MongoDbSetting.CollectionName);}//错误//public BookService(IOptionsSnapshot<AppSetting> settings)//{// var mongoClient = new MongoClient(settings.Value.MongoDbSetting.Connection);// var mongoDatabase = mongoClient.GetDatabase(settings.Value.MongoDbSetting.Database);// _books = mongoDatabase.GetCollection<Book>(settings.Value.MongoDbSetting.CollectionName);//}public Book Create(Book book){_books.InsertOne(book);return book;}public async Task<Book> CreateAsync(Book book){await _books.InsertOneAsync(book);return book;}public IList<Book> Get(){return _books.Find(book => true).ToList();}public async Task<IList<Book>> GetAsync(){return await _books.Find(book => true).ToListAsync();}public Book Get(string id){return _books.Find(book => book.Id == id).FirstOrDefault();}public async Task<Book> GetAsync(string id){return await _books.Find(book => book.Id == id).FirstOrDefaultAsync();}public void Remove(string id){_books.DeleteOne(book => book.Id == id);}public async Task RemoveAsync(string id){await _books.DeleteOneAsync(book => book.Id == id);}public void Update(string id, Book bookIn){_books.ReplaceOne(book => book.Id == id, bookIn);}public async Task UpdateAsync(string id, Book bookIn){await _books.ReplaceOneAsync(book => book.Id == id, bookIn);}}
在上面的代码中,会通过构造函数从DI检索IBookStoreDatabaseSettings实例获取MongoDB连接字符串、数据库名 和 集合名。
当然,我们也可以使用 约定大于配置 的方式,统一采用实体类的名字 作为默认的 集合名,示例如下:
_books = mongoDatabase.GetCollection<Book>(typeof(Book).Name);
最后,将BookService也加入到IoC容器中:
services.AddSingleton<IBookService, BookService>();
这里,将BookService作为单一实例注入,这是因为 BookService 直接依赖于 MongoClient,而根据官方Mongo Client重用准则,我们应该使用单一实例服务在IoC容器中注入MongoClient。
添加Controller
在Controllers目录下,新增 BookController 控制器:
using AutoMapper;using Microsoft.AspNetCore.Mvc;using Net6.with.MongoDB.Demo.Models;using Net6.with.MongoDB.Demo.Services;namespace Net6.with.MongoDB.Demo.Controllers.MQ;/// <summary>////// </summary>[ApiController]public class BookController : AreaController{private readonly IMapper _mapper;private readonly IBookService _bookService;public BookController(IMapper mapper, IBookService bookService){_mapper = mapper;_bookService = bookService;}[HttpGet][ProducesResponseType(typeof(IList<Book>), StatusCodes.Status200OK)][ProducesResponseType(typeof(IList<Book>), StatusCodes.Status204NoContent)]public async Task<ActionResult<IList<Book>>> Get(){var books = await _bookService.GetAsync();if (books == null){return NoContent();}return Ok(books);}[HttpGet("{id:length(24)}", Name = "GetBook")][ProducesResponseType(typeof(Book), StatusCodes.Status200OK)][ProducesResponseType(typeof(Book), StatusCodes.Status404NotFound)]public async Task<ActionResult<Book>> Get(string id){var book = await _bookService.GetAsync(id);if (book == null){return NotFound();}return Ok(book);}[HttpPost][ProducesResponseType(typeof(Book), StatusCodes.Status201Created)]public async Task<ActionResult<Book>> Create(CreateBookDto bookDto){var book = _mapper.Map<Book>(bookDto);await _bookService.CreateAsync(book);return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, bookDto);}[HttpPut("{id:length(24)}")][ProducesResponseType(StatusCodes.Status200OK)][ProducesResponseType(StatusCodes.Status404NotFound)]public async Task<ActionResult> Update(string id, UpdateBookDto bookDto){var book = await _bookService.GetAsync(id);if (book == null){return NotFound();}_mapper.Map(bookDto, book);await _bookService.UpdateAsync(id, book);return Ok();}[HttpDelete("{id:length(24)}")][ProducesResponseType(StatusCodes.Status200OK)][ProducesResponseType(StatusCodes.Status404NotFound)]public async Task<ActionResult> Update(string id){var book = await _bookService.GetAsync(id);if (book == null){return NotFound();}await _bookService.RemoveAsync(id);return Ok();}}
测试WebAPI
生成该ASP.NET Core WebAPI应用,启动之后在Swagger页面进行测试:
参考
MongoDB入门实战教程(5)
Microsoft Doc:使用ASP.NET Core和MongoDB创建WebAPI
