在 POST API 中传递多个参数,而不使用 .Net Core MVC 中的 DTO 类

Posted

技术标签:

【中文标题】在 POST API 中传递多个参数,而不使用 .Net Core MVC 中的 DTO 类【英文标题】:Post Multiple Parameters Without DTO Class 【发布时间】:2018-09-08 14:00:42 【问题描述】:

我的网络项目有一个调用 API 的操作

    [HttpPost]
    public async Task<IActionResult> ExpireSurvey(int id)
    
        var token = await HttpContext.GetTokenAsync("access_token");

        using (var client = new HttpClient())
        
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

            var path = "/api/forms/ExpireSurvey";
            var url = Domain + path;
            var data = JsonConvert.SerializeObject(id);
            HttpContent httpContent = new StringContent(data, Encoding.UTF8, "application/json");
            var response = await client.PutAsync(url, httpContent);

            return Json(response);
        
    

在 API 项目中接收如下:

[HttpPut]
    public IActionResult ExpireSurvey([FromBody] int surveyId)
    
        _repository.ExpireSurvey(surveyId, expiryDate);
        return Ok();
    

这很好用——但是,假设我想传入一个 int id 和一个 DateTime 变量,我如何将它们序列化并将它们都传递到 HttpContent 中?我可以使用 DTO 对象来完成,但我不想在只有两个字段时设置 DTO 对象。

【问题讨论】:

using (var client = new HttpClient()) 不是最好的选择,寻找它! 【参考方案1】:

你可以像这样使用匿名类型

var x = new  id = 2, date = DateTime.Now ;
var data = JsonConvert.SerializeObject(x);

接收数据时,只能有一个[FromBody]参数。因此,这不适用于接收多个参数(除非您可以将除一个之外的所有参数都放入 URL)。如果不想声明 DTO,可以使用如下动态对象:

[HttpPost]
public void Post([FromBody] dynamic data)

    Console.WriteLine(data.id);
    Console.WriteLine(data.date);

不过,不要过度使用匿名类型和动态变量。它们对于使用 JSON 非常方便,但是您会丢失所有类型检查,这是使 C# 非常适合使用的原因之一。

【讨论】:

这将通过[HttpPut] public IActionResult ExpireSurvey([FromBody] int id, DateTime date)很好地映射到API? 没有。我已经扩展了我的答案以涵盖接收数据。【参考方案2】:

我认为认识到 ASP.NET Core 是基于 REST 的并且 REST 从根本上处理资源的概念会很有帮助。虽然不是一个牢不可破的规则,但总体思路是您应该在这里拥有您所谓的 DTO。换句话说,您发布的不是不同且不相关的数据位,而是代表某事的 object

如果您开始混合 Swagger 之类的东西来为您的 API 生成文档,这将变得越来越重要。您创建的对象将成为该文档的一部分,为您的 API 的使用者提供一个模板,以便在他们的应用开发中遵循。

总而言之,我想说的是接受资源/对象/DTO/其他的概念。 模型您的 API 使用的数据。作为 API 的开发者和您的 API 的任何消费者,它都会有所帮助。

【讨论】:

感谢您的信息。如果只有一个字段怎么办?比如身份证?是否仍建议为 Id 设置 DTO? 不,在这种情况下,对象是标量。但是,特别是对于 id,根据定义,id 标识资源,因此它本身不需要是它自己的资源。【参考方案3】:

您可以将多个参数作为 URL 传递,如下例所示

参数名称必须相同(不区分大小写),如果名称不同 匹配则不会设置参数的值。

[HttpPost]
[Route("surveyId/expiryDate")]
public IActionResult Post(int surveyId, DateTime expiryDate)

    return Ok(new  surveyId, expiryDate );

调用网址

http://localhost:[port]/api/[controller]/1/3-29-2018

【讨论】:

啊,是的,我忘记了这个方法!这不是在正文中发送数据吗? 是的,它只发送您在 URL 中作为参数传递的内容,而不发送表单正文数据 这是 Post/Put 的坏习惯吗?我觉得我以前在某处读过仅对 Get 请求使用 URL 参数? 如果你有敏感数据或者有很多参数不要使用,最好使用带有DTO或模型的post 非常感谢!这对我来说似乎很好用: [HttpPost] [Route("endpoint/id")] public async Task RegisterUserDevice([FromBody]Model myModel, int id)【参考方案4】:

根据上面的答案,我得到了以下代码。希望这对某人有帮助! (当然要感谢其他人让我走上正轨)

/// <summary>
/// Post api/dostuff/id
[HttpPost]
[Route("dostuff/id")]
public async Task<IActionResult> DoStuff([FromBody]Model model, int id)

    // Both model and id are available for use!

【讨论】:

感谢您提供这个 - 很高兴知道这是可能的【参考方案5】:

你可以用字典来做

Dictionary<int, object> dict = new Dictionary<int, object>();
dict["id"] = 1
dict["date"] = DateTime.Now;

JsonConvert.SerializeObject(dict);

【讨论】:

有趣!为什么是 Dictionary 而不是 @egmfrs 我的错。应该是int 不,你是对的,它不能以任何其他方式工作。 string 是否引用字段名称,而 object 是否引用它们所持有的任何内容? @egmfrs 哦,天哪……我一度把自己弄糊涂了。是的,它应该是字符串!字符串指的是字段名称,对象指的是值。因为你需要 int + datetime 所以它应该是对象 嗯.. 由于某种原因,日期被传递给 API,但 id 为 0。【参考方案6】:

你可以换行

var data = JsonConvert.SerializeObject(id);

var data = new StringContent(JsonConvert.SerializeObject((surveyId, expiryDate)), Encoding.UTF8, "application/json");

诀窍是您使用一个 Tuple 对象,其中包含您的参数作为单个参数。

您也应该在服务器端使用 Tuple 类型。它可能看起来像:

[HttpPost]
public Task MyWebApiMethod([FromBody] (int SurveyId, DateTime ExpiryDate) parameters)

    int surveyId = parameters.SurveyId;
    DateTime expiryDate = parameters.ExpiryDate;
    // Process your parameters ...

我现在没有 Visual Studio,如果有任何编译问题等,请见谅。

【讨论】:

以上是关于在 POST API 中传递多个参数,而不使用 .Net Core MVC 中的 DTO 类的主要内容,如果未能解决你的问题,请参考以下文章

web API之post参数传递

JavaScript/jQuery:将多个参数传递给 API 中的 POST 请求

如何使用JSON正文在REST API POST方法中传递多个记录

当我们在ColdFusion中使用API 调用(POST请求)将参数数量传递给服务器时,如何修复“POST请求超出”错误?

POST 参数未使用 VBA 传递给 Web API

web api中post参数传递