.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]属性,甚至更多:当您使用身份验证功能时,一些用户身份对象也会自动注入。

.Net 6 带来改进

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();

.Net 6 带来改进

通过 REST 快速轻松地公开 protobuf 文件

原文地址:https://anthonygiretti.com/2021/08/27/asp-net-core-6-minimal-apis-two-reasons-why-i-cant-do-without-it-so-far/

我的 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

.Net 6 带来改进

上一篇:无法将类 XXX中的构造器 XXX应用到给定类型


下一篇:Natasha 4.0 探索之路系列(四) 模板 API