.NET Core WebAPI(自动)通过JavaScript fetch调用时绑定参数

目录

介绍

本文将如何工作

WebAPI参数属性

背景

在WebAPI参数上使用FromQuery

源代码

启动WebAPI:使用浏览器进行测试

[FromQuery]示例代码

JavaScript获取[FromQuery]

错误

在WebAPI参数上使用FromForm

注意——防伪(AntiForgery)

对.NET Core最小WebAPIs的重大更改

FromForm的WebAPI略有变化

嘘!它总是一些东西!FromForm的JS获取调用

在WebAPI参数上使用FromBody

FromBody的JavaScript fetch调用有问题

不起作用

不起作用2

不起作用3

不起作用4:但确实击中了WebAPI

自动绑定错误:WebAPI无法绑定到变量

问题是什么:你如何解决它?

创建服务器端对象

为工作示例定义 RegisterUser4

JS获取FromBody & 使用JSON.Stringify

在WebAPI参数上使用FromHeader

JavaScript获取[FromHeader]

额外材料OpenApi文档

如何查看OpenApi文档?

您也可以通过curl试用api


GitHub - raddevus/BindApi:在dotnet webapi和JavaScript Fetch中使用自动绑定的文章示例代码[^]

介绍

这是一篇快速文章,其中包含多个示例,演示了如何利用.NET Core WebAPI自动绑定功能的用户。我知道这通常被称为模型绑定,但我的示例涵盖了您只需将一个参数值传递给WebAPI方法的情况。

本文将如何工作

我将为每个示例提供两件事,以便你可以确切地了解自动绑定功能在.NET Core WebAPI中的工作原理。

  1. WebAPI方法定义(通过最小API的示例代码)
  2. JavaScript Fetch示例,可用于POST到WebAPI并查看结果

WebAPI参数属性

.NET Core WebAPI方法允许你使用不同属性的数量来标记参数:

  1. [FromQuery]
  2. [FromForm]
  3. [FromBody]
  4. [FromHeader]
  5. [FromServices]*
  6. [FromKeyedServices]*

*最后两个是.NET Core 8.x的全新功能,我不会在这里介绍它们。但是,我将通过完整的示例介绍前四个属性。

背景

在撰写另一篇文章时,每个用户都有自己的数据库(即将推出),我遇到了.NET Core WebAPIs中的自动绑定参数问题。

我已经编写了许多.NET Core WebAPI,但我注意到有时它比其他Web API更容易。我通常喜欢我的WebAPI使用[FromBody]从发布的正文中获取数据。

但是,我发现了在某些情况下这对我来说会失败的确切原因。

WebAPI参数上使用FromQuery

让我们从我认为最简单的发布数据方法开始,在WebAPI方法上使用[FromQuery]属性。

源代码

  1. 我将在此处添加最短的代码,以便创建快速讨论,但如果您想查看源代码,可以从本文顶部下载或在我的GitHub存储库中获取。
  2. 我将创建包含最小WebAPI的非常小的项目,并且几乎在每种情况下方法的名称都相同,只是它们将为每个示例包含一个数字,以便您可以在本地启动WebAPI,并根据需要自己尝试这些示例。

启动WebAPI:使用浏览器进行测试

启动WebAPI(从下载的代码)后,您可以加载URL并使用浏览器控制台使用JavaScript Fetch API POSTWebAPI。以下是其外观的快照:

[FromQuery]示例代码

[HttpPost] public ActionResult RegisterUser1([FromQuery] string uuid)

在我们的最小API中,您将看到此方法按以下方式定义:

app.MapPost("/RegisterUser1", IResult ([FromQuery] string uuid) =>   {
    return Results.Ok(new { Message = $"QUERY - You sent in uuid: {uuid}" });
});

JavaScript获取[FromQuery]

fetch(`http://localhost:5247/RegisterUser1?uuid=987-fake-uuid-1234`,
      {method: 'POST'})
        .then(response => response.json())
        .then(data => console.log(data));

这个很容易。如果您在URL中提供queryString项(?uuid),则该项目将自动绑定到uuid字符串变量,您将获得有效结果。但是,如果未提供queryString值,则当WebAPI尝试自动绑定时,它将发生错误。

错误

 An unhandled exception has occurred while executing the request.
      Microsoft.AspNetCore.Http.BadHttpRequestException: 
Required parameter "string uuid" was not provided from query string.

WebAPI参数上使用FromForm

让我们使用该[FromForm]属性定义第二个WebAPI方法。

app.MapPost("/RegisterUser2", IResult ([FromForm] string uuid) =>   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})

注意——防伪(AntiForgery)

一旦我开始针对上述命令运行Fetch,我就开始在WebAPI端收到一条奇怪的错误消息,如下所示:

Unhandled exception. System.InvalidOperationException: Unable to find the required
 services. Please add all the required services by calling 
'IServiceCollection.AddAntiforgery' in the application startup code.
   at Microsoft.AspNetCore.Builder
.AntiforgeryApplicationBuilderExtensions
.VerifyAntiforgeryServicesAreRegistered(IApplicationBuilder builder)

.NET Core最小WebAPIs的重大更改

幸运的是,我能够搜索并发现问题是什么以及如何解决它。嘘!

 中断性变更:IFormFile参数需要防伪检查——.NET|Microsoft 学习[^]

FromFormWebAPI略有变化

app.MapPost("/RegisterUser2", IResult ([FromForm] string uuid) =>   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})
.DisableAntiforgery()

嘘!它总是一些东西!
FromFormJS获取调用

有一些设置可以将我们的数据传递到Web表单上。首先,我们必须创建FormData对象并添加我们的名称/值对。之后,我们可以发布数据。

// 1. Create the FormData object
var fd = new FormData();
// 2. Append the name/value pair(s) for values you want to send
fd.append("uuid", "123-test2-2345-uuid-551");
fetch(`http://localhost:5247/RegisterUser2`,{
      method:'POST',
     body:fd,   // add the FormData object to the body data which will be posted
})
.then(response => response.json())
.then(data => console.log(data));

现在,我们已经使用了两个运行良好的不同属性。让我们深入研究一下使用[FromBody]属性,这将带来很大的困难。

WebAPI参数上使用FromBody

app.MapPost("/RegisterUser3", IResult ([FromBody] string uuid) =>   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})

FromBodyJavaScript fetch调用有问题

乍一看,这个应该很容易,因为你可能会认为你应该能够在正文上传入一个字符串值。无论如何,我就是这么想的。

不起作用

app.MapPost("/RegisterUser3", IResult ([FromBody] string uuid) =>   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})

但是,这甚至不会通过您的浏览器,因为它希望您为正文定义一个对象(在两个{ }大括号之间)。

接下来,您可能认为您可以创建一个包含目标参数(uuid)名称的对象并传递它,如下所示:

不起作用2

var data = {"uuid":"yaka-yaka"};
fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:data,   
})
.then(response => response.json())
.then(data => console.log(data));

这是行不通的,也不会通过您的浏览器。同样,它认为身体物体的构造不正确。

不起作用3

fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:{"uuid":"this-is-uuid-123"},   
})
.then(response => response.json())
.then(data => console.log(data));

还是行不通。你会得到一个415 Unsupported Media type。因此,您需要添加Content-Type对象并将其设置为JSON,以便Fetch调用知道您打算使用JSON进行调用。这是因为您在正文中添加了大括号。

不起作用4:但确实击中了WebAPI

这个实际上确实击中了WebAPI

fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:{"uuid":"this-is-uuid-123"},   
    headers: {
           'Content-type':'application/json; charset=UTF-8',
       },
})
.then(response => response.json())
.then(data => console.log(data));

但是,现在您从服务器收到错误,其中指出:

自动绑定错误:WebAPI无法绑定到变量

Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to read parameter 
"string uuid" from the request body as JSON.

这是一个自动绑定错误,因为WebAPI没有看到uuid值,即使我们确实将其与body对象一起传递。

在这一点上,我大吃一惊。

问题是什么:你如何解决它?

好吧,你不能在JavaScript方面解决它。后来发现,你不能将字符串值作为参数直接传递给WebAPI。相反,您必须创建一个与client-side object 匹配的server-side object

创建服务器端对象

下面是我们要添加到Program.cs中的新类(仅用于示例目的):

record UuidHolder{
    public string uuid{get;set;}
}

为工作示例定义 RegisterUser4

我们将使用以下WebAPI作为我们的工作示例:

app.MapPost("/RegisterUser4", IResult ([FromBody] UuidHolder uuid) =>   {
    return Results.Ok(new { Message = $"BODY - You sent in uuid: {uuid.uuid}" });
})

这将保留RegisterUser3 WebAPI方法,因此您可以看到无法对其进行绑定。

现在,我们必须稍微改变我们的JavaScript Fetch调用以使用JSON.stringify(),然后一切都会正常工作。

JS获取FromBody & 使用JSON.Stringify

fetch(`http://localhost:5247/RegisterUser4`,{
      method:'POST',
     body:JSON.stringify({"uuid":"this-is-uuid-123"}),   
    headers: {
           'Content-type':'application/json; charset=UTF-8',
       },
})
.then(response => response.json())
.then(data => console.log(data));

它是有效的!

我以为将数据发送到身体上是最简单的方法,但这是最困难的。让我们介绍最后一个(FromHeader)并总结一下。

WebAPI参数上使用FromHeader

这是最后一个,它允许我们将数据放在标题中并发布它。

app.MapPost("/RegisterUser5", IResult ([FromHeader] string uuid) =>   {
    return Results.Ok(new { Message = $"HEADER - You sent in uuid: {uuid}" });
})

JavaScript获取[FromHeader]

这个很容易做到,但我不完全确定为什么我们要使用标题发布数据。

但是,它确实可以帮助我们将数据自动绑定到我们可能具有的某些标头值。

fetch(`http://localhost:5247/RegisterUser5`,{
      method:'POST', 
    headers: {
           'Content-type':'application/json; charset=UTF-8',
            "uuid":"123-456-789"
       },
})
.then(response => response.json())
.then(data => console.log(data));

现在,可以使用任何基本属性在.NET Core WebAPI方法中自动绑定,数据将通过。当它没有时,你就会明白去哪里看。

额外材料OpenApi文档

哇!我刚刚发现(在发表我的文章后)我实际上通过OpenApi获得了一些关于我的API的免费文档。

dotnet项目模板在Program.cs文件中添加了几行,用于处理生成文档。

app.UseSwagger();
app.UseSwaggerUI();

然后,在每个post方法上,我添加了以下调用:

.WithOpenApi();

如何查看OpenApi文档?

我在网上搜索了所有内容,并扫描了这个解释OpenApi文档的冗长文档,但它从未向我展示如何查看文档。这太疯狂了!我终于找到了如何在此处查看自动生成的文档。

要检查文档,请启动webapi并转到:http://localhost:5247/swagger

您将看到以下内容:

您也可以通过curl试用api

文档处于活动状态,您现在可以通过UI试用API。它在后台使用curl发布到webapi您将看到curl可以正确地发布到body方法。但是,它在FromForm上失败。真的很有意思。

https://www.codeproject.com/Articles/5383531/NET-Core-WebAPI-Auto-Binding-Parameters-When-Calli

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值