.Net 6 带来改进
介绍
本节.net 6的文章是我阅读国外大佬文章后的自己一个总结
正文
在ASP.NET Core 6 mininum 中,路由到代码的端点可以使用新的静态类Results轻松管理 HTTP 状态。
它还可以管理多种结果,例如 Json、File、Text 等。所有这些方法都返回一个IResult ,这是来自Microsoft.AspNetCore.Http 程序集 6.0.0.0的 Results 静态类签名。
另注意看下面的IHelloService和ClaimsPrincipal,最小 API 中的依赖注入,服务不再需要注入[FromService]属性,甚至更多:当您使用身份验证功能时,一些用户身份对象也会自动注入。
public interface IHelloService
{
string Hello(ClaimsPrincipal user, bool isHappy);
}
public class HelloService : IHelloService
{
public string Hello(ClaimsPrincipal user, bool isHappy)
{
var hello = $"Hello {user.Identity.Name}";
if (isHappy)
return $"{hello}, you seem to be happy today";
return hello;
}
}
app.MapGet("/Hello", (bool? isHappy, IHelloService service, ClaimsPrincipal user) =>
{
if (isHappy is null)
return Results.BadRequest("Please tell if you are happy or not :-)");
return Results.Ok(service.Hello(user, (bool)isHappy));
}).RequireAuthorization();
通过 REST 快速轻松地公开 protobuf 文件
我的 gRPC 项目中没有一个不能使用暴露的 protobufs 文件和最少的 API,它非常好用!以下服务用于列出 protobuf 文件及其版本、下载 protobuf 文件或在浏览器中显示 protobuf 文件的内容
namespace CountryService.gRPC.Services;
public class ProtoService
{
private readonly string _baseDirectory;
public ProtoService(IWebHostEnvironment webHost)
{
_baseDirectory = webHost.ContentRootPath;
}
public Dictionary<string, IEnumerable<string>> GetAll()
{
return Directory.GetDirectories($"{_baseDirectory}/protos")
.Select(x => new { version = x, protos = Directory.GetFiles(x).Select(Path.GetFileName) })
.ToDictionary(o => Path.GetRelativePath("protos", o.version), o => o.protos);
}
public string Get(int version, string protoName)
{
var filePath = $"{_baseDirectory}/protos/v{version}/{protoName}";
var exist = File.Exists(filePath);
return exist ? filePath : null;
}
public async Task<string> ViewAsync(int version, string protoName)
{
var filePath = $"{_baseDirectory}/protos/v{version}/{protoName}";
var exist = File.Exists(filePath);
return exist ? await File.ReadAllTextAsync(filePath) : string.Empty;
}
}
然后,通过依赖注入,我可以在最小端点上轻松地公开它们:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddGrpc(options => {
options.EnableDetailedErrors = true;
options.IgnoreUnknownServices = true;
options.MaxReceiveMessageSize = 6291456; // 6 MB
options.MaxSendMessageSize = 6291456; // 6 MB
options.CompressionProviders = new List<ICompressionProvider>
{
new BrotliCompressionProvider() // br
};
options.ResponseCompressionAlgorithm = "br"; // grpc-accept-encoding
options.ResponseCompressionLevel = CompressionLevel.Optimal; // compression level used if not set on the provider
options.Interceptors.Add<ExceptionInterceptor>(); // Register custom ExceptionInterceptor interceptor
});
builder.Services.AddGrpcReflection();
builder.Services.AddScoped<ICountryRepository, CountryRepository>();
builder.Services.AddScoped<ICountryServices, CountryServices>();
builder.Services.AddSingleton<ProtoService>();
builder.Services.AddDbContext<CountryContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("CountryService")));
var app = builder.Build();
app.MapGrpcReflectionService();
app.MapGrpcService<CountryGrpcService>();
app.MapGet("/protos", (ProtoService protoService) =>
{
return Results.Ok(protoService.GetAll());
});
app.MapGet("/protos/v{version:int}/{protoName}", (ProtoService protoService, int version, string protoName) =>
{
var filePath = protoService.Get(version, protoName);
if (filePath != null)
return Results.File(filePath);
return Results.NotFound();
});
app.MapGet("/protos/v{version:int}/{protoName}/view", async (ProtoService protoService, int version, string protoName) =>
{
var text = await protoService.ViewAsync(version, protoName);
if (!string.IsNullOrEmpty(text))
return Results.Text(text);
return Results.NotFound();
});
// Custom response handling over ASP.NET Core middleware
app.Use(async (context, next) =>
{
if (!context.Request.Path.Value.Contains("protos/v"))
{
context.Response.ContentType = "application/grpc";
context.Response.Headers.Add("grpc-status", ((int)StatusCode.NotFound).ToString());
}
await next();
});
// Run the app
app.Run();
我最喜欢的是静态结果类的效率。使用该类,我可以使用Ok()方法轻松公开 json 数据,使用Text()方法公开文件内容或使用File()方法提供文件下载。
使用File()方法的示例,我可以通过 Visual Studio 2022 中的 Connected Services mnu 导入 protobuf:
小技巧
谁不喜欢 Entity Framework Core?我喜欢。你知道我也喜欢它吗?为了能够快速测试我的 dbContext 是否配置正确,突然我想快速测试是否使用DbSet可以向数据库发出请求,你永远不知道我可能做错了什么?那么最小的 API,仍然通过依赖注入,允许我注入我的Dbcontext并测试一个 LINQ 请求,看看一切是否正常:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<CountryContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("CountryService")));
var app = builder.Build();
app.MapGet("/countries", (CountryContext dbContext) =>
{
return Results.Ok(dbContext.Countries.Select(x => new
{
x.Name,
x.Description,
x.CapitalCity,
x.Anthem,
SpokenLagnuages = x.CountryLanguages.Select(y => y.Language.Name)
}));
});
// Run the app
app.Run();
结语
联系作者:加群:867095512 @MrChuJiu