我有一个正在 POST 到 Web API 的客户端。收到 POST 内容时,JSON 使用属性的私有(private)成员名称而不是公共(public)属性。 (客户端应用程序使用 Asp.Net-Web-api2 库,Web API 本身是使用 IIS7.5 上的 IHttpHandler 实现的,不是 MVC 风格的应用程序,而且代码在TFS 事故导致我重新编码,现在出现了奇怪的行为)
//Object I am passing
[Serializable]
public class Usage
{
private string _user;
private string _trackingUnit;
public string User {get {return _user;} set {_user = value;}}
public string TrackingUnit { get{return _trackingUnit;} set { _trackingUnit = value;}}
}
我使用以下内容发布帖子
Usage usage = new Usage();
usage.User = "pete";
usage.TrackingUnit = "unit of work";
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync(url, usage);
我使用以下方式接收 POST
byte[] postData = context.Request.BinaryRead(context.Request.ContentLength);
string strData = Encoding.UTF8.GetString(postData);
Usage newUsage = JsonConvert.DeserializeObject<Usage>(strData);
当我检查 strData 时,它看起来如下所示,这会导致反序列化返回未填充的使用对象
{"_user":"pete","_trackingUnit":"unit of work"}
我希望
{"User":"pete","TrackingUnit":"unit of work"}
注释:
如果我新建一个新的Usage对象并尝试在Web API中序列化它并返回格式正确的字符串
JsonConvert.SerializeObject(usage);
{"User":"pete","TrackingUnit":"unit of work"}
此外,如果我尝试在客户端应用程序中进行 JsonConvert.Serialize,它也会按预期工作
最佳答案
您看到此情况的原因是您的框架使用 json.net对于 JSON 序列化,代码库中的某处选项 DefaultContractResolver.IgnoreSerializableAttribute
已设置为false
。当此设置时,Json.NET 将序列化标记为 [Serializable]
的类型的公共(public)和私有(private)字段 -- 哪个是你的。
为了确认发生这种情况的位置,我们可以检查引用源。首先 HttpClientExtensions.PostAsJsonAsync<T>()
使用新构建的 JsonMediaTypeFormatter
序列化为 JSON :
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, Uri requestUri, T value, CancellationToken cancellationToken)
{
return client.PostAsync(requestUri, value, new JsonMediaTypeFormatter(), cancellationToken);
}
它是基类 BaseJsonMediaTypeFormatter
依次有一个内部IContractResolver _defaultContractResolver
类型 JsonContractResolver
它在其构造函数中设置
// Need this setting to have [Serializable] types serialized correctly
IgnoreSerializableAttribute = false;
这就是您问题的根源。
解决此问题的选项如下。
首先,如果您愿意向模型添加 Json.NET 依赖项,您可以使用 [JsonObject]
标记您的类型。
[Serializable]
[JsonObject]
public class Usage
{
private string _user;
private string _trackingUnit;
public string User {get {return _user;} set {_user = value;}}
public string TrackingUnit { get{return _trackingUnit;} set { _trackingUnit = value;}}
}
这会覆盖 [Serializable]
通过重置 JsonObjectAttribute.MemberSerialization
为其默认值 MemberSerialization.OptOut
.
其次,您可以使用 data contract attributes 注释您的类型,Json.NET 尊重:
[Serializable]
[DataContract]
public class Usage
{
private string _user;
private string _trackingUnit;
[DataMember]
public string User {get {return _user;} set {_user = value;}}
[DataMember]
public string TrackingUnit { get{return _trackingUnit;} set { _trackingUnit = value;}}
}
请注意,数据协定序列化是可选的,因此您需要注释每个要序列化的成员。
第三,您可以删除 [Serializable]
-- 但在你的问题中你表明这不是一个选择。
最后,您可以基于reference source创建自己的扩展方法。取代 HttpClientExtensions
中的内容并使用 IgnoreSerializableAttribute = true
序列化您的对象,例如(未测试):
public static class MyHttpClientExtensions
{
static JsonMediaTypeFormatter CreateJsonMediaTypeFormatter()
{
var JsonMediaTypeFormatter = new JsonMediaTypeFormatter();
// Use the provided JsonContractResolver but reset IgnoreSerializableAttribute
((DefaultContractResolver)JsonMediaTypeFormatter.SerializerSettings).IgnoreSerializableAttribute = true;
return JsonMediaTypeFormatter;
}
public static Task<HttpResponseMessage> MyPostAsJsonAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken)
{
return client.PostAsync(requestUri, value, CreateJsonMediaTypeFormatter(), cancellationToken);
}
// Replace other JSON methods as required.
}
关于c# - HttpClient.PostAsJsonAsync 使用私有(private)成员而不是公共(public)属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48480456/