HttpClient.PostAsJsonAsync使用私有成员而不是公共属性

时间:2018-01-27 20:53:54

标签: c# json asp.net-web-api2

我有一个POST到Web API的客户端。收到POST内容时,JSON使用属性的私有成员名称而不是公共属性。 (客户端应用程序正在使用Asp.Net-Web-api2库,而Web API本身是使用IIS7.5上的IHttpHandler实现的,并且不是MVC样式的应用程序,代码也在使用现有的Usage类之前导致我重新编码的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时,它看起来如下所示,这会导致反序列化返回一个未填充的Usage对象

{"_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,它也可以按预期工作

1 个答案:

答案 0 :(得分:1)

您看到的原因是您的框架使用进行JSON序列化,而在代码库中的某个位置,选项DefaultContractResolver.IgnoreSerializableAttribute已设置为{{ 1}}。当这个设置时,Json.NET将序列化标记为false的类型的公共和私有字段 - 你的。

为了确认这种情况发生,我们可以检查参考源。首先,HttpClientExtensions.PostAsJsonAsync<T>()使用新构造的[Serializable]

序列化为JSON
JsonMediaTypeFormatter

它的基类BaseJsonMediaTypeFormatter又有一个类型为JsonContractResolver的内部public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, Uri requestUri, T value, CancellationToken cancellationToken) { return client.PostAsync(requestUri, value, new JsonMediaTypeFormatter(), cancellationToken); } ,在其构造函数中设置

IContractResolver _defaultContractResolver

这就是问题的根源。

解决此问题的

您的选项如下所示。

首先,如果您愿意为模型添加Json.NET依赖项,可以使用[JsonObject]

标记您的类型
// Need this setting to have [Serializable] types serialized correctly
IgnoreSerializableAttribute = false;

这会将JsonObjectAttribute.MemberSerialization重置为默认值MemberSerialization.OptOut,从而覆盖[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;}} }

其次,您可以使用data contract attributes注释您的类型,Json.NET尊重它:

[Serializable]

请注意,数据合同序列化是选择性的,因此您需要注释要序列化的每个成员。

第三,您可以删除[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;}} } - 但在您的问题中,您表明这不是一个选项。

最后,您可以根据reference source制作自己的扩展方法,以取代HttpClientExtensions中的扩展方法,并使用[Serializable]序列化您的对象,例如(未经测试):

IgnoreSerializableAttribute = true