概要
WPFアプリでユーザー設定をJSONに保存していると、アプリ更新時に設定クラスへ新しいプロパティを追加することがあります。 このとき、DataContractJsonSerializerを使っている場合は注意が必要です。
旧バージョンで保存されたJSONには、新しく追加したキーが存在しません。
その状態で読み込むと、新規プロパティがnullや0のまま残り、色変換やフォント設定などで例外や不自然なUI表示を起こすことがあります。
起きやすい問題
例えば、色設定クラスにHeaderBackgroundを後から追加したとします。
[DataMember(Order = 20)]
public string HeaderBackground { get; set; } = "#F0F0F0";
一見すると、初期値があるので安全に見えます。
しかし、DataContractJsonSerializerの復元では、通常のコンストラクタやフィールド初期化子が期待通りに使われないケースがあります。
そのため、旧JSONに存在しないプロパティはnullのまま残ることがあります。
そのnullを色変換へ渡すと、次のような症状につながります。
- 見出し帯やコードペインの背景が真っ黒になる
- フォント名が空になって表示が崩れる
- 数値設定が
0になり、UIサイズや文字サイズが異常になる - ユーザーへ「設定ファイルを削除してください」と案内せざるを得なくなる
解決策
解決策は、読み込み直後にOnDeserializedで既定値を補填することです。
古いJSONから復元したあと、null、空文字、範囲外の数値を安全な値へ戻します。
コードを読み込み中...このように、設定クラス自身に補填処理を持たせておくと、古い設定ファイルを読み込んでもアプリ側のUI処理へ危険な値が渡りにくくなります。
実装時のポイント
[OnDeserialized]メソッドはprivateでも動きます。- 引数には
StreamingContextが必要です。 - 文字列は
string.IsNullOrWhiteSpaceでnullと空文字をまとめて補填します。 - 数値型は
nullにならないため、0や範囲外の値を未設定扱いにするか判断します。 - 新しい設定プロパティを追加したら、同じタイミングで補填処理にも1行追加します。
設定ファイルの互換性は、リリース後に効いてきます。 新規インストールでは問題なくても、既存ユーザーの設定JSONだけで壊れるケースがあるため、更新時のチェック項目として持っておくべきです。
向いている場面
このパターンは、次のようなアプリに向いています。
- WPFアプリでユーザー設定をJSON保存している
- 色、フォント、表示設定、レイアウト設定を持っている
- アプリ更新で設定項目が増える
- 既存ユーザーに設定ファイル削除を依頼したくない
特に、配布済みの業務ツールでは「設定ファイルを消してください」という案内は避けたいところです。 読み込み後に自動補正できる設計にしておくと、更新時のトラブルをかなり減らせます。
まとめ
DataContractJsonSerializerで設定を保存している場合、新規プロパティの初期値だけを信じると、旧JSON読み込み時にnullや不正値が残ることがあります。
[OnDeserialized]で読み込み直後のマイグレーションを行えば、古い設定ファイルを残したまま安全にアプリを更新できます。
WPFアプリやVSTO補助画面など、長く使われるデスクトップツールでは、設定クラスに必ず入れておきたい防御策です。
