7天精通ASP.NET Core:RealWorld全栈实战指南
引言:你还在为ASP.NET Core实战项目发愁吗?
作为.NET开发者,你是否也曾面临这些痛点:
- 学习了框架基础知识,却不知如何构建完整项目
- 开源项目要么过于简单,要么复杂到难以入手
- 缺乏符合企业级标准的参考实现
本文将通过RealWorld示例应用(一个媲美Medium的博客平台后端),带你7天从入门到精通ASP.NET Core开发,掌握:
- 领域驱动设计(DDD)在实际项目中的应用
- CQRS模式与MediatR实现命令查询分离
- JWT认证授权完整流程
- 实体关系设计与EF Core最佳实践
- Docker容器化部署与CI/CD
项目架构全景图
技术栈概览
| 组件 | 技术选型 | 版本要求 | 核心作用 |
|---|---|---|---|
| 框架 | ASP.NET Core | 6.0+ | Web应用基础框架 |
| ORM | Entity Framework Core | 6.0+ | 数据访问层 |
| 认证 | JWT Bearer | 内置 | 用户身份验证 |
| 架构模式 | CQRS | 自定义实现 | 命令查询职责分离 |
| 消息传递 | MediatR | 12.0+ | 进程内消息传递 |
| 验证 | Fluent Validation | 11.0+ | 输入模型验证 |
| API文档 | Swagger | 6.0+ | 自动生成API文档 |
| 部署 | Docker | 20.10+ | 容器化部署 |
项目结构(Feature-based)
Conduit/
├── Domain/ # 领域模型
├── Features/ # 按功能模块组织
│ ├── Articles/ # 文章管理
│ ├── Comments/ # 评论功能
│ ├── Users/ # 用户管理
│ └── ...
├── Infrastructure/ # 基础设施
│ ├── ConduitContext.cs # EF上下文
│ └── Security/ # 安全相关
└── Program.cs # 应用入口
核心业务流程图
环境搭建:3步启动项目
1. 获取源代码
git clone https://gitcode.com/gh_mirrors/as/aspnetcore-realworld-example-app.git
cd aspnetcore-realworld-example-app
2. 本地开发环境(推荐)
# 安装.NET 6 SDK
# 启动应用
dotnet run --project src/Conduit/Conduit.csproj
3. Docker容器化部署
# 构建镜像
make build # 等价于 docker-compose build
# 启动容器
make run # 等价于 docker-compose up
访问Swagger文档:http://localhost:5000/swagger
默认数据库:SQLite(文件型数据库,无需额外配置)
核心功能实现详解
1. 领域模型设计
用户与文章关系模型
关键实体代码(Person.cs)
public class Person
{
public int PersonId { get; set; }
public string Username { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public byte[] Hash { get; set; } = Array.Empty<byte>();
public byte[] Salt { get; set; } = Array.Empty<byte>();
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
// 导航属性
public ICollection<Article> Articles { get; set; } = new List<Article>();
public ICollection<ArticleFavorite> ArticleFavorites { get; set; } = new List<ArticleFavorite>();
public ICollection<FollowedPeople> Followers { get; set; } = new List<FollowedPeople>();
public ICollection<FollowedPeople> Following { get; set; } = new List<FollowedPeople>();
}
2. 数据库上下文配置
public class ConduitContext : DbContext
{
public ConduitContext(DbContextOptions options) : base(options) { }
public DbSet<Article> Articles { get; init; } = null!;
public DbSet<Person> Persons { get; init; } = null!;
public DbSet<Tag> Tags { get; init; } = null!;
// 其他DbSet...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 多对多关系配置
modelBuilder.Entity<ArticleTag>(b =>
{
b.HasKey(t => new { t.ArticleId, t.TagId });
b.HasOne(pt => pt.Article)
.WithMany(p => p.ArticleTags)
.HasForeignKey(pt => pt.ArticleId);
b.HasOne(pt => pt.Tag)
.WithMany(t => t.ArticleTags)
.HasForeignKey(pt => pt.TagId);
});
// 关注关系配置
modelBuilder.Entity<FollowedPeople>(b =>
{
b.HasKey(t => new { t.ObserverId, t.TargetId });
b.HasOne(pt => pt.Observer)
.WithMany(p => p.Followers)
.HasForeignKey(pt => pt.ObserverId)
.OnDelete(DeleteBehavior.Restrict);
});
}
}
3. CQRS模式实现(以用户注册为例)
命令定义(Create.cs)
public record Command(UserData User) : IRequest<UserEnvelope>;
public class CommandValidator : AbstractValidator<Command>
{
public CommandValidator()
{
RuleFor(x => x.User.Username).NotNull().NotEmpty();
RuleFor(x => x.User.Email).NotNull().NotEmpty().EmailAddress();
RuleFor(x => x.User.Password).NotNull().NotEmpty().MinimumLength(8);
}
}
命令处理程序
public class Handler(
ConduitContext context,
IPasswordHasher passwordHasher,
IJwtTokenGenerator jwtTokenGenerator,
IMapper mapper
) : IRequestHandler<Command, UserEnvelope>
{
public async Task<UserEnvelope> Handle(Command message, CancellationToken cancellationToken)
{
// 检查用户名和邮箱是否已存在
if (await context.Persons.AnyAsync(x => x.Username == message.User.Username))
{
throw new RestException(HttpStatusCode.BadRequest,
new { Username = "用户名已被使用" });
}
// 创建新用户
var salt = Guid.NewGuid().ToByteArray();
var person = new Person
{
Username = message.User.Username,
Email = message.User.Email,
Hash = await passwordHasher.Hash(message.User.Password, salt),
Salt = salt
};
await context.Persons.AddAsync(person, cancellationToken);
await context.SaveChangesAsync(cancellationToken);
// 生成JWT令牌
var user = mapper.Map<Person, User>(person);
user.Token = jwtTokenGenerator.CreateToken(person.Username);
return new UserEnvelope(user);
}
}
API控制器
[Route("users")]
public class UsersController(IMediator mediator)
{
[HttpPost]
public Task<UserEnvelope> Create(
[FromBody] Create.Command command,
CancellationToken cancellationToken)
=> mediator.Send(command, cancellationToken);
}
4. 认证与授权
JWT配置(ServicesExtensions.cs)
public static void AddJwt(this IServiceCollection services)
{
var signingKey = new SymmetricSecurityKey(
"somethinglongerforthisdumbalgorithmisrequired"u8.ToArray());
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = "issuer",
ValidateAudience = true,
ValidAudience = "audience",
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
}
权限控制示例
[Authorize(AuthenticationSchemes = JwtIssuerOptions.Schemes)]
[HttpPost("{slug}/comments")]
public Task<CommentEnvelope> Create(string slug,
[FromBody] Create.Model model,
CancellationToken cancellationToken)
=> mediator.Send(new Create.Command(model, slug), cancellationToken);
错误处理机制
全局异常中间件
public class ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var result = exception switch
{
RestException re => JsonSerializer.Serialize(new { errors = re.Errors }),
_ => JsonSerializer.Serialize(new { errors = "服务器内部错误" })
};
context.Response.ContentType = "application/json";
context.Response.StatusCode = exception is RestException re ?
(int)re.Code : (int)HttpStatusCode.InternalServerError;
await context.Response.WriteAsync(result);
}
}
测试策略
集成测试示例(创建文章)
public class CreateTests : SliceFixture
{
[Fact]
public async Task Expect_Create_Article()
{
var command = new Create.Command(new Create.ArticleData
{
Title = "测试文章",
Description = "这是一篇测试文章",
Body = "测试文章内容",
TagList = new[] { "测试", "ASP.NET Core" }
});
var article = await ArticleHelpers.CreateArticle(this, command);
Assert.NotNull(article);
Assert.Equal(command.Article.Title, article.Title);
Assert.Equal(2, article.TagList.Count());
}
}
部署指南
Docker Compose配置
services:
conduit:
build: .
environment:
- ASPNETCORE_Conduit_DatabaseProvider=sqlite
- ASPNETCORE_Conduit_ConnectionString=Filename=realworld.db
ports:
- "8080:8080"
部署步骤
- 准备环境变量配置文件
- 构建Docker镜像:
docker-compose build - 启动服务:
docker-compose up -d - 数据库迁移:
docker-compose exec conduit dotnet ef database update - 健康检查:访问 http://localhost:8080/swagger
进阶实践:性能优化与扩展
1. 数据访问优化
- 使用异步查询:
await context.Articles.FirstOrDefaultAsync() - 合理使用Include和ThenInclude加载关联数据
- 实现数据分页:
Skip((page-1)*pageSize).Take(pageSize)
2. 缓存策略
// 添加分布式缓存
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "Conduit:";
});
// 使用缓存示例
[HttpGet("popular")]
public async Task<IActionResult> GetPopularTags(
[FromServices] IDistributedCache cache)
{
var cacheKey = "popular_tags";
var cachedTags = await cache.GetStringAsync(cacheKey);
if (cachedTags != null)
{
return Ok(JsonSerializer.Deserialize<TagsEnvelope>(cachedTags));
}
var tags = await _mediator.Send(new List.Query());
await cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(tags),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) });
return Ok(tags);
}
总结与展望
通过本教程,你已经掌握了使用ASP.NET Core构建企业级RESTful API的核心技能,包括:
- 基于Feature的项目结构设计
- CQRS与MediatR实现业务逻辑分离
- 领域驱动设计在实际项目中的应用
- JWT认证授权完整流程
- Docker容器化部署
后续学习路径
- 实现API版本控制
- 添加请求限流中间件
- 集成ELK日志收集
- 实现分布式事务
- 构建CI/CD流水线
项目改进建议
- 替换SQLite为PostgreSQL提高性能
- 添加Redis缓存热门文章和标签
- 实现全文搜索功能
- 添加API监控和告警
希望本教程能帮助你更好地理解和应用ASP.NET Core技术栈。如果你有任何问题或建议,欢迎在评论区留言讨论!
点赞 + 收藏 + 关注,获取更多ASP.NET Core实战教程!下期预告:《ASP.NET Core微服务架构设计与实现》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



