14

我对 WCF 有点陌生,并将尝试清楚地描述我正在尝试做的事情。

我有一个使用 JSON 请求的 WCF 网络服务。在大多数情况下,我在发送/接收 JSON 方面做得很好。例如,以下代码运行良好且符合预期。

发送的 JSON:

{ "guy": {"FirstName":"Dave"} }

周转基金:

    [DataContract]
    public class SomeGuy
    {
        [DataMember]
        public string FirstName { get; set; }
    }

    [OperationContract]
    [WebInvoke(Method = "POST",
               BodyStyle = WebMessageBodyStyle.WrappedRequest,
               RequestFormat = WebMessageFormat.Json,
               ResponseFormat = WebMessageFormat.Json)]
    public string Register(SomeGuy guy)
    {
        return guy.FirstName;
    }

这将按预期返回一个带有“Dave”的 JSON 对象。问题是我不能总是保证我收到的 JSON 将与我的 DataContract 中的成员完全匹配。例如,JSON:

{ "guy": {"firstname":"Dave"} }

由于大小写不匹配,将无法正确序列化。guy.FirstName 将为空。这种行为是有道理的,但我真的不知道如何解决这个问题。我是否必须在客户端强制使用字段名称,还是有办法在服务器端进行协调?

一个可能相关的问题:我可以接受通用 JSON 对象并将其序列化为 StringDictionary 或某种简单的键值结构吗?所以无论在 JSON 中发送什么字段名称,我都可以访问已发送给我的名称和值吗?现在,我可以读取我收到的数据的唯一方法是它是否与预定义的 DataContract 完全匹配。

4

5 回答 5

11

这是将 json 读入字典的另一种方法:

[DataContract]
public class Contract
    {
    [DataMember]
    public JsonDictionary Registration { get; set; }
    }

[Serializable]
public class JsonDictionary : ISerializable
    {
    private Dictionary<string, object> m_entries;

    public JsonDictionary()
        {
        m_entries = new Dictionary<string, object>();
        }

    public IEnumerable<KeyValuePair<string, object>> Entries
        {
        get { return m_entries; }
        }

    protected JsonDictionary(SerializationInfo info, StreamingContext context)
        {
        m_entries = new Dictionary<string, object>();
        foreach (var entry in info)
            {
            m_entries.Add(entry.Name, entry.Value);
            }
        }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
        foreach (var entry in m_entries)
            {
            info.AddValue(entry.Key, entry.Value);
            }
        }
    }
于 2011-09-09T10:57:07.917 回答
5

顾名思义,数据合约是一组规则。如果您想可靠地将消息映射到操作,则需要遵循这些规则。

为什么不能保证套管是正确的?如果您只想使用 JavaScript 中的小写标识符,则可以使用该MessageParameter属性 - 但您仍然必须选择特定名称。

从理论上讲,您可以接受原始 JSON 并手动反序列化它(只需获取一个字符串参数并使用任何 JSON 库进行反序列化),但这确实不符合 WCF 的精神。

我认为您真正需要解决的不是数据合同区分大小写的事实,而是 JSON 没有在客户端正确组合的事实。


如果您想在操作中接受原始 JSON 字符串,则将 更改BodyStyleWebMessageBodyStyle.Bare,并将您的方法签名更改为接受单个字符串参数,该参数将填充客户端发送的任何 JSON 字符串。

请注意,您得到的只是一个字符串,您必须自己完成所有解析和属性映射以及验证和错误处理。这不是我会选择的路线,但如果你愿意承担所涉及的努力和风险,这是一种潜在的选择。

于 2010-02-19T16:52:00.723 回答
3

您可以尝试使用小写名称添加另一个DataMember属性,但我假设您想要一种不区分大小写的方法来协调成员名称,在这种情况下,使用额外的 DataMember 属性变得不合理。

可以提供IDataContractSurrogate实现,但这将涉及您的大量额外工作以及大量反射(无法以静态方式执行此操作,可以在编译时验证)。

就我个人而言,当涉及到 JSON 时,我已经放弃了使用DataContractSerializer该类。相反,我使用Json.NET来满足我所有的 JSON 需求。我可以看到你可以在哪里将 Json.NET 插入到DataContractSerializerthrough aIDataContractSurrogate中,但它仍然会有点粗糙。

考虑到使用DataContractSerializer. DataContractSerializer此外,再加上for JSON 不能正确处理值的事实,这DateTimeOffset对我来说很容易,特别是因为我在 ASP.NET MVC 环境中工作(这允许我以任何方式塑造结果想)。

如果您使用 JSON 作为编码公开 RESTful 服务,这确实是更好的选择,您可以将其与 WCF 混合和匹配,以通过您需要的所有传输和消息协议公开所有端点。

于 2010-02-19T16:49:06.113 回答
3

为了实现我的目标,即拥有一个可以接受完全任意的“key”:“value”对列表作为原始 JSON 字符串的服务,然后决定如何处理它们而无需事先知道“key”名称,我结合了 casper 和 aaron 的建议。

第一,要访问原始 JSON 字符串,这个 MSDN 博客非常有帮助。

我无法简单地将单个方法参数更改为 String 和BodyStyletoWebMessageBodyStyle.Bare而没有问题。将 BodyStyle 设置为 Bare 时,请确保端点behaviorConfiguration设置为<webHttp/>而不是<enableWebScript/>

第二个注意事项是,正如casperOne 提到的,该方法只能有 1 个参数。不过,此参数必须是 aStream才能访问原始文本(请参阅上面的 MSDN 博客)。

获得原始 JSON 字符串后,只需将其反序列化为 StringDictionary。我为此选择了 JSON.Net,它运行良好。这是一个简单的例子来说明。

[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare,
    ResponseFormat = WebMessageFormat.Json)]
public string Register(Stream rawJSON)
{ 
    // Convert our raw JSON string into a key, value
    StreamReader sr = new StreamReader(rawJSON);
    Dictionary<string, string> registration =     
        JsonConvert.DeserializeObject<Dictionary<string, string>>(
            sr.ReadToEnd());

    // Loop through the fields we've been sent.
    foreach (KeyValuePair<string, string> pair in registration)
    {
        switch (pair.Key.ToLower())
        {
            case "firstname":
                return pair.Value;
                break;
        }

    }
}

这允许我通过 JSON 接受任意字段列表,并且字段名称不区分大小写。我知道这不是数据完整性或 WCF 服务理想结构的最严格方法,但据我所知,这是到达我想去的地方的最简单方法。

于 2010-02-24T22:43:01.090 回答
0

这实际上取决于您使用数据的目的。理论上,您可以通过使用字符串返回类型来保持这种通用性。然而,数据将代表一个对象,客户端控件应该知道如何枚举返回的 JSON 对象。您可以返回类型,这也可能有所帮助。

然后在您的客户端代码中,您可以拥有一个知道如何确定和读取不同类型的功能。

于 2010-02-19T16:48:52.290 回答