如何在 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,
如果我有 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,