c# - HttpClient.PostAsJsonAsync 使用私有(private)成员而不是公共(public)属性

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

我有一个正在 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 序列化,代码库中的某处选项 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/

相关文章:

c# - 在 .Net 中打印

c# - 来自 Entity Framework 的数据访问在调试期间有效,但在实时时无效

c# - 读取JSON文件时keyvaluepair值为0

c# - 如何从 RadioButtonList 中获取选中的值?

javascript - 使用 Handlebars 模板引擎传递 JSON 数组

asp.net-web-api2 - Ninject 激活 HttpConfiguration 时出错

json - 检索并使用Volley错误HTTP响应代码和开关大小写来处理错误

javascript - 使用公共(public) JSON API 并将其显示为 html

c# - 使用 FromUri 绑定(bind)没有参数名称前缀的对象

asp.net-web-api - client.DeleteAsync - 在正文中包含对象