你已经告别了"Hello World"阶段,能比泡方便面还快地搭建API,但总觉得哪里不对劲...仿佛每次生产环境出问题(本地却正常)时,框架都在无声地嘲笑你。是的,是时候升级了。
DI帮你写出可测试、可维护、低耦合的代码。它还能防止服务之间像离不开充电器的朋友那样紧密依赖。
.NET依赖注入:该用内置DI还是自研? 有没有在Startup.cs配置服务时,两小时后发现自己深陷作用域不匹配和内存泄漏的泥潭... levelup.gitconnected.com
想象雇佣自带工具的水管工 vs 需要你现买工具的。后者就是紧耦合代码。别做那种人。
步骤1:创建服务接口与实现
public interface IGreetingService
{
string GetGreeting(string name);
}
public class GreetingService : IGreetingService
{
public string GetGreeting(string name)
{
return $"你好, {name}! 祝你编码高效。";
}
}
步骤2:在Program.cs注册服务
builder.Services.AddScoped<IGreetingService, GreetingService>();
步骤3:在控制器中注入使用
public class HomeController : Controller
{
private readonly IGreetingService _greetingService;
public HomeController(IGreetingService greetingService)
{
_greetingService = greetingService;
}
public IActionResult Index()
{
var message = _greetingService.GetGreeting("开发者");
return Content(message);
}
}
现在这个控制器不关心谁提供问候语,实现了松耦合和可测试性。
自定义中间件(RequestLoggerMiddleware.cs):
public class RequestLoggerMiddleware
{
private readonly RequestDelegate _next;
public RequestLoggerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"[请求] {context.Request.Method} {context.Request.Path}");
await _next(context);
Console.WriteLine($"[响应] {context.Response.StatusCode}");
}
}
在Program.cs注册:
app.UseMiddleware<RequestLoggerMiddleware>();
关键工具:
你会把ATM密码写在银行卡上吗?那为何要用明文存数据库密码?
步骤1:appsettings.json
{
"MyAppSettings": {
"SupportEmail": "support@yourapp.com"
}
}
步骤2:创建强类型类
public class MyAppSettings
{
public string SupportEmail { get; set; }
}
步骤3:绑定并注入
// Program.cs
builder.Services.Configure<MyAppSettings>(
builder.Configuration.GetSection("MyAppSettings"));
模拟异步调用的服务:
public interface IJokeService
{
Task<string> GetRandomJokeAsync();
}
public class JokeService : IJokeService
{
public async Task<string> GetRandomJokeAsync()
{
await Task.Delay(1000); // 模拟I/O延迟
return "为什么程序员喜欢黑暗模式?因为光亮会吸引bug!";
}
}
实体模型:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsAvailable { get; set; }
}
DbContext:
public class AppDbContext : DbContext
{
public DbSet<Book> Books { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public void PlaceOrder(int userId)
{
_logger.LogInformation("正在为用户{UserId}下单,时间:{Time}", userId, DateTime.UtcNow);
// ...
}
}
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/weather/{city}", (string city, IWeatherService weatherService) =>
{
var forecast = weatherService.GetForecast(city);
return Results.Ok(forecast);
});
app.Run();
public class EmailReminderService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new { message = "出错了" });
});
});
public decimal GetUsdToInrRate()
{
return _cache.GetOrCreate("USD_INR_RATE", entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
return 83.50m;
});
}
总结:现在怎么做? 这10个概念只是冰山一角。要真正掌握它们:
因为会写.AddScoped()是一回事,而理解其作用域原理、使用场景及对内存性能的影响——这才是精通的开始。
继续构建,继续突破,持续学习。如果本文有帮助,分享给还在硬编码配置密钥的同事吧——他们正需要这个。