如何使用 .NET Core 8 构建干净架构的 Web API

发布:2024-09-27 11:35 阅读:72 点赞:0

一. 引言

在软件开发中,干净架构是一种设计方法,旨在确保应用程序的代码结构清晰、有序、易于维护和适应变化。它的核心原则是将业务逻辑与外部依赖(如框架和用户界面)分离,从而在不影响核心系统的情况下,便于更新和扩展。

干净架构的主要目标是创建一个结构,使业务逻辑独立,从而减少更改对核心系统的影响。这意味着您可以替换或修改框架、数据库或UI组件,而无需重写核心代码。通过将依赖项保持为外部和可替换的,您可以创建一个灵活、持久的应用架构,经受时间的考验。

本文将引导您逐步实现 .NET Core 8 中的干净架构,确保您的应用程序建立在坚实、可扩展的原则上。

二. 什么是干净架构?

干净架构是一种软件设计模式,将代码组织为不同的层次,确保关注点的清晰分离。其主要目标是使应用程序更易于维护、测试和适应变化。干净架构将核心业务逻辑与外部依赖(如数据库、框架和用户界面)隔离开来。

在干净架构中,代码分为四个关键层次:

  1. 领域层(Domain Layer):包含核心业务逻辑和实体。该层完全独立于外部技术。
  2. 应用层(Application Layer):管理用例并与领域层交互以执行业务操作。
  3. 基础设施层(Infrastructure Layer):处理外部关注点,例如数据库、API和文件系统。它实现了仓库模式,以分离数据访问逻辑。
  4. 表示层(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 { getset; } // 电影ID属性
        public string Name { getset; } = string.Empty; // 电影名称属性
        public int Cost { getset; } // 电影成本属性
    }
}

步骤 4: 创建应用层项目

接下来,创建一个名为 CleanArchitectureDemo.Application 的类库项目。应用层包含业务逻辑。

4.1 创建文件夹

创建三个文件夹:IServiceService 和 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的项目,以达到我们的开发目标。这种架构能够提高代码的可维护性和灵活性,适应未来的技术变化。