Json.Net和WCF数据成员的属性映射问题

时间:2016-08-08 08:04:37

标签: c# json wcf json.net

我正在使用Json.Net Nuget包将Json对象反序列化为C#具体对象。我的Json对象具有snake_casing" property_name"但我的C#对象是关注camelCasing" propertyName"。当我反序列化对象时,它正常工作,但是当我尝试从WCF服务反序列化相同的Json对象时,它没有映射到C#类的属性。

var eventMessage = JsonConvert.DeserializeObject<TestClass>( JsonMessage );

ServiceContract:

 [ServiceContract]
public interface IService
{
    [OperationContract]
    [FaultContract( typeof( MessageUnAuthenticatedFault ))]
    [WebInvoke( Method = "POST",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        UriTemplate = "Process" )]
    string Process( string message );
}

这是我的DataContract

[DataContract]
public class TestClass
{
    [DataMember]
    public long Id { get; set; }

    [DataMember]
    [JsonProperty( PropertyName = "request_name" )]
    public string RequestedName { get; set; }

    [DataMember]
    [JsonProperty( PropertyName = "request_type" )]
    public string RequestType { get; set; }

    [DataMember]
    [JsonProperty( PropertyName = "request_key" )]
    public string RequestKey { get; set; }

    [DataMember]
    [JsonProperty( PropertyName = "descriptive_name" )]
    public string DescriptiveName { get; set; } = null;

    [DataMember]
    [JsonProperty( PropertyName = "owner_internal_id" )]
    public string OwnerInternalId { get; set; }

    [DataMember]
    public string URL { get; set; }

    [DataMember]
    public Status Status { get; set; }

    [DataMember]
    public DateTime? Created { get; set; }

    [DataMember]
    public DateTime? Modified { get; set; }

}

Json对象看起来像这样:

{"generated": "2016-08-04T08:06+0000", "request_type": "test", "request_key": "1111", "descriptive_name": "Description", "owner_internal_id": "1213456", "Created":"2016-08-04T08:00"}

为什么Json.Net在WCF服务的情况下没有正确映射属性?

P.S:我的服务仅支持JSON请求和响应。

此致

1 个答案:

答案 0 :(得分:2)

<强>更新

现在你已经在问题中包含了服务合同,我发现存在一个更基本的问题。 WCF用于交换Data Contract objects,并且在XML和JSON之间是格式无关的。它是如此不可知,以至于没有直接的方式来访问底层的原始请求或响应流。相反,WCF坚持为您进行绑定。由于您上传的JSON不是JSON原语,因此尝试将其绑定到string message会失败。

相反,您需要按照

的方式定义服务
[ServiceContract]
public interface IService
{
    [OperationContract]
    [FaultContract( typeof( MessageUnAuthenticatedFault ))]
    [WebInvoke( Method = "POST",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        UriTemplate = "Process" )]
    ResponseClass Process( TestClass message );
}

ResponseClass是你想要归还的地方。请查看WCF rest service to get post JSON data and retrieve JSON data with DataContract示例。

如果您确实需要基础帖子流进行手动解析,那么可能会尝试WCF REST Service JSON Post dataWCF + REST: Where is the request data?中的技巧。

原始答案

WCF不使用Json.NET进行JSON序列化。它使用DataContractJsonSerializer。因此,使用[JsonProperty]注释您的类型将不起作用。相反,您需要设置DataMemberAttribute.Name,即:

[DataContract]
public class TestClass
{
    [DataMember]
    public long Id { get; set; }

    [DataMember(Name = "request_name")]
    public string RequestedName { get; set; }

    [DataMember(Name = "request_type")]
    public string RequestType { get; set; }

    [DataMember(Name = "request_key")]
    public string RequestKey { get; set; }

    [DataMember(Name = "descriptive_name")]
    public string DescriptiveName { get; set; }

    [DataMember(Name = "owner_internal_id")]
    public string OwnerInternalId { get; set; }

    [DataMember]
    public string URL { get; set; }

    [DataMember]
    public Status Status { get; set; }

    [DataMember]
    public DateTime? Created { get; set; }

    [DataMember]
    public DateTime? Modified { get; set; }
}

要使用此序列化程序测试独立JSON反序列化,您可以使用以下帮助程序方法:

public static partial class DataContractJsonSerializerHelper
{
    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }

    public static string SerializeJson<T>(T obj, DataContractJsonSerializer serializer = null)
    {
        serializer = serializer ?? new DataContractJsonSerializer(obj.GetType());
        using (var memory = new MemoryStream())
        {
            serializer.WriteObject(memory, obj);
            memory.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(memory))
            {
                return reader.ReadToEnd();
            }
        }
    }

    public static T DeserializeJson<T>(string json, DataContractJsonSerializer serializer = null)
    {
        serializer = serializer ?? new DataContractJsonSerializer(typeof(T));
        using (var stream = GenerateStreamFromString(json))
        {
            var obj = serializer.ReadObject(stream);
            return (T)obj;
        }
    }
}

然后做:

var test = DataContractJsonSerializerHelper.DeserializeJson<TestClass>(jsonString);

您还必须使用Microsoft的首选DateTime格式设置"/Date(1329159196126-0500)/"属性格式,或使用代理进行反序列化以进行手动解析。有关详细信息,请参阅DataContractJsonSerializer - Deserializing DateTime within ListWCF Extensibility – Serialization Surrogates;有关背景信息,请参阅ASP.NET AJAX: Inside JSON date and time string。或者只为每个DateTime使用代理属性,例如:

    [IgnoreDataMember]
    public DateTime? Created { get; set; }

    [DataMember(Name = "Created")]
    string CreatedString
    {
        get
        {
            if (Created == null)
                return null;
            // From https://stackoverflow.com/questions/114983/given-a-datetime-object-how-do-i-get-a-iso-8601-date-in-string-format
            return Created.Value.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
        }
        set
        {
            if (string.IsNullOrEmpty(value))
                Created = null;
            else
                Created = DateTime.Parse(value);
        }
    }

    [DataMember]
    public DateTime? Modified { get; set; }
}

如果您真的想将Json.NET与WCF一起用于反序列化,则需要做一些工作。请参阅C# WCF REST - How do you use JSON.Net serializer instead of the default DataContractSerializer?,可能还有Using Custom WCF Body Deserialization without changing URI Template Deserialization

有关各种Microsoft框架使用的JSON序列化程序的详细信息,请参阅Json serializers in ASP.NET and other