HttpClient.PostAsJsonAsync 使用私有成员而不是 public 属性
HttpClient.PostAsJsonAsync using private members instead of public properties
我有一个正在 POST 访问 Web API 的客户端。当收到 POST 内容时,JSON 正在使用属性的私有成员名称而不是 public 属性。 (客户端应用程序使用 Asp.Net-Web-api2 库,Web API 本身是使用 IIS7.5 上的 IHttpHandler 实现的,不是 MVC 风格的应用程序,代码也与现有用法 class 在导致我重新编码和现在奇怪行为的 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;}}
}
我使用以下
创建 post
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 时,它看起来如下所示,这导致反序列化为 return 未填充的 Usage 对象
{"_user":"pete","_trackingUnit":"unit of work"}
我希望
{"User":"pete","TrackingUnit":"unit of work"}
备注:
如果我新建一个新的 Usage 对象并尝试在 Web 中序列化它 API 并且 return 字符串格式正确
JsonConvert.SerializeObject(usage);
{"User":"pete","TrackingUnit":"unit of work"}
此外,如果我尝试 JsonConvert.Serialize 在客户端应用程序中,它也会按预期工作
您看到的原因是您的框架使用 json.net for JSON serialization, and somewhere in the code base the option DefaultContractResolver.IgnoreSerializableAttribute
已设置为 false
。当此设置时,Json.NET 将序列化标记为 [Serializable]
的类型的 public 和私有 字段 -- 这是你的。
要确认发生这种情况的位置,我们可以检查参考来源。首先,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);
}
它是基础 class BaseJsonMediaTypeFormatter
in turn has an internal IContractResolver _defaultContractResolver
of type 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;}}
}
这通过重置 JsonObjectAttribute.MemberSerialization
to its default value MemberSerialization.OptOut
覆盖 [Serializable]
。
其次,您可以使用 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 that replace those in 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.
}
我有一个正在 POST 访问 Web API 的客户端。当收到 POST 内容时,JSON 正在使用属性的私有成员名称而不是 public 属性。 (客户端应用程序使用 Asp.Net-Web-api2 库,Web API 本身是使用 IIS7.5 上的 IHttpHandler 实现的,不是 MVC 风格的应用程序,代码也与现有用法 class 在导致我重新编码和现在奇怪行为的 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;}}
}
我使用以下
创建 postUsage 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);
我正在使用以下
接收 POSTbyte[] postData = context.Request.BinaryRead(context.Request.ContentLength);
string strData = Encoding.UTF8.GetString(postData);
Usage newUsage = JsonConvert.DeserializeObject<Usage>(strData);
当我检查 strData 时,它看起来如下所示,这导致反序列化为 return 未填充的 Usage 对象
{"_user":"pete","_trackingUnit":"unit of work"}
我希望
{"User":"pete","TrackingUnit":"unit of work"}
备注:
如果我新建一个新的 Usage 对象并尝试在 Web 中序列化它 API 并且 return 字符串格式正确
JsonConvert.SerializeObject(usage);
{"User":"pete","TrackingUnit":"unit of work"}
此外,如果我尝试 JsonConvert.Serialize 在客户端应用程序中,它也会按预期工作
您看到的原因是您的框架使用 json.net for JSON serialization, and somewhere in the code base the option DefaultContractResolver.IgnoreSerializableAttribute
已设置为 false
。当此设置时,Json.NET 将序列化标记为 [Serializable]
的类型的 public 和私有 字段 -- 这是你的。
要确认发生这种情况的位置,我们可以检查参考来源。首先,HttpClientExtensions.PostAsJsonAsync<T>()
使用新构造的 JsonMediaTypeFormatter
:
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, Uri requestUri, T value, CancellationToken cancellationToken)
{
return client.PostAsync(requestUri, value, new JsonMediaTypeFormatter(), cancellationToken);
}
它是基础 class BaseJsonMediaTypeFormatter
in turn has an internal IContractResolver _defaultContractResolver
of type 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;}}
}
这通过重置 JsonObjectAttribute.MemberSerialization
to its default value MemberSerialization.OptOut
覆盖 [Serializable]
。
其次,您可以使用 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 that replace those in 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.
}