如何使用 .NET Core 8 构建干净架构的 Web API
一. 引言
在软件开发中,干净架构是一种设计方法,旨在确保应用程序的代码结构清晰、有序、易于维护和适应变化。它的核心原则是将业务逻辑与外部依赖(如框架和用户界面)分离,从而在不影响核心系统的情况下,便于更新和扩展。
干净架构的主要目标是创建一个结构,使业务逻辑独立,从而减少更改对核心系统的影响。这意味着您可以替换或修改框架、数据库或UI组件,而无需重写核心代码。通过将依赖项保持为外部和可替换的,您可以创建一个灵活、持久的应用架构,经受时间的考验。
本文将引导您逐步实现 .NET Core 8 中的干净架构,确保您的应用程序建立在坚实、可扩展的原则上。
二. 什么是干净架构?
干净架构是一种软件设计模式,将代码组织为不同的层次,确保关注点的清晰分离。其主要目标是使应用程序更易于维护、测试和适应变化。干净架构将核心业务逻辑与外部依赖(如数据库、框架和用户界面)隔离开来。
在干净架构中,代码分为四个关键层次:
-
领域层(Domain Layer):包含核心业务逻辑和实体。该层完全独立于外部技术。 -
应用层(Application Layer):管理用例并与领域层交互以执行业务操作。 -
基础设施层(Infrastructure Layer):处理外部关注点,例如数据库、API和文件系统。它实现了仓库模式,以分离数据访问逻辑。 -
表示层(Presentation Layer):用户界面或API层,与用户或其他系统交互,处理HTTP请求和响应。
通过保持这些层的独立性,干净架构确保UI、数据库或任何外部服务的变化不会影响应用程序的核心逻辑,从而使其在长期内更加弹性和灵活。
三. 干净架构的优缺点
优点 | 缺点 |
---|---|
清晰的组织结构:应用的每个部分都有特定角色。 | 复杂的设置:对于小项目来说,设置更难。 |
易于维护:可以在不影响整个系统的情况下进行更改。 | 初始开发耗时:最初开发速度较慢。 |
更好的测试:核心逻辑更易于测试。 | 难以学习:对于新开发者可能会造成困惑。 |
灵活性:可以在不改变核心逻辑的情况下更换数据库、UI或框架。 | 对小应用来说过于复杂:可能不适合简单项目。 |
无框架锁定:核心逻辑不依赖于特定框架。 | 代码量增加:增加额外的代码和文件。 |
便于协作:开发者可以分别处理不同部分。 | 可能影响性能:额外的层可能会影响速度。 |
可扩展性:应用程序增长时易于添加新功能。 | 可能导致重复代码:这可能导致层之间的相似代码。 |
面向未来:技术变化不会破坏核心逻辑。 | 调试更困难:许多层次可能使调试变得复杂。 |
四. 干净架构的实现步骤
步骤 1: 创建新项目
在 Visual Studio 中创建一个空解决方案,并将其命名为 CleanArchitectureDemo
。
步骤 2: 创建领域层项目
创建一个新的类库项目,命名为 CleanArchitecture.Domain
。该层包含企业逻辑,包括实体及其规范。
步骤 3: 添加模型类
在该项目中添加名为 Movie.cs
的模型类。
using System;
namespace CleanArchitecture.Domain
{
public class Movie
{
// 默认构造函数
public Movie() { }
// 带参数的构造函数
public Movie(int movieId, string name, int cost)
{
this.MovieId = movieId; // 设置电影ID
this.Name = name; // 设置电影名称
this.Cost = cost; // 设置电影成本
}
public int MovieId { get; set; } // 电影ID属性
public string Name { get; set; } = string.Empty; // 电影名称属性
public int Cost { get; set; } // 电影成本属性
}
}
步骤 4: 创建应用层项目
接下来,创建一个名为 CleanArchitectureDemo.Application
的类库项目。应用层包含业务逻辑。
4.1 创建文件夹
创建三个文件夹:IService
、Service
和 IRepository
。
4.2 创建接口和服务
在 IService
文件夹中添加 IMovieService.cs
接口,在 Service
文件夹中添加 MovieService.cs
类,在 IRepository
文件夹中添加 IMovieRepository.cs
接口。
IMovieService.cs
using CleanArchitecture.Domain;
using System.Collections.Generic;
namespace CleanArchitecture.Application.IService
{
public interface IMovieService
{
List<Movie> GetAllMovies(); // 获取所有电影的接口
}
}
MovieService.cs
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Application.IService;
using CleanArchitecture.Domain;
using System.Collections.Generic;
namespace CleanArchitecture.Application.Service
{
public class MovieService : IMovieService
{
private readonly IMovieRepository movieRepository; // 声明电影仓库接口
// 构造函数,注入IMovieRepository
public MovieService(IMovieRepository movieRepository)
{
this.movieRepository = movieRepository; // 初始化电影仓库
}
// 获取所有电影的方法
public List<Movie> GetAllMovies()
{
var movies = movieRepository.GetAllMovies(); // 调用仓库获取电影列表
return movies; // 返回电影列表
}
}
}
IMovieRepository.cs
using CleanArchitecture.Domain;
using System.Collections.Generic;
namespace CleanArchitecture.Application.IRepository
{
public interface IMovieRepository
{
List<Movie> GetAllMovies(); // 获取所有电影的接口
}
}
步骤 5: 创建基础设施层
创建一个名为 CleanArchitectureDemo.Infrastructure
的类库项目,处理外部关注点。
5.1 创建仓库
创建一个名为 Repository
的文件夹,并添加 MovieRepository.cs
类。
MovieRepository.cs
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Domain;
using System.Collections.Generic;
namespace CleanArchitecture.Infrastructure.Repository
{
public class MovieRepository : IMovieRepository
{
// 静态电影列表
private static List<Movie> movies = new List<Movie>
{
new Movie() { Cost = 100, Name = "M1", MovieId = 1 },
new Movie() { Cost = 200, Name = "M2", MovieId = 2 },
new Movie() { Cost = 150, Name = "M3", MovieId = 3 }
};
// 获取所有电影的方法
public List<Movie> GetAllMovies()
{
return movies; // 返回电影列表
}
}
}
步骤 6: 创建表示层
创建一个名为 CleanArchitecture.API
的API项目,负责向前端用户展示数据。
6.1 添加依赖注入
在 Program.cs
文件中添加依赖注入配置。
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Application.IService;
using CleanArchitecture.Application.Service;
using CleanArchitecture.Infrastructure.Repository;
var builder = WebApplication.CreateBuilder(args);
// 将服务添加到容器中
builder.Services.AddControllers(); // 添加控制器服务
builder.Services.AddEndpointsApiExplorer(); // 探索端点
builder.Services.AddSwaggerGen(); // 添加Swagger生成服务
// 注册服务和仓库
builder.Services.AddScoped<IMovieRepository, MovieRepository>();
builder.Services.AddScoped<IMovieService, MovieService>();
var app = builder.Build();
// 配置HTTP请求管道
if (app.Environment.IsDevelopment())
{
app.UseSwagger(); // 在开发环境中使用Swagger
app.UseSwaggerUI(); // 使用Swagger UI
}
app.UseHttpsRedirection(); // 启用HTTPS重定向
app.UseAuthorization(); // 启用授权
app.MapControllers(); // 映射控制器
app.Run(); // 运行应用程序
6.2 添加控制器
在控制器文件夹中添加名为 MovieController.cs
的新控制器。
MovieController.cs
using CleanArchitecture.Application.IService;
using Microsoft.AspNetCore.Mvc;
namespace CleanArchitecture.API.Controllers
{
[Route("api/[controller]")] // 路由设置
public class MovieController : Controller
{
private readonly IMovieService _movieService; // 声明电影服务接口
// 构造函数,注入IMovieService
public MovieController(IMovieService movieService)
{
_movieService = movieService; // 初始化电影服务
}
// 获取电影列表的HTTP GET方法
[HttpGet("Get")]
public IActionResult GetMovies()
{
var movieList = _movieService.GetAllMovies(); // 获取所有电影
return Ok(movieList); // 返回成功响应和电影列表
}
}
}
五. 结论
通过以上步骤,我们成功实现了使用 .NET Core 8 的干净架构。我们了解了各个层次之间如何相互通信,并可以利用干净架构开发基于Web API或MVC的项目,以达到我们的开发目标。这种架构能够提高代码的可维护性和灵活性,适应未来的技术变化。