1. C#与.NET API编程入门指南
第一次接触C#和.NET API开发时,我被微软这套生态系统的完整性震撼到了。作为从Java转过来的开发者,我发现C#在语法糖和开发效率上确实有不少惊喜。记得最早用ASP.NET Web API做项目时,自动生成的Swagger文档让我省去了大量写接口文档的时间,这种开箱即用的体验真的很棒。
如果你正在寻找一门既能快速开发企业级应用,又具备强大性能的后端语言,C#配合.NET框架会是个不错的选择。特别是在Windows环境下,Visual Studio提供的智能提示和调试工具链,能让开发效率提升好几个档次。不过别被"微软技术"这个标签吓到,现在的.NET Core已经完美支持跨平台,在Linux服务器上跑得一样欢快。
2. 开发环境搭建与项目初始化
2.1 开发工具选择
工欲善其事必先利其器,推荐几个我实测好用的工具组合:
- Visual Studio 2022 Community:免费版完全够用,智能补全和重构功能强大到哭
- VS Code + C#插件:轻量级选择,适合喜欢简洁环境的开发者
- Rider:JetBrains出品,重构功能比VS更激进,适合大型项目
安装时记得勾选".NET桌面开发"和"ASP.NET和Web开发"工作负载。有个小技巧:如果网络环境不好,建议下载离线安装包,不然可能卡在组件下载环节。
2.2 创建第一个API项目
打开VS后:
- 选择"创建新项目" → "ASP.NET Core Web API"
- 项目模板选择时,注意取消勾选"使用控制器",我们用最小API开始
- 身份验证类型选"无",暂时不需要复杂权限控制
- 配置HTTPS和OpenAPI支持(这就是Swagger)
生成的项目结构里,重点关注:
Program.cs:所有魔法的起点appsettings.json:配置管理Properties/launchSettings.json:启动配置文件
// 最小API示例 var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();3. 核心概念深入解析
3.1 依赖注入系统
.NET的DI容器设计得非常优雅,比Spring的配置简单不少。通过builder.Services提供的各种Add方法,可以快速注册服务:
// 注册服务 builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddSingleton<ICacheService, RedisCacheService>(); // 使用服务 app.MapGet("/users", (IUserService service) => { return service.GetAllUsers(); });三种生命周期要分清:
- Transient:每次请求都新建实例
- Scoped:同一请求内共享实例(最常用)
- Singleton:全局单例
3.2 中间件管道
中间件是.NET处理请求的核心机制,执行顺序很重要:
app.UseHttpsRedirection(); app.UseAuthorization(); app.Use(async (context, next) => { // 前置逻辑 await next(); // 后置逻辑 });常见内置中间件:
UseRouting:路由匹配UseCors:跨域支持UseStaticFiles:静态文件服务UseAuthentication:认证处理
4. 实战:构建完整用户API
4.1 数据模型设计
先定义用户实体和DTO:
public record User(Guid Id, string Name, string Email); public record CreateUserDto(string Name, string Email);4.2 仓储模式实现
public interface IUserRepository { User Add(CreateUserDto user); User? GetById(Guid id); IEnumerable<User> GetAll(); } public class UserRepository : IUserRepository { private static readonly List<User> _users = new(); public User Add(CreateUserDto user) { var newUser = new User(Guid.NewGuid(), user.Name, user.Email); _users.Add(newUser); return newUser; } // 其他方法实现... }4.3 控制器与路由配置
虽然最小API很酷,但正式项目还是推荐用控制器:
[ApiController] [Route("api/[controller]")] public class UsersController : ControllerBase { private readonly IUserRepository _repository; public UsersController(IUserRepository repository) { _repository = repository; } [HttpGet] public IActionResult GetAll() { return Ok(_repository.GetAll()); } [HttpPost] public IActionResult Create(CreateUserDto dto) { var user = _repository.Add(dto); return CreatedAtAction(nameof(GetById), new { id = user.Id }, user); } }5. 异常处理与日志记录
5.1 全局异常处理
app.UseExceptionHandler(handler => { handler.Run(async context => { var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error; context.Response.StatusCode = exception switch { ArgumentException => StatusCodes.Status400BadRequest, _ => StatusCodes.Status500InternalServerError }; await context.Response.WriteAsJsonAsync(new { error = exception?.Message }); }); });5.2 结构化日志
.NET内置了强大的日志系统:
builder.Logging.AddConsole(); builder.Logging.AddDebug(); builder.Logging.AddEventLog(); // 在控制器中使用 _logger.LogInformation("Getting all users"); _logger.LogError(ex, "Error creating user");推荐搭配Serilog使用,可以输出到文件、Elasticsearch等:
builder.Host.UseSerilog((ctx, config) => { config.WriteTo.Console() .WriteTo.File("logs/log-.txt", rollingInterval: Day); });6. 性能优化技巧
6.1 响应缓存
// 启用内存缓存 builder.Services.AddMemoryCache(); // 使用缓存 app.MapGet("/users", [ResponseCache(Duration = 30)] () => { return _repository.GetAll(); });6.2 异步编程
所有IO操作都应该异步:
public interface IUserRepository { Task<User> AddAsync(CreateUserDto user); Task<User?> GetByIdAsync(Guid id); Task<IEnumerable<User>> GetAllAsync(); } [HttpGet] public async Task<IActionResult> GetAll() { var users = await _repository.GetAllAsync(); return Ok(users); }7. 测试驱动开发
7.1 单元测试
[TestClass] public class UserServiceTests { private UserService _service; private Mock<IUserRepository> _mockRepo; [TestInitialize] public void Setup() { _mockRepo = new Mock<IUserRepository>(); _service = new UserService(_mockRepo.Object); } [TestMethod] public async Task CreateUser_ShouldReturnUser_WhenInputValid() { // Arrange var dto = new CreateUserDto("Test", "test@example.com"); _mockRepo.Setup(x => x.AddAsync(It.IsAny<CreateUserDto>())) .ReturnsAsync(new User(Guid.NewGuid(), dto.Name, dto.Email)); // Act var result = await _service.CreateUserAsync(dto); // Assert Assert.AreEqual(dto.Name, result.Name); } }7.2 集成测试
[TestClass] public class UsersControllerTests { private WebApplicationFactory<Program> _factory; private HttpClient _client; [TestInitialize] public void Setup() { _factory = new WebApplicationFactory<Program>(); _client = _factory.CreateClient(); } [TestMethod] public async Task GetUsers_ShouldReturn200() { var response = await _client.GetAsync("/api/users"); Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); } }8. 部署与监控
8.1 Docker化部署
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -o /app FROM mcr.microsoft.com/dotnet/aspnet:7.0 WORKDIR /app COPY --from=build /app . ENTRYPOINT ["dotnet", "YourApi.dll"]构建命令:
docker build -t your-api . docker run -p 8080:80 your-api8.2 健康检查
builder.Services.AddHealthChecks() .AddCheck<DatabaseHealthCheck>("database"); app.MapHealthChecks("/health");9. 常见问题排查
9.1 依赖注入异常
症状:System.InvalidOperationException: Unable to resolve service for type...
解决方案:
- 检查服务是否注册(在Program.cs或Startup.cs)
- 确认生命周期匹配(Scoped服务不能在Singleton中使用)
- 确保构造函数参数是接口而非具体类
9.2 跨域问题
症状:前端请求报CORS错误
解决方案:
builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); app.UseCors("AllowAll");9.3 性能瓶颈
排查工具:
- Visual Studio诊断工具
- Application Insights
- MiniProfiler
builder.Services.AddMiniProfiler(options => { options.RouteBasePath = "/profiler"; }).AddEntityFramework(); app.UseMiniProfiler();10. 进阶路线建议
掌握基础后,可以继续深入:
- 认证授权:JWT、OAuth2、IdentityServer
- 消息队列:RabbitMQ、Azure Service Bus
- 微服务:Dapr、Orleans
- gRPC:高性能RPC框架
- Blazor:全栈C#开发
有个小技巧:多关注微软官方文档的更新,.NET团队每月都会发布新功能和改进。我在实际项目中发现,合理使用新特性(如记录类型、模式匹配)能让代码更简洁。