news 2026/9/8 6:03:43

.NET 10 Web API集成Clean Architecture与EF Core的AI实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET 10 Web API集成Clean Architecture与EF Core的AI实践指南

最近很多人在跟 .NET 10 Web API 的全套课程,方向是 Clean Architecture、EF Core,再加上 AI 能力接入。这套组合最值得关注的不是某个单点技术,而是把架构设计、数据持久化和 AI 服务串成一条完整链路的思路。适合正在做 .NET 后端开发、想从单体 Controller 堆代码转向分层架构,或者想给现有 Web API 接入大模型能力的开发者。下面按我实际跑完一轮 Demo 后的经验,把环境、分层、EF Core、AI 接入和踩坑点完整拆一遍。

1. 这类全栈课程真正值得学的东西,是把架构和 AI 组合成一条可落地的链路

很多人看到“Clean Architecture + EF Core + AI”第一反应是知识点太多,不知道该从哪入手。实际上这套组合的核心不是让你背分层理论,而是帮你解决一个非常具体的问题:当 Web API 开始接入 AI 能力时,代码结构怎么组织才不会乱。

1.1 为什么 Clean Architecture 在这里是基础

如果只是写一个简单的接口,Controller 里直接写业务逻辑也能跑。但一旦项目里同时存在数据库访问、第三方 AI 服务调用、请求参数校验、日志记录,Controller 就会越来越臃肿。Clean Architecture 的做法是把系统按依赖方向分层:Domain 放核心业务,Application 放用例逻辑,Infrastructure 放数据库和外部服务,WebAPI 只负责接收请求和返回响应。

这样做的好处是,AI 服务或者数据库实现未来都可以替换,业务层不需要跟着改。课程里把这一点作为主线,后面的 EF Core 和 AI 集成都是在为这条主线服务。

1.2 EF Core 和 AI 在这条链路里分别承担什么

EF Core 解决的是数据持久化问题。在 Clean Architecture 里,DbContext、实体映射、迁移脚本都属于 Infrastructure 层,Application 层只依赖抽象的仓储接口或查询接口。

AI 部分则分成两个维度:

  • 开发过程中用 Copilot Agent 辅助写代码、测试、查报错;
  • 业务功能中通过接口接入 Gemini 这类大模型服务。

这两个维度不能混为一谈。Copilot Agent 是开发工具,不进入运行时;Gemini 服务调用则是业务代码的一部分,需要按依赖方向封装。把这两件事分开,整条链路才清晰。

2. 环境准备:先把开发链跑通,再谈分层和 AI

我建议先把本地环境准备好,不要一上来就建解决方案。环境问题不解决,后面每一步都会卡。

2.1 开发机需要准备什么

最低配置和推荐配置可以看下面这张表:

项目最低要求推荐配置
操作系统Windows 10 / 11,或 macOS 13+同左
.NET SDK.NET 10 SDK.NET 10 SDK + 最新补丁
IDEVisual Studio 2022 或 VS CodeVisual Studio 2022 或 Rider
数据库SQL Server LocalDBSQL Server / PostgreSQL / SQLite
内存8 GB16 GB 以上
网络能访问 NuGet 和 AI 服务稳定网络,避免超时

这里有个细节:.NET 10 的某些功能在旧版 SDK 里没有,比如新增的 API 模板选项和默认配置行为。如果你用的是预览版或者刚发布的正式版,一定要确认 SDK 版本和 NuGet 包版本匹配。原始课程材料没有给出具体版本号,所以落地时先跑一次dotnet --info确认环境。

2.2 用命令行建出解决方案结构

我习惯用命令行创建项目,比在 IDE 里点模板更快,也更清楚每个项目的依赖关系。

dotnet new sln -n CleanArchDemo dotnet new webapi -n CleanArchDemo.WebApi dotnet new classlib -n CleanArchDemo.Domain dotnet new classlib -n CleanArchDemo.Application dotnet new classlib -n CleanArchDemo.Infrastructure dotnet sln add CleanArchDemo.WebApi CleanArchDemo.Domain CleanArchDemo.Application CleanArchDemo.Infrastructure

这里要注意,.NET 10 的 Web API 模板默认会包含一些最小 API 示例和天气接口。建完项目后先把示例代码删掉,再开始写自己的代码,避免后面测试时被默认接口干扰。

2.3 项目引用关系是分层架构的关键

只建项目不设引用,等于没有分层。Clean Architecture 的核心是依赖方向必须从外向内:

cd CleanArchDemo.WebApi dotnet add reference ../CleanArchDemo.Application dotnet add reference ../CleanArchDemo.Infrastructure cd ../CleanArchDemo.Application dotnet add reference ../CleanArchDemo.Domain cd ../CleanArchDemo.Infrastructure dotnet add reference ../CleanArchDemo.Application dotnet add reference ../CleanArchDemo.Domain

注意 WebApi 层可以同时引用 Application 和 Infrastructure,因为启动项目本身负责组装依赖注入。但 Application 层不能引用 Infrastructure 层,这是最容易搞反的地方。如果项目里有“循环依赖”的报错,先检查是不是引用方向错了。

3. Clean Architecture 分层:谁该放哪,依赖方向怎么控制

分层不是把文件放进不同文件夹就完事了,而是要让每一层只依赖它下面那层。下面按实际项目里的常见划分拆开说。

3.1 Domain 层只放核心业务实体

Domain 层在四个项目里处于最中心,它不应该引用任何其他项目。这里放的是业务实体和核心业务规则,比如订单、产品、用户这类概念,以及它们自身的行为。

namespace CleanArchDemo.Domain.Entities; public class Product { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public decimal Price { get; set; } public DateTime CreatedAt { get; set; } = DateTime.UtcNow; }

在这个示例里,Product 只是一个简单的实体。实际项目中,领域实体可能包含状态流转、业务校验、事件发布等逻辑。关键判断标准是:这个对象不依赖数据库、不依赖框架、不依赖外部服务,它能独立存在。

3.2 Application 层处理用例

Application 层是业务用例的编排层。它定义接口,不关心接口怎么实现。比如要做一个“根据提示词生成内容”的功能,Application 层先定义一个IAiService接口,再定义一个用例类去调用这个接口。

using CleanArchDemo.Domain.Entities; namespace CleanArchDemo.Application.Interfaces; public interface IAiService { Task<string> CompleteAsync(string prompt, CancellationToken cancellationToken); }
using CleanArchDemo.Application.Interfaces; namespace CleanArchDemo.Application.UseCases; public class GenerateContentUseCase { private readonly IAiService _aiService; public GenerateContentUseCase(IAiService aiService) { _aiService = aiService; } public async Task<string> ExecuteAsync(string prompt, CancellationToken cancellationToken) { return await _aiService.CompleteAsync(prompt, cancellationToken); } }

为什么要这样做?因为控制反转之后,测试时可以替换成 Mock,未来换服务商时也不需要改业务代码。

3.3 Infrastructure 层放 EF Core 和外部服务

Infrastructure 层负责把 Application 层定义的接口变成实现。EF Core 的DbContext、实体配置、仓储实现、AI 服务的具体调用都放在这里。

这一层是整个架构里代码量最多的部分,也是最容易出现依赖混乱的地方。记住一个原则:Infrastructure 可以引用 Application 和 Domain,但 Application 永远不能引用 Infrastructure。

3.4 WebAPI 层只是入口

WebAPI 层包含 Controller、Program.cs、中间件和依赖注入注册。Controller 的逻辑应该尽可能薄,只做三件事:接收参数、调用 Application 层的用例、返回结果。

using CleanArchDemo.Application.UseCases; using Microsoft.AspNetCore.Mvc; namespace CleanArchDemo.WebApi.Controllers; [ApiController] [Route("api/[controller]")] public class AiController : ControllerBase { private readonly GenerateContentUseCase _useCase; public AiController(GenerateContentUseCase useCase) { _useCase = useCase; } [HttpPost("generate")] public async Task<IActionResult> Generate([FromBody] GenerateRequest request, CancellationToken cancellationToken) { var result = await _useCase.ExecuteAsync(request.Prompt, cancellationToken); return Ok(new { Result = result }); } }

如果 Controller 里出现了数据库直接调用、AI 客户端实例化、日志手写拼接这些代码,说明分层已经失效了。

4. EF Core 在 Clean Architecture 中的实践

EF Core 本身不难,难的是放在哪、怎么迁移、仓储要不要包一层。这部分我多说几句。

4.1 DbContext 放在 Infrastructure 还是 Persistence

很多模板会单独建一个 Persistence 项目,把 DbContext 放进去。这个方案可以,但对大多数项目来说没有必要。直接在 Infrastructure 下建一个Persistence文件夹,里面放AppDbContext和实体配置就够了。项目多了反而增加维护成本。

using CleanArchDemo.Domain.Entities; using Microsoft.EntityFrameworkCore; namespace CleanArchDemo.Infrastructure.Persistence; public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<Product> Products => Set<Product>(); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly); base.OnModelCreating(modelBuilder); } }

ApplyConfigurationsFromAssembly会自动加载当前程序集里所有的IEntityTypeConfiguration实现,不用逐个注册,省事很多。

4.2 迁移操作的顺序

迁移是 EF Core 里比较容易出错的环节。主要是顺序问题。先安装工具,再添加迁移,最后更新数据库:

dotnet tool install --global dotnet-ef dotnet ef migrations add InitialCreate --project CleanArchDemo.Infrastructure --startup-project CleanArchDemo.WebApi dotnet ef database update --project CleanArchDemo.Infrastructure --startup-project CleanArchDemo.WebApi

这里最容易踩的坑是:不指定--project--startup-project,工具默认在当前目录找项目,结果要么报“没有找到 DbContext”,要么把迁移生成到了错误的项目。如果报错说找不到连接字符串,多半是startup-project没指向 WebApi 项目,因为连接字符串一般配置在启动项目里。

4.3 Repository 要不要包一层

关于 Repository 模式,我的建议是:简单查询不要包。直接用DbContext或者IDbContextFactory反而更清晰。EF Core 本身就是 UnitOfWork 和数据访问抽象的集合体,再包一层透明的 Repository 只会增加代码量,却没有带来实际好处。

什么时候才需要 Repository?当你有多个持久化方案需要切换,或者在测试中需要大量模拟数据访问层时,才值得包一层接口。如果只是做普通的 CRUD,Application 层通过构造函数注入AppDbContext或者一个更具体的仓储接口就够了。

有一个边界要注意:EF Core 支持不等于所有查询性能都好。比如连表查询、嵌套 Include、分页大表、N+1 查询,这些都需要单独检查生成的 SQL。不能因为框架帮你做了,就忽略查询效率。

5. AI 能力接入:Copilot Agent 在开发中的角色,以及 Gemini 的集成方式

这个课程的标题里有 Copilot Agent,又出现了 Gem,实际落地时通常就是两个方向:用 Copilot Agent 辅助开发,以及接入 Gemini 一类大模型服务。下面分别说。

5.1 Copilot Agent 是开发助手,不是业务组件

Copilot Agent 解决的问题是在写代码、查报错、补测试时减少重复劳动。比如我建完项目后会让它帮我生成一个符合 Clean Architecture 的 Product CRUD 例子,它能在几秒内给出 Domain、Application、Infrastructure 三层的基础代码。

但它不能替代你做架构决策。Agent 生成的代码经常只是“能用”,不一定符合你项目的具体规则。比如它会默认把业务校验写在 Controller 里,或者在 Application 层直接用 EF Core,这些都需要你按分层原则手动修正。我一般会让它先生成,再按架构规则逐层检查。

5.2 在 Application 层定义 AI 服务接口

接入 Gemini 这类模型时,先在 Application 层定义接口,然后在 Infrastructure 层实现真实请求。上面第 3 节里已经写了IAiService接口,下面看具体实现。

5.3 Infrastructure 层实现 Gemini 调用

using System.Net.Http.Json; using CleanArchDemo.Application.Interfaces; namespace CleanArchDemo.Infrastructure.Services; public class GeminiAiService : IAiService { private readonly HttpClient _httpClient; private readonly string _apiKey; private readonly string _endpoint; public GeminiAiService(HttpClient httpClient, IConfiguration configuration) { _httpClient = httpClient; _apiKey = configuration["AI:ApiKey"] ?? throw new InvalidOperationException("AI:ApiKey is not configured."); _endpoint = configuration["AI:Endpoint"] ?? "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent"; } public async Task<string> CompleteAsync(string prompt, CancellationToken cancellationToken) { var request = new { contents = new[] { new { parts = new[] { new { text = prompt } } } } }; var url = $"{_endpoint}?key={_apiKey}"; var response = await _httpClient.PostAsJsonAsync(url, request, cancellationToken); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync<GeminiResponse>(cancellationToken: cancellationToken); return result?.Candidates?.FirstOrDefault()?.Content?.Parts?.FirstOrDefault()?.Text ?? string.Empty; } } public class GeminiResponse { public List<GeminiCandidate>? Candidates { get; set; } } public class GeminiCandidate { public GeminiContent? Content { get; set; } } public class GeminiContent { public List<GeminiPart>? Parts { get; set; } } public class GeminiPart { public string? Text { get; set; } }

这段代码里,API Key 从配置读取,而不是硬编码。还要用HttpClientFactory来管理 HttpClient,避免套接字耗尽。如果你要做流式输出,接口需要改成IAsyncEnumerable<string>,并在实现里处理 SSE 流。

这里最容易忽略的是超时和重试。AI 服务响应时间不稳定,单一超时配置可能不够。建议加一个重试策略,比如指数退避,同时设置合理的超时时间。具体的重试次数和超时时间要根据你的业务容忍度来定,没有统一答案。

6. 运行与验证:从单条请求到批量调用的判断标准

代码写完不是结束,能跑通并且稳定才是真正目的。这部分从最小链路开始,逐步扩展到更复杂的调用。

6.1 先跑最小链路

无论项目多复杂,第一步永远是启动 WebAPI,确认 Swagger 能打开,然后用一个最简单的接口验证。比如先调用传统的 Product 接口,再调用 AI 接口。这里有一个很实用的顺序:

  1. 启动项目,确认端口正常监听;
  2. 打开 Swagger 页面,确认接口枚举正常;
  3. 先用不带 AI 的普通接口测试数据库读写;
  4. 再测 AI 接口,输入一个短提示词,确认返回不为空。

不要一上来就测试长文本、多并发、流式输出。先把最小链路跑通,后面所有问题都更容易定位。

6.2 日志和异常处理

日志是整个链路里最容易被低估的部分。没有日志,你只能靠猜。建议在 Program.cs 里配置结构化日志,并且在 AI 服务实现里记录请求耗时和状态码。

builder.Services.AddHttpClient<GeminiAiService>(client => { client.Timeout = TimeSpan.FromSeconds(60); });

在业务代码里,对 AI 服务的异常要单独处理。网络超时、API Key 失效、模型返回空内容、输入被内容审核拦截,这些都是不同的错误,不能混在一个 catch 里。

6.3 超时、并发、输出完整性

判断 AI 接口是否稳定,不能只看一次调用是否成功。我建议关注这几个指标:

指标判断标准排查方向
单次耗时普通短文本应在 5 到 30 秒内网络、模型大小、请求内容长度
成功率连续 20 次调用,失败次数应为 0API Key、超时、限流
输出完整性返回内容不截断、不丢失流式处理是否正确、长度限制
并发稳定性同时 5 个请求不报错HttpClient 管理、连接池、限流

如果你要做批量调用,比如一次处理 10 条文本,不要用并行度拉满的方式。先用SemaphoreSlim限制并发数,比如 3 到 5 个,然后逐条记录结果。批量任务失败时还要考虑重试和跳过,不能因为一条失败就中断整个队列。

7. 常见踩坑和排查顺序

最后这部分是我最想写的。很多问题看起来像框架或 AI 服务的问题,实际往往是环境、配置或输入格式的问题。

7.1 编译和运行时的高频问题

先列几个容易遇到的现象和排查方向:

现象常见原因排查顺序
迁移生成到错误项目未指定--project先看命令参数,再看项目结构
连接字符串找不到配置写在非启动项目确认startup-project,确认环境变量
依赖注入报错服务未注册或生命周期不匹配看 Program.cs 注册代码,确认 AddScoped 还是 AddTransient
NuGet 包版本冲突不同项目引用了不同 EF Core 版本统一 SDK 版本和包版本
API Key 为空配置未加载或环境变量名不一致检查 appsettings.json、launchSettings.json、环境变量

这里有个常见误区:构建时通过不代表运行时没有问题。E F Core 的查询可能在编译期完全正常,但运行时因为数据库表不存在、字段类型不匹配、迁移未应用而崩溃。所以每次改动实体后,优先跑迁移,再启动项目。

7.2 AI 接口调用的排查链路

AI 接口一旦报错,很多人第一反应是“模型是不是挂了”,实际上更多的原因是请求格式、认证或网络。

我一般按这个顺序排查:

  1. 先看报错信息里的状态码。401 是 Key 问题,429 是限流,500 是服务端问题;
  2. 再检查请求体格式。Gemini 的contents结构不能写错,字段名大小写要严格;
  3. 检查网络是否能正常访问目标地址。这里只判断你的服务器和目标服务之间的连通性,不涉及任何代理工具;
  4. 检查超时配置。如果 HttpClient 的 Timeout 设置过短,长文本请求会被提前中断;
  5. 最后看返回内容。有时候请求成功但内容为空,可能是输入提示词被过滤,或者模型返回了空 parts。

如果报错信息里有SSL或证书相关字样,先确认目标机器的证书链是否完整。这类问题通常跟代码逻辑无关。

7.3 我的建议

这套课程里最值得模仿的不是某个类怎么写,而是它的组织方式和验证节奏。我们先从最小案例跑起,再逐步加深,不要让 AI 功能绑架了整个架构设计。如果你只是学习,用 SQLite 加一个短文本示例就够了;如果要上生产,就需要把日志、超时、重试、配额管理、内容格式校验都提前设计好。

踩过几次之后我发现,很多问题不是框架能力不够,而是前置环境和输入材料没有处理干净。项目引用方向错了,连接字符串没有放对位置,API Key 没有生效,这些占了排查时间的一大部分。先把这些基础环节做扎实,Clean Architecture、EF Core 和 AI 集成这套方案才能真正给你带来长期收益。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 6:03:31

前后端分离家校互联系统:Python FastAPI + Vue 3 全栈开发实战

1. 项目概述与整体构思1.1 家校互联系统到底在解决什么问题先说个场景。家里有娃上学的朋友应该都体会过&#xff0c;班级群里每天刷几百条消息&#xff0c;老师发通知、家长问作业、要接龙、要打卡&#xff0c;信息乱成一锅粥。老师这边更是头疼&#xff0c;同一个通知要发家长…

作者头像 李华
网站建设 2026/9/8 6:03:22

OpenCV单目测距实战:从相机标定到实时距离计算

简介&#xff1a;这是一份基于OpenCV与Python实现相机到物体距离测量的极简项目资源&#xff0c;面向计算机视觉初学者与需要快速实现单目测距功能的开发者。资源核心采用三角形相似度原理&#xff0c;使用前需要先标定两个关键参数——标记物体的真实宽度&#xff08;或高度&a…

作者头像 李华
网站建设 2026/9/8 6:03:21

用八种软件结构风格实现KWIC:设计图与代码实战

简介&#xff1a;一份面向软件工程学习者与开发者的KWIC系统实现资料&#xff0c;围绕管道过滤器、虚拟机、仓库、黑板、事件驱动、分层、面向对象、客户端-服务器八种软件结构风格&#xff0c;分别给出可运行的Java实现代码、设计图与要求文档&#xff0c;用于理解不同结构风格…

作者头像 李华
网站建设 2026/9/8 6:03:00

Kotlin中缀函数全解析:语法、优先级、性能与DSL实战

pairOf("id", 1001)和"id" to 1001之间&#xff0c;差的只是几个字符&#xff0c;但读起来的感受完全不一样。第一次在 Kotlin 代码里看到mapOf("name" to "kotlin")的时候&#xff0c;大多数人都会愣一下&#xff1a;这个to是关键字吗…

作者头像 李华
网站建设 2026/9/8 6:02:41

VOC格式中国交通数据集实战:4000张图片转YOLOv8训练全流程

简介&#xff1a;面向自动驾驶与智能交通研究的中国交通数据集&#xff0c;基于PASCAL VOC标准构建&#xff0c;收录4000张涵盖城市道路、高速路与乡村路等多种场景的交通图像&#xff0c;标注了车辆、行人、交通标志、道路等关键元素&#xff0c;可用于目标检测、实例分割、语…

作者头像 李华
网站建设 2026/9/8 6:02:21

自制准直驱执行器:行走机器人关节的力控与调参实战

很多开发者从机械臂、舵机或者普通电机转入行走机器人领域后&#xff0c;最先劝退自己的往往不是步态算法&#xff0c;而是最底层的关节执行器。关节空载响应很好&#xff0c;一带负载就发抖、发热&#xff0c;甚至一受冲击就扫齿&#xff0c;这类现象在四足、双足机器人项目里…

作者头像 李华