7天精通ASP.NET Core:RealWorld全栈实战指南

7天精通ASP.NET Core:RealWorld全栈实战指南

【免费下载链接】aspnetcore-realworld-example-app ASP.NET Core backend implementation for RealWorld 【免费下载链接】aspnetcore-realworld-example-app 项目地址: https://gitcode.com/gh_mirrors/as/aspnetcore-realworld-example-app

引言:你还在为ASP.NET Core实战项目发愁吗?

作为.NET开发者,你是否也曾面临这些痛点:

  • 学习了框架基础知识,却不知如何构建完整项目
  • 开源项目要么过于简单,要么复杂到难以入手
  • 缺乏符合企业级标准的参考实现

本文将通过RealWorld示例应用(一个媲美Medium的博客平台后端),带你7天从入门到精通ASP.NET Core开发,掌握:

  • 领域驱动设计(DDD)在实际项目中的应用
  • CQRS模式与MediatR实现命令查询分离
  • JWT认证授权完整流程
  • 实体关系设计与EF Core最佳实践
  • Docker容器化部署与CI/CD

项目架构全景图

技术栈概览

组件技术选型版本要求核心作用
框架ASP.NET Core6.0+Web应用基础框架
ORMEntity Framework Core6.0+数据访问层
认证JWT Bearer内置用户身份验证
架构模式CQRS自定义实现命令查询职责分离
消息传递MediatR12.0+进程内消息传递
验证Fluent Validation11.0+输入模型验证
API文档Swagger6.0+自动生成API文档
部署Docker20.10+容器化部署

项目结构(Feature-based)

Conduit/
├── Domain/            # 领域模型
├── Features/          # 按功能模块组织
│   ├── Articles/      # 文章管理
│   ├── Comments/      # 评论功能
│   ├── Users/         # 用户管理
│   └── ...
├── Infrastructure/    # 基础设施
│   ├── ConduitContext.cs  # EF上下文
│   └── Security/      # 安全相关
└── Program.cs         # 应用入口

核心业务流程图

mermaid

环境搭建: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. 领域模型设计

用户与文章关系模型

mermaid

关键实体代码(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"

部署步骤

  1. 准备环境变量配置文件
  2. 构建Docker镜像:docker-compose build
  3. 启动服务:docker-compose up -d
  4. 数据库迁移:docker-compose exec conduit dotnet ef database update
  5. 健康检查:访问 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的核心技能,包括:

  1. 基于Feature的项目结构设计
  2. CQRS与MediatR实现业务逻辑分离
  3. 领域驱动设计在实际项目中的应用
  4. JWT认证授权完整流程
  5. Docker容器化部署

后续学习路径

  1. 实现API版本控制
  2. 添加请求限流中间件
  3. 集成ELK日志收集
  4. 实现分布式事务
  5. 构建CI/CD流水线

项目改进建议

  • 替换SQLite为PostgreSQL提高性能
  • 添加Redis缓存热门文章和标签
  • 实现全文搜索功能
  • 添加API监控和告警

希望本教程能帮助你更好地理解和应用ASP.NET Core技术栈。如果你有任何问题或建议,欢迎在评论区留言讨论!

点赞 + 收藏 + 关注,获取更多ASP.NET Core实战教程!下期预告:《ASP.NET Core微服务架构设计与实现》

【免费下载链接】aspnetcore-realworld-example-app ASP.NET Core backend implementation for RealWorld 【免费下载链接】aspnetcore-realworld-example-app 项目地址: https://gitcode.com/gh_mirrors/as/aspnetcore-realworld-example-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值