14

私は WCF に少し慣れていないので、私がやろうとしていることを明確に説明しようとします。

JSON 要求を使用する WCF Web サービスがあります。ほとんどの場合、JSON の送受信は正常に行われています。たとえば、次のコードは正常に機能し、期待どおりに機能します。

JSON 送信:

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

WCF:

    [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 は null になります。この動作は理にかなっていますが、これを回避する方法がよくわかりません。クライアントでフィールド名を強制する必要がありますか、またはサーバー側で調整する方法はありますか?

おそらく関連する質問: 一般的な 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文字列が入力される単一の文字列パラメーターを受け入れます。

取得するのはこれからの単一の文字列だけであることに注意してください。すべての解析とプロパティのマッピング、検証、およびエラー処理を自分で行う必要があります。それは私が選択するルートではありませんが、それに伴う努力とリスクを喜んで引き受けるのであれば、それは1つの潜在的な選択肢です。

于 2010-02-19T16:52:00.723 に答える
3

DataMember小文字の名前で別の属性を追加することもできますが、大文字と小文字を区別せずにメンバー名を調整する方法が必要だと思います。その場合、追加のDataMember属性を使用するのは不合理になります。

IDataContractSurrogateの実装を提供することもできますが、それには多くの追加作業と多くの反映が必要になります(コンパイル時に検証できる静的な方法でこれを行う方法はありません)。

個人的には、JSONに関してはDataContractSerializerクラスの使用をあきらめました。むしろ、JSONのすべてのニーズにJson.NETを使用しています。DataContractSerializerを介してJson.NETをどこにプラグインできるかはわかりますが、IDataContractSurrogateそれでも少しラフになります。

Json.NETは、の使用が難しいことを考えると簡単な選択でしたDataContractSerializer。また、DataContractSerializerfor JSONが値を正しく処理しないという事実に加えDateTimeOffsetて、特にASP.NET MVC環境で作業していたので(これにより、結果を任意の方法で形成できるため)、非常に簡単でした。欲しいです)。

エンコーディングとしてJSONを使用してRESTfulサービスを公開する場合、これは本当に良い選択です。これをWCFと組み合わせて、必要なすべてのトランスポートおよびメッセージプロトコルですべてのエンドポイントを公開できます。

于 2010-02-19T16:49:06.113 に答える
3

「キー」の完全に任意のリストを受け入れることができるサービスを持つという私の目標を達成するために:「値」ペアを生のJSON文字列として受け取り、「キー」名を事前に知らなくてもそれらをどうするかを決定します。キャスパーとアーロンのアドバイスを組み合わせました。

まず、生のJSON文字列にアクセスするには、このMSDNブログが非常に役立ちました。

単一のメソッドパラメータをStringとBodyStyletoWebMessageBodyStyle.Bareに問題なく変更することはできませんでした。BodyStyleをBareに設定するときは、エンドポイントbehaviorConfigurationがに設定されていることを確認して<webHttp/>ください<enableWebScript/>

2番目の注意点は、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 に答える