2014 年,Microsoft 宣布他们打算发布已经流行的 .NET Framework 的开源继任者:.NET Core。这是一项重大举措,不久之后,.NET 源代码在 GitHub 上发布。宣布 .NET Core 将成为 .NET 所有未来版本的基础,并由 .NET 基金会指导进行开源贡献。
.NET Core 取得了重大成功。随着 2020 年 .NET 5 的发布,.NET Framework 和 .NET Core 合并为单一的开源跨平台技术。
向开源的转变围绕 .NET 平台培养了一个蓬勃发展的社区。许多有才华的人为该平台发布了高质量的工具和库,这些工具和库每天都使开发人员的生活更轻松。
我是开源的坚定支持者,更是反对不重新发明轮子。在这篇文章中,我将概述 4 个绝对最好的库,我根本离不开。大多数时候,我通过安装这些来开始任何新项目。
传统上,在 .NET 中处理 HTTP 请求需要大量的手动代码和样板代码。开发人员必须手动处理构造 HTTP 请求、处理标头、管理响应和执行反序列化等细节。
这通常是通过 HttpClient 类的某种自定义实现来完成的:
public class Program
{
private static readonly HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
var user = await GetUserAsync(123);
Console.WriteLine($"User Name: {user.Name}");
}
private static async Task<User> GetUserAsync(int userId)
{
// Set the base address and default headers if needed
client.BaseAddress = new Uri("https://api.example.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Make the HTTP request
var response = await client.GetAsync($"users/{userId}");
response.EnsureSuccessStatusCode(); // Throws if not 200-299
// Deserialize the response body
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject\<User>(responseBody);
}
}
它可能很麻烦、重复且难以阅读。
取而代之的是,Refit 通过将您的 REST API 转换为实时接口来为您处理所有这些。
只需定义您的接口:
public interface IMyApi
{
[Get("/users/{userId}")]
Task<User> GetUserAsync(int userId);
}
将服务注入到您需要的任何位置,并使用它来发出 HTTP 请求。
public class UsersController : ControllerBase
{
private readonly IMyApi _myApi;
public UsersController(IMyApi myApi)
{
_myApi = myApi;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _myApi.GetUserAsync(id);
return Ok(user);
}
}
在引擎盖下,Refit 将使用所有最佳实践和标准为您搭建必要的代码。您需要做的就是定义接口,其余的都会得到处理。
您的所有 HTTP 调用都被分离到简化的、可维护的部分中,避免了样板代码。系统会为您处理序列化和反序列化,并且会为您检查 API 调用的编译时类型。这意味着您可以及早发现潜在错误,从而在运行时避免它们。Refit 还具有高度可定制性,可以轻松定制以处理自定义标题、参数等。
Coravel 是一个优秀的库,它使繁重的任务,如调度、排队、缓存、后台作业和事件广播变得非常简单和直观。Coravel是一个庞大的图书馆,处理许多不同的领域。
具体来说,我喜欢使用它的调度功能。您很少构建不必处理某种重复性任务的系统。也许您必须每小时将数据卸载到第三方系统一次,或者您必须每晚凌晨 12 点进行数据库备份。Coravel 提供了一种接近零的配置方法来处理此类任务,并且比主要云提供商提供的解决方案更易于维护。
只需定义一个继承自 IInvocable 接口的任务。Coravel 中的可调用项仅表示 Coravel 可以在应用程序的不同部分使用的特定任务。在这里,您可以放置要按计划运行的实际业务逻辑。
using Coravel.Invocable;
using System;
using System.Threading.Tasks;
public class MyScheduledTask : IInvocable
{
public Task Invoke()
{
// Your logic here
Console.WriteLine($"Executing scheduled task at: {DateTime.Now}");
return;
}
}
现在,只需在您的Program.cs中注册Coravel调度器服务,并指定您希望任务运行的时间和频率。
using Coravel;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add Coravel services
builder.Services.AddScheduler();
// Register the invocable task
builder.Services.AddTransient<MyScheduledTask>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
// Schedule the invocable task
var provider = app.Services;
provider.UseScheduler(scheduler =>
{
scheduler.Schedul\<MyScheduledTask>().EveryMinute();
});
app.Run();
大功告成。在幕后,Coravel 将搭建脚手架并处理按计划运行任务所需的代码。它可以设置为完全按照您所需的时间间隔运行,如果您愿意,甚至可以接受 CRON 表达式。
请务必在 Github 上为 Coravel 加星标。
FluentValidation 是一个常用的 .NET 库,它简化了在 .NET 应用程序中定义和执行验证规则的过程。传统上,.NET 中的数据验证是一项繁重的任务,需要您使用自定义逻辑或不灵活的数据注释来增加类。
取而代之的是,FluentValidation 允许开发人员通过提供一个接口来促进可定制的验证实现,从而摆脱必须编写验证逻辑的担忧。FluentValidation 的界面允许您以与自然语言非常相似的方式定义验证规则,而无需编写冗长且重复的验证代码,这些代码很快就会变得难以管理。这极大地提高了代码的可读性,并使未来的开发人员更容易理解和维护。
首先定义一个继承自 AbstractValidator 的类,然后使用 RuleFor 方法定义验证规则。
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Name)
.NotEmpty().WithMessage("Name is required.");
RuleFor(customer => customer.Age)
.InclusiveBetween(18, 60).WithMessage("Age must be between 18 and 60.");
RuleFor(customer => customer.Email)
.EmailAddress().WithMessage("Invalid email address.");
}
}
FluentValidation 附带了许多方便的预定义验证方法,例如 .EmailAddress()、.NotEmpty()、.GreaterThan() 和 .CreditCard(),但也可以处理您自己的自定义验证逻辑
定义后,CustomerValidator 可用于在必要时验证任何客户对象。
var customer = new Customer { Name = "", Age = 25, Email = "invalid-email" };
var validator = new CustomerValidator();
var result = validator.Validate(customer);
if (!result.IsValid)
{
foreach (var failure in result.Errors)
{
Console.WriteLine($"Property {failure.PropertyName} failed validation. Error: {failure.ErrorMessage}");
}
}
Polly 是一个流行的弹性和故障处理库,可以显着提高应用程序的鲁棒性。它允许开发人员定义不同的策略,以促进重试逻辑、熔断、超时、隔板隔离和回退,从而提高软件的可靠性。
在编写软件时,不可避免地会发生异常和临时错误。例如,您的程序在其生命周期内的某个时刻将不可避免地遇到网络超时。如果没有一种优雅的方法来处理这些情况,应用程序的关键业务方面可能会受到影响。这就是波莉的闪光点。polly 中的策略是高度模块化的,可以进行组合以解决最复杂的错误处理方案。
例如,您可以将重试策略与熔断机制和回退策略相结合,以创建可靠的故障处理策略。
假设您有一个从外部 API 获取数据的服务,并且您希望使此调用能够灵活应对暂时性故障:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Polly;
using Polly.CircuitBreaker;
using Polly.Fallback;
using Polly.Retry;
class Program
{
static async Task Main(string[] args)
{
// Define the retry policy
var retryPolicy = Policy
.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
// Define the circuit breaker policy
var circuitBreakerPolicy = Policy
.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.CircuitBreakerAsync(3, TimeSpan.FromSeconds(30));
// Define the fallback policy
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<BrokenCircuitException>()
.OrResult(r => !r.IsSuccessStatusCode)
.FallbackAsync(
new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent("{\"message\": \"Fallback response\"}")
},
onFallbackAsync: async b =>
{
Console.WriteLine("Executing fallback logic...");
});
// Combine the policies
var combinedPolicy = fallbackPolicy.WrapAsync(circuitBreakerPolicy).WrapAsync(retryPolicy);
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://external-api.com/data");
try
{
// Execute the request with the combined policy
HttpResponseMessage response = await combinedPolicy.ExecuteAsync(() => httpClient.SendAsync(request));
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Request succeeded!");
// Process the response
string data = await response.Content.ReadAsStringAsync();
Console.WriteLine(data);
}
else
{
Console.WriteLine("Request failed with status code: " + response.StatusCode);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred: " + ex.Message);
}
}
}
}
我们首先定义我们需要的三个策略;重试策略、熔断策略和回退策略。
如果遇到不成功的状态代码,重试策略将尝试重试失败的 HTTP 请求最多三次。重试采用指数退避策略进行间隔,这意味着重试之间的时间越多,操作失败的次数越多,重试之间的时间就越长。
熔断机制策略的工作原理是在连续三次尝试失败后停止执行。一旦发生这种情况,30 秒内将不再尝试,让系统有机会恢复,然后再试一次。