C#使用HTTPClient进行HTTP PATCH请求

5

我使用 dot net core 3.1 中的测试服务器编写了一个测试,现在我想向一个端点发送 PATCH 请求。然而,由于我还不熟悉 PATCH 的使用方法,所以我不知道如何发送端点期望的正确对象。

[Fact]
public async Task Patch()
{
    var operations = new List<Operation>
    {
        new Operation("replace", "entryId", "'attendance ui", 5)
    };

    var jsonPatchDocument = new JsonPatchDocument(operations, new DefaultContractResolver());

        
    // Act
    var content = new StringContent(JsonConvert.SerializeObject(jsonPatchDocument), Encoding.UTF8, "application/json");
    var httpResponse = await HttpClient.PatchAsync($"v1/Entry/1", content);
    var actual = await httpResponse.Content.ReadAsStringAsync();
        
}

[HttpPatch("{entryId}")]
public async Task<ActionResult> Patch(int entryId, [FromBody] JsonPatchDocument<EntryModel> patchDocument)
{
    if (patchDocument == null)
       {
           return BadRequest();
       }

       var existingEntry = _mapper.Map<EntryModel>(await _entryService.Get(entryId));

       patchDocument.ApplyTo(existingEntry);

       var entry = _mapper.Map<Entry>(existingEntry);
       var updatedEntry = _mapper.Map<Entry>(await _entryService.Update(entryId, entry));

       return Ok(await updatedEntry.ModelToPayload());
}

我正在创建一个JsonPatchDocument对象,并使用一系列操作对其进行序列化,然后使用HTTP Client和端点URL执行PatchAsync方法。

我的问题是:我应该对什么样的对象进行Patch操作?我是否正确地执行了这个过程?

我尝试像下面图片中所示发送EntryModel对象,但是patchDocument.Operations返回为空列表。

enter image description here

谢谢, Nick

3个回答

3

我最终通过以下几个步骤解决了我的问题:

  • 在Startup.cs中添加依赖services.AddControllers().AddNewtonsoftJson();,否则JsonPatchDocument似乎不起作用。这是来自Nuget包`Microsoft.AspNetCore.Mvc.Newtonsoft.json`。
  • 有一种比@Neil的答案更简单的创建数组的方法,即: var patchDoc = new JsonPatchDocument<EntryModel>().Replace(o => o.EntryTypeId, 5);
  • 您需要使用特定的媒体类型:var content = new StringContent(JsonConvert.SerializeObject(patchDoc), Encoding.UTF8, "application/json-patch+json");

下面是完整的代码:

/// <summary>
/// Verify PUT /Entrys is working and returns updated records
/// </summary>
[Fact]
public async Task Patch()
{
    var patchDoc = new JsonPatchDocument<EntryModel>()
            .Replace(o => o.EntryTypeId, 5);

    var content = new StringContent(JsonConvert.SerializeObject(patchDoc), Encoding.UTF8, "application/json-patch+json");
    var httpResponse = await HttpClient.PatchAsync($"v1/Entry/1", content);
    var actual = await httpResponse.Content.ReadAsStringAsync();

    // Assert
    Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
    Assert.True(httpResponse.IsSuccessStatusCode);
}

/// <summary>
/// Endpoint to do partial update
/// </summary>
/// <returns></returns>
[HttpPatch("{entryId}")]
public async Task<ActionResult> Patch(int entryId, [FromBody] JsonPatchDocument<EntryModel> patchDocument)
{
    if (patchDocument == null)
       {
           return BadRequest();
       }

       var existingEntry = _mapper.Map<EntryModel>(await _entryService.Get(entryId));

        // Apply changes 
        patchDocument.ApplyTo(existingEntry);

        var entry = _mapper.Map<Entry>(existingEntry);
        var updatedEntry = _mapper.Map<Entry>(await _entryService.Update(entryId, entry));

        return Ok();
}

你好,有没有关于如何为对象列表实现Patch的示例或想法?(例如:通过从路径中获取ID来获取数据库用户,一次批准/更新多个用户的状态)谢谢! - Florin Vîrdol

0

JsonPatchDocument 不起作用。要使其起作用,您必须添加媒体类型格式化程序。

  1. 安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson

  2. 在 startup.cs 中,在 AddControllers() 后添加 ->

    .AddNewtonsoftJson(x => x.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); })

  3. 如果您需要将 JSON 作为默认的媒体类型格式化程序,请将其放在任何其他媒体类型格式化程序之前。


0

我在大量搜索后最终自己解决了这个问题。请查看答案以了解如何使用TestServer实现它。 - nick gowdy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接