.Net 7入门-初体验Minial API

751 阅读5分钟

.NET 7.NET 6 都支持 Minimal API,但是它们之间还是存在一些区别:

  1. 支持的平台:.NET 7 引入了对 Apple SiliconWindows ARM64 的原生支持,这使得 .NET 7Minimal API 可以在更广泛的平台上运行。而 .NET 6 只支持在 Windows、macOS 和 Linux 上运行。
  2. 语法特性:.NET 7Minimal API 支持一些新的语法特性,比如 top-level statements,这使得编写 Minimal API 更加简洁。而 .NET 6Minimal API 不支持这些新特性。
  3. Web API 支持:.NET 7Minimal API 支持 Web API 的构建,而 .NET 6Minimal API 主要是用来构建命令行应用程序或单独的 HTTP 端点。
  4. 性能:.NET 7 中的 Minimal API 在某些情况下比 .NET 6 更快,这主要得益于其采用了一些新的优化和性能改进。不过具体的性能优化效果还需要在具体场景中测试才能得出结论。

总之,虽然 .NET 6.NET 7 都支持 Minimal API,但它们在支持平台、语法特性、Web API 支持和性能方面都存在一些差异。开发者可以根据自己的需求和具体场景选择适合的版本来使用。

随着.Net 7发布,我们也来探索一下.Net 7。 随着.Net 7发布的同时,C# 10.0也会随之发布,在C# 10.0中为了.Net 6的发布,语言级别集成了很多新特性, 这些特性主要有:

  • Top-level statements
  • async main
  • Global using directives ( 基于SDK的隐式global using)
  • File-scoped名称空间
  • new表达式类型推断
  • 空引用类型

有了这些新特性之后, .Net 6推出了Minimal API, 那么到底什么Minimal API? 为了更快速的直观的观察他们,我们先安装.Net 6sdk, 您可以微软的网站:dotnet.microsoft.com/download/do… 来下载和安装.Net 6, 安装完成之后我们可以继续观察了。

1. Minimal API初体验

image

1928y97y2874y21873182wada

相比原来的模板生成的项目,这里的文件是相当的少:

appsettings.json appsetttings.Developments.json Program.cs

我们可以进一步的看一下Program.cs的内容:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
​
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
​
app.MapGet("/", async (context) => await context.Response.WriteAsync("hello"));
​
app.Run();

在 .NET 7 中,应该使用HttpContext对象的Response属性来创建响应。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
​
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
​
app.MapGet("/", () =>
{
    var response = app.Context.Response;
    response.ContentType = "text/plain";
    return response.WriteAsync("hello");
});
​
app.Run();

在此代码中,我们使用 app.Context.Response 来获取 HttpContext 对象的 Response 属性,并将响应类型设置为 "text/plain"。然后,我们使用 response.WriteAsync() 方法将字符串 "hello" 写入响应体中。

请注意,在这个代码中我们使用了 asyncawait 关键字,这是因为在写入响应体时需要进行异步操作。这是一种更好的编程风格,因为它允许 Web 服务器同时处理多个请求。

关于这部分代码,我们可以看到有如下的特征:

  • 应用了新的特性: top-level statement
  • .Net 6 应用了新的特性: 隐式global using
  • 没有了Startup类了。
  • 应用了新的类WebApplication
  • 应用了新的类WebApplicationBuilder

ec19c872-20b7-467a-aadf-a500e8cd378a

d7d06b0b-8db4-4ac2-a13a-77fc066f234f

43682bf5-aa93-48ff-ba48-2ebb38a61fdb

94b34e72-1722-4606-839a-84db7b8f91cd

对比较我们之前的应用模板,除了主要的新特性支持,最重要的要是WebApplication类和WebApplicationBuilder类的应用,除此之外,路由部分也和之间有所有不同,之前我们是先启用路由中间件,然后使用useEndpoint扩展方法进行映射,但是现在可以直接app.MapGet()等一系列的方法。同时可以看到我们通过WebAplicationBuilder来添加我们需要的服务,通过WebApplication的实例来启用中间件,构建管道。

除了使用模板之外,我们还是更快速的使用更小的代码来构建我们的mini应用,下面我们看看路由的用法:

var app = WebApplication.Create(args);
​
app.MapGet("/", () => "Hello World");
​
app.Run();

想监听更多的HTTP动作?

app.MapGet("/", () => "This is a GET");
app.MapPost("/", () => "This is a POST");
app.MapPut("/", () => "This is a PUT");
app.MapDelete("/", () => "This is a DELETE");
app.MapMethods("/options-or-head", new [] { "OPTIONS", "HEAD" },
() => "This is an options or head request ");
app.MapGet("/", () => "This is an inline lambda");
 
var handler = () => "This is a lambda variable";
 
app.MapGet("/", handler)

当然你可以使用任何你想使用的类型,例如:

var handler = new HelloHandler();
 
app.MapGet("/", handler.Hello);
 
class HelloHandler
{
    public string Hello() 
    {
        return "Hello World";
    }
}

你还可以处理更多的路由参数:

app.MapGet("/users/{userId}/books/{bookId}", 
(int userId, int bookId) => $"The user id is {userId} and book id is {bookId}");

路由约束在这里还是可以继续使用:

app.MapGet("/todos/{id:int}", (int id) => db.Todos.Find(id));
app.MapGet("/todos/{text}", (string text) => db.Todos.Where(t => t.Text.Contains(text));
app.MapGet("/posts/{slug:regex(^[a-z0-9_-]+$)}", (string slug) => $"Post {slug}");

同时Attributes可以明确的定义参数:

using Microsoft.AspNetCore.Mvc;
 
app.MapGet("/{id}", ([FromRoute]int id, 
                     [FromQuery(Name = "p")]int page, 
                     [FromServices]Service service, 
                     [FromHeader(Name = "Content-Type")]string contentType) => { });

自定义response:

app.MapGet("/todos/{id}", (int id, TodoDb db) => 
    db.Todos.Find(id) is Todo todo 
        ? Results.Ok(todo)
        : Results.NotFound()
);

看一个完整的文件上传的例子:

app.MapGet("/upload", async (HttpRequest req) =>
{
    if (!req.HasFormContentType)
    {
        return Results.BadRequest();
    }
 
    var form = await req.ReadFormAsync();
    var file = form.Files["file"];
 
    if (file is null)
    {
        return Results.BadRequest();
    }
 
    var uploads = Path.Combine(uploadsPath, file.FileName);
    await using var fileStream = File.OpenWrite(uploads);
    await using var uploadStream = file.OpenReadStream();
    await uploadStream.CopyToAsync(fileStream);
 
    return Results.NoContent();
})
.Accepts<IFormFile>("multipart/form-data");
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using System.Threading.Tasks;
​
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
​
var app = builder.Build();
​
app.MapPost("/upload", async (HttpContext context) =>
{
    // 检查是否有文件上传
    if (context.Request.Form.Files.Count == 0)
    {
        return Results.BadRequest("No files were uploaded.");
    }
​
    // 处理每个上传的文件
    foreach (var file in context.Request.Form.Files)
    {
        // 检查文件大小是否符合要求,例如不能大于 10MB
        if (file.Length > 10 * 1024 * 1024)
        {
            return Results.BadRequest($"The file {file.FileName} is too large.");
        }
​
        // 保存文件到磁盘
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), "uploads", file.FileName);
        await using var stream = new FileStream(filePath, FileMode.Create);
        await file.CopyToAsync(stream);
    }
​
    return Results.Ok("Files uploaded successfully.");
});
​
app.Run();

那么在 .NET 7 中,创建一个新的 ASP.NET Core Web 应用程序需要使用以下命令:

dotnet new web -n FileUpload

接下来,进入项目目录,并使用以下命令添加一个文件上传控制器:

cd FileUpload
dotnet add package Microsoft.AspNetCore.Http
dotnet add package Microsoft.AspNetCore.Http.Features

Controllers 文件夹下创建一个名为 UploadController.cs 的控制器,并添加以下代码:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Threading.Tasks;
​
namespace FileUpload.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class UploadController : ControllerBase
    {
        [HttpPost]
        public async Task<IActionResult> Upload(IFormFile file)
        {
            if (file == null || file.Length == 0)
            {
                return BadRequest("No file uploaded.");
            }
​
            var filePath = Path.GetTempFileName();
            using (var stream = System.IO.File.Create(filePath))
            {
                await file.CopyToAsync(stream);
            }
​
            return Ok($"File uploaded successfully. Stored in {filePath}");
        }
    }
}

在此代码中,我们创建了一个名为UploadController的控制器,并添加了一个名为 Upload的动作。此动作将接受一个 IFormFile对象,该对象将包含要上传的文件的数据。如果未选择文件或所选文件大小为零,则该动作将返回一个 BadRequest响应。否则,该动作将创建一个唯一的临时文件名,并将上传的文件保存到该文件中。最后,该动作将返回一个 Ok响应,指示文件已成功上传并保存在临时文件中。

接下来,在 Startup.cs 文件中添加以下代码,以允许文件上传:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
​
namespace FileUpload
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddHttpContextAccessor();
            services.AddMvc();
        }
​
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
​
            app.UseHttpsRedirection();
​
            app.UseRouting();
​
            app.UseAuthorization();
​
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

在此代码中,我们使用 AddControllers 方法将 MVC 控制器添加到应用程序中,并使用 AddHttpContextAccessor方法添加 IHttpContextAccessor 服务以访问 HTTP 请求和响应。最后,我们在 Configure 方法中添加了必要的中间件和路由规则,以便启用 MVC 控制器并允许文件上传。

最后,您可以使用 dotnet run 命令运行应用程序,然后使用您选择的工具(如 PostmancURL)向 https://localhost:5001/upload 发送 POST 请求,其中包含要上传的文件。应用程序将返回一个包含临时文件路径的 JSON 响应。