如何在 Web Api 的正文中传递派生的 JObject class

How do you pass a derived JObject class in the body of a Web Api

如果我有 class

public class TestMe : JObject
{

}

如何在 API 方法中使用它?

public async Task<IHttpActionResult> UpdateMe(int accountId, [FromBody] TestMe sometest)
{
  Console.WriteLine(sometest);
  ...

当我尝试为正文张贴任何内容时,例如:

{
  "Bye": "string"
}

UpdateMe 方法中的 Console.WriteLine 行甚至被命中之前,我收到以下错误:

"The parameters dictionary contains an invalid entry for parameter 'sometest' for method 'System.Threading.Tasks.Task`1[System.Web.Http.IHttpActionResult] UpdateMe(Int32, TestMe)' in '<somepath>.Controllers.MiscController'. The dictionary contains a value of type 'Newtonsoft.Json.Linq.JObject', but the parameter requires a value of type 'TestMe'."

不可能的简短回答,IMO 你所要求的是不可能的,与 api.

无关

IMO 你有 3 个选项要么使用

  • 动态类型
  • 自定义对象类型
  • 词典类型

如本文answer所述,

Whatever is the reason you want to do that - the reason is simple: JObject implements IDictionary and this case is treated in a special way by Json.NET. If your class implements IDictionary - Json.NET will not look at properties of your class but instead will look for keys and values in the dictionary. So to fix your case you can do this

让我们了解一些细节:

为了证明我的第一点,请尝试使用 newton.json 创建一个简单的控制台应用程序,输入字符串:

var input = "{\"Bye\": \"string\"}";

使用动态它会很好地工作:

var result = JsonConvert.DeserializeObject<dynamic>(input);
Console.WriteLine(JsonConvert.SerializeObject(result));

现在自定义对象如下:

public class TestMe
{
    public string Bye { get; set; }
}

var result = JsonConvert.DeserializeObject<TestMe>(input);
Console.WriteLine(JsonConvert.SerializeObject(result));

也很好用。

现在让我们采用您的方法:

public class TestMe : JObject
{
    
}

用下面的方法测试它,它会坏:

var result = JsonConvert.DeserializeObject<TestMe>(input);
Console.WriteLine(JsonConvert.SerializeObject(result));

现在让我们尝试使用字典:

public class TestMe
{
    [JsonExtensionData]
    public Dictionary<string, JToken> MyProperties { get; set; } = new Dictionary<string, JToken>();
}

并进行测试

var result = JsonConvert.DeserializeObject<TestMe>(input);
Console.WriteLine(JsonConvert.SerializeObject(result));

也可以正常工作。

现在我给出了3个选项。

控制器无法接受直接继承自 JObject class 的 class。 (more info here)。我假设在您的情况下,您不知道您将在输入 JSON 中收到哪些属性。这些是可能的解决方案:

只接受控制器中的 JObject class。

[Route("{accountID}")]
[HttpPost]
public async Task<IHttpActionResult> UpdateMe(int accountId, [FromBody] JObject sometest)
{
    string test = sometest.ToString();

    return Ok(test);
}

您可以根据需要使用 JObject class。示例 - read more here.
这是解决问题的一种方法。


另一种解决方案是将 JSON 正文作为原始 JSON 读取并根据您的需要执行:

[Route("{accountID}")]
[HttpPost]
public async Task<IHttpActionResult> UpdateMe(int accountId)
{
    string rawContent = string.Empty;
    using (var contentStream = await this.Request.Content.ReadAsStreamAsync())
    {
        contentStream.Seek(0, SeekOrigin.Begin);
        using (var sr = new StreamReader(contentStream))
        {
            rawContent = sr.ReadToEnd();
            // use raw content here
        }
    }

    return Ok(rawContent);
}

未知输入 JSON 的另一种解决方案是在控制器中接受 dynamic 类型,但我个人不建议这样做。如何实施read here. Why I don't like it,