web-dev-qa-db-ja.com

WCFでの既定の日付のシリアル化を変更する

WCFのDateTimeのデフォルトのJSONシリアル化/逆シリアル化を変更する方法はありますか?

現在、DateTimeは/Date(1372252162657+0200)/形式にシリアル化されていますが、これは問題ないはずですが、サーバーがUTCでない場合(変更できない)、問題が発生しています。

このサービスで処理されているすべての日付/時刻データはUTC形式です。サーバーがUTCにある場合、すべてが機能します。ただし、ステージング/製品環境はGMT + 1(パリ)に設定され、シリアライザは日付/時刻がGMT + 1であると想定し、属性Kindを完全に無視します。したがって、DateTime.SetKind()を呼び出してUTCに設定しても、期待どおりに機能しません。実際、シリアル化された時間は1時間遅れます。

私は双方向の日付会話を行うこともできます(逆シリアル化するときにも同じ仮定を行うため、常にGMT + 1です)日付の会話:UTCとサーバー時間の間のやり取りですが、これは面倒です。だから私は多分私は単にデフォルトのシリアル化動作をオーバーライドできると思いました。

17
Mel

はい、これは「Message Formatters」という概念を使用して行うことができます

ただし、メッセージフォーマッタは、スタックオーバーフローについてここで説明するのは難しく、範囲外です。参照できます WCF Extensibility:Message Formatters

これを台無しにしたくない場合は、ハックを利用できます。

各メソッドの戻り値の型をStreamに設定します。

例えば.

        public Stream GetStaticData()
        {
            var objTobeReturned = something;
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
            return new MemoryStream(Encoding.UTF8.GetBytes(objTobeReturned.ToJson()));
        }

ここでToJson()は、NewtonSoftライブラリを使用してオブジェクトをjson文字列に変換する独自の拡張メソッドです。

WCFは、シリアル化のためにストリーム出力をスキップし、そのままクライアントに渡します。

答えが出たらいいのに。

4
Ronak Patel

tdelepineのコードスニペットを拡張するために、ここで私が使用したコード:

私のWCF JSONサービスでは、(null可能)DateTime値があり、サービスがより読みやすい形式で日付を返すようにしたいので、iPhoneアプリで日付を解釈できます。

いくつかの変更を適用した後のJSONは次のようになります。

enter image description here

WCFがDateTimesを書き込むデフォルトの方法であるUpdateDateOriginalフィールドと、以下のコードを使用して作成したより親しみやすいUpdateDateフィールドに注目してください。

私の元の行は次のようになりました:

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

...そして、ここに新しい友好的なUpdateDate JSON値を作成する行があります。

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

[DataMember(Name = "UpdateDate")]
private string UpdateDateString { get; set; }

[OnSerializing]
void OnSerializing(StreamingContext context)
{
    if (this.UpdateDate == null)
    this.UpdateDateString = "";
    else
    this.UpdateDateString = this.UpdateDate.Value.ToString("MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

[OnDeserialized]
void OnDeserializing(StreamingContext context)
{
    if (this.UpdateDateString == null)
    this.UpdateDate = null;
    else
    this.UpdateDate = DateTime.ParseExact(this.UpdateDateString, "MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

実際、DateTimeの値をISO8601形式で返す方が便利な場合があります。例えば:

UpdateTime: "2014-08-24T13:02:32",

これを行うには、上記のコードを使用するだけですが、両方の場所で文字列"MMM/dd/yyyy HH:mm""s"に変更します。

また、DateTime値がUTCに格納されているが、WCFサービスがユーザーのローカルタイムゾーンで値を返すようにしたい場合は、ここで私のヒントに従うことができます。

ユーザーのローカルタイムゾーンでDateTimeを取得

いくつかの簡単な例で、人生は簡単ではありません!

21
Mike Gledhill

あなたはあなたのjsonオブジェクト定義でこの回避策を使うことができます

[IgnoreDataMember]
public DateTime dateObject;

public string dateCustomSerialize
{
 get {
//Custom get
}
set {
//Custom set
}
}

評価者には、カスタム形式のシリアル化を配置します

12
tdelepine

これでタイムゾーンの問題が解決するわけではありませんが、WCF、ティック、DateTimeと戦っている他の人のためにここに投稿します。

目盛りは必要ないが、人間が読める形式の時刻が必要な場合は、追加のstringプロパティを導入することで実現できます。次に、値を文字列に変換する前にDateTimeをいじるだけです。

    [IgnoreDataMember]    // Ignore the original tick date.
    public DateTime LastReminderDate { get { return _lastReminderDate; } set { _lastReminderDate = value; } }
    [DataMember]          // Make sure you have a public or private setter!
    public string LastReminderDateText { get { return _lastReminderDate.ToString(); } set { _lastReminderDate = DateTime.Parse(value); } }
0
Robotron

1つの方法は、メッセージフォーマッタを使用して、デフォルトのDataContractSerializerWCF Extensibility – Message Formatters で説明されているように変更することです。

もう1つのオプションは、オブジェクトをストリームにロードする拡張メソッドを記述して、オブジェクトに必要なシリアライザを適用することです。これを行う方法の詳細については、受け入れ済みの回答 WCF 4のデフォルトのJSONシリアライザーをJSON.NETに置き換える を参照してください。

0
Karl Anderson