次の方法で共有


XmlSerializer クラスの使用

Windows Communication Foundation (WCF) では、2 つの異なるシリアル化テクノロジを使用して、アプリケーション内のデータをクライアントとサービスの間で送信される XML ( DataContractSerializerXmlSerializer) に変換できます。

DataContractSerializer

既定では、WCF は DataContractSerializer クラスを使用してデータ型をシリアル化します。 このシリアライザーでは、次の型がサポートされています。

  • プリミティブ型 (整数、文字列、バイト配列など) だけでなく、プリミティブとして扱われる XmlElementDateTimeなどの特殊な型もあります。

  • データ コントラクト型 ( DataContractAttribute 属性でマークされた型)。

  • ISerializable インターフェイスを実装する型を含む、SerializableAttribute属性でマークされた型。

  • IXmlSerializable インターフェイスを実装する型。

  • 多くのジェネリック コレクション型を含む多くの一般的なコレクション型。

多くの .NET Framework 型は後者の 2 つのカテゴリに分類されるため、シリアル化できます。 シリアル化可能な型の配列もシリアル化可能です。 完全な一覧については、「 サービス コントラクトでのデータ転送の指定」を参照してください。

データ コントラクト型と共に使用される DataContractSerializerは、新しい WCF サービスを記述する場合に推奨される方法です。 詳細については、「 データ コントラクトの使用」を参照してください。

XmlSerializer

WCF では、 XmlSerializer クラスもサポートされています。 XmlSerializer クラスは WCF に固有ではありません。 Web サービスで使用されるのと同じシリアル化エンジン ASP.NET。 XmlSerializer クラスは、DataContractSerializer クラスよりもはるかに狭い型セットをサポートしますが、結果の XML をより細かく制御でき、XML スキーマ定義言語 (XSD) 標準の多くをサポートしています。 また、シリアル化可能な型に対する宣言属性も必要ありません。 詳細については、.NET Framework ドキュメントの XML シリアル化に関するトピックを参照してください。 XmlSerializer クラスは、データ コントラクト型をサポートしていません。

Svcutil.exe または Visual Studio の サービス参照の追加 機能を使用してサード パーティのサービスのクライアント コードを生成したり、サード パーティのスキーマにアクセスしたりする場合は、適切なシリアライザーが自動的に選択されます。 スキーマが DataContractSerializerと互換性がない場合は、 XmlSerializer が選択されます。

XmlSerializer に切り替える

場合によっては、 XmlSerializerに手動で切り替える必要があります。 これは、たとえば次のような場合に発生します。

  • ASP.NET Web サービスから WCF にアプリケーションを移行する場合は、新しいデータ コントラクト型を作成する代わりに、既存の XmlSerializer互換性のある型を再利用できます。

  • メッセージに表示される XML を正確に制御することが重要であるが、Web サービス記述言語 (WSDL) ドキュメントを使用できない場合 (たとえば、DataContractSerializer と互換性のない、標準化された公開された特定のスキーマに準拠する必要がある型を含むサービスを作成する場合)。

  • 従来の SOAP エンコード標準に従うサービスを作成する場合。

このような場合や他の場合は、次のコードに示すように、XmlSerializerFormatAttribute属性をサービスに適用することで、XmlSerializer クラスに手動で切り替えることができます。

[ServiceContract]
[XmlSerializerFormat]
public class BankingService
{
[OperationContract]
    public void ProcessTransaction(BankingTransaction bt)
    {
        // Code not shown.
    }
}

//BankingTransaction is not a data contract class,
//but is an XmlSerializer-compatible class instead.
public class BankingTransaction
{
    [XmlAttribute]
    public string Operation;
    [XmlElement]
    public Account fromAccount;
    [XmlElement]
    public Account toAccount;
    [XmlElement]
    public int amount;
}
//Notice that the Account class must also be XmlSerializer-compatible.
<ServiceContract(), XmlSerializerFormat()> _
Public Class BankingService
    <OperationContract()> _
    Public Sub ProcessTransaction(ByVal bt As BankingTransaction)
        ' Code not shown.
    End Sub
End Class


' BankingTransaction is not a data contract class,
' but is an XmlSerializer-compatible class instead.

Public Class BankingTransaction
    <XmlAttribute()> _
    Public Operation As String
    <XmlElement()> _
    Public fromAccount As Account
    <XmlElement()> _
    Public toAccount As Account
    <XmlElement()> _
    Public amount As Integer
End Class
'Notice that the Account class must also be XmlSerializer-compatible.

セキュリティに関する考慮事項

シリアル化エンジンを切り替えるときは注意が必要です。 使用されているシリアライザーに応じて、同じ型を XML に異なる方法でシリアル化できます。 誤って間違ったシリアライザーを使用した場合は、開示する予定のない型から情報を開示している可能性があります。

たとえば、 DataContractSerializer クラスは、データ コントラクト型をシリアル化するときに、 DataMemberAttribute 属性でマークされたメンバーのみをシリアル化します。 XmlSerializer クラスは、任意のパブリック メンバーをシリアル化します。 次のコードの型を参照してください。

[DataContract]
public class Customer
{
    [DataMember]
    public string firstName;
    [DataMember]
    public string lastName;
    public string creditCardNumber;
}
<DataContract()> _
Public Class Customer
    <DataMember()> _
    Public firstName As String
    <DataMember()> _
    Public lastName As String
    Public creditCardNumber As String
End Class

XmlSerializer クラスが選択されているサービス コントラクトで型が誤って使用された場合、creditCardNumber メンバーがシリアル化されます。これは、おそらく意図したものではありません。

DataContractSerializer クラスが既定値であっても、DataContractFormatAttribute属性をサービス コントラクトの種類に適用することで、サービスに対して明示的に選択できます (ただし、これは必須ではありません)。

サービスに使用されるシリアライザーはコントラクトの不可欠な部分であり、別のバインドを選択したり、他の構成設定を変更したりして変更することはできません。

その他の重要なセキュリティに関する考慮事項は、 XmlSerializer クラスに適用されます。 まず、 XmlSerializer クラスを使用する WCF アプリケーションには、開示から保護されたキーを使用して署名することを強くお勧めします。 この推奨事項は、 XmlSerializer に手動で切り替える場合と自動スイッチを実行する場合 (Svcutil.exe、サービス参照の追加、または同様のツール) の両方に適用されます。 これは、 XmlSerializer シリアル化エンジンは、アプリケーションと同じキーで署名されている限り、 事前に生成されたシリアル化アセンブリ の読み込みをサポートしているためです。 署名されていないアプリケーションは、事前に生成されたシリアル化アセンブリの予期される名前と一致する悪意のあるアセンブリがアプリケーション フォルダーまたはグローバル アセンブリ キャッシュに配置される可能性から完全に保護されていません。 もちろん、攻撃者はまず、この 2 つの場所のいずれかに書き込みアクセス権を取得して、このアクションを試みる必要があります。

XmlSerializerを使用するたびに存在するもう 1 つの脅威は、システムの一時フォルダーへの書き込みアクセスに関連しています。 XmlSerializerシリアル化エンジンは、このフォルダー内の一時的なシリアル化アセンブリを作成して使用します。 一時フォルダーへの書き込みアクセス権を持つプロセスは、これらのシリアル化アセンブリを悪意のあるコードで上書きする可能性があることに注意してください。

XmlSerializer サポートの規則

コントラクト操作パラメーターまたは戻り値に XmlSerializer互換性のある属性を直接適用することはできません。 ただし、次のコードに示すように、型指定されたメッセージ (メッセージ コントラクト本文部分) に適用できます。

[ServiceContract]
[XmlSerializerFormat]
public class BankingService
{
    [OperationContract]
    public void ProcessTransaction(BankingTransaction bt)
    {
        //Code not shown.
    }
}

[MessageContract]
public class BankingTransaction
{
    [MessageHeader]
    public string Operation;
    [XmlElement, MessageBodyMember]
    public Account fromAccount;
    [XmlElement, MessageBodyMember]
    public Account toAccount;
    [XmlAttribute, MessageBodyMember]
    public int amount;
}
<ServiceContract(), XmlSerializerFormat()> _
Public Class BankingService
    <OperationContract()> _
    Public Sub ProcessTransaction(ByVal bt As BankingTransaction)
        'Code not shown.
    End Sub
End Class

<MessageContract()> _
Public Class BankingTransaction
    <MessageHeader()> _
    Public Operation As String
    <XmlElement(), MessageBodyMember()> _
    Public fromAccount As Account
    <XmlElement(), MessageBodyMember()> _
    Public toAccount As Account
    <XmlAttribute(), MessageBodyMember()> _
    Public amount As Integer
End Class

型指定されたメッセージ メンバーに適用すると、これらの属性は、型指定されたメッセージ属性で競合するプロパティをオーバーライドします。 たとえば、次のコードでは、 ElementNameNameをオーバーライドします。

    [MessageContract]
    public class BankingTransaction
    {
        [MessageHeader] public string Operation;

        //This element will be <fromAcct> and not <from>:
        [XmlElement(ElementName="fromAcct"), MessageBodyMember(Name="from")]
        public Account fromAccount;

        [XmlElement, MessageBodyMember]
        public Account toAccount;

        [XmlAttribute, MessageBodyMember]
        public int amount;
}
<MessageContract()> _
Public Class BankingTransaction
    <MessageHeader()> _
    Public Operation As String

    'This element will be <fromAcct> and not <from>:
    <XmlElement(ElementName:="fromAcct"), _
        MessageBodyMember(Name:="from")> _
    Public fromAccount As Account

    <XmlElement(), MessageBodyMember()> _
    Public toAccount As Account

    <XmlAttribute(), MessageBodyMember()> _
    Public amount As Integer
End Class

XmlSerializerを使用する場合、MessageHeaderArrayAttribute属性はサポートされません。

この場合、 XmlSerializer は、WCF より前にリリースされた例外をスローします。"スキーマの最上位レベルで宣言された要素は、 maxOccurs> 1 を持つことはできません。 XmlElementAttributeの代わりにXmlArrayまたはXmlArrayItemを使用するか、ラップされたパラメーター スタイルを使用して、'more' のラッパー要素を指定します。

このような例外が発生した場合は、この状況が適用されるかどうかを調査します。

WCF では、メッセージ コントラクトと操作コントラクトの SoapIncludeAttribute 属性と XmlIncludeAttribute 属性はサポートされていません。代わりに KnownTypeAttribute 属性を使用してください。

IXmlSerializable インターフェイスを実装する型

IXmlSerializable インターフェイスを実装する型は、DataContractSerializerで完全にサポートされます。 スキーマを制御するには、 XmlSchemaProviderAttribute 属性を常にこれらの型に適用する必要があります。

Warnung

ポリモーフィック型をシリアル化する場合は、正しい型がシリアル化されるように、 XmlSchemaProviderAttribute を型に適用する必要があります。

IXmlSerializableを実装する型には、任意のコンテンツを表す型、1 つの要素を表す型、レガシ DataSet型の 3 種類があります。

  • コンテンツ タイプは、 XmlSchemaProviderAttribute 属性で指定されたスキーマ プロバイダー メソッドを使用します。 このメソッドは null を返しません。属性の IsAny プロパティは既定値の false のままにします。 これは、 IXmlSerializable 型の最も一般的な使用方法です。

  • 要素型は、 IXmlSerializable 型が独自のルート要素名を制御する必要がある場合に使用されます。 型を要素型としてマークするには、XmlSchemaProviderAttribute属性のIsAny プロパティをtrueに設定するか、スキーマ プロバイダー メソッドからnullを返します。 スキーマ プロバイダー メソッドを持つことは、要素型では省略可能です。XmlSchemaProviderAttributeでメソッド名の代わりにnullを指定できます。 ただし、 IsAnytrue され、スキーマ プロバイダー メソッドが指定されている場合、メソッドは nullを返す必要があります。

  • 従来のDataSet型は、XmlSchemaProviderAttribute属性でマークされていないIXmlSerializable型です。 代わりに、スキーマ生成に GetSchema メソッドを使用します。 このパターンは DataSet 型に使用され、型指定されたデータセットは以前のバージョンの .NET Framework でクラスを派生させますが、現在は廃止され、従来の理由でのみサポートされています。 このパターンに依存せず、常に XmlSchemaProviderAttributeIXmlSerializable 型に適用してください。

IXmlSerializable コンテンツ タイプ

IXmlSerializableを実装し、前に定義したコンテンツ タイプである型のデータ メンバーをシリアル化する場合、シリアライザーはデータ メンバーのラッパー要素を書き込み、WriteXml メソッドに制御を渡します。 WriteXml実装では、ラッパー要素への属性の追加を含む任意の XML を書き込むことができます。 WriteXmlが完了すると、シリアライザーは要素を閉じます。

IXmlSerializableを実装し、前に定義したコンテンツ タイプである型のデータ メンバーを逆シリアル化する場合、デシリアライザーはデータ メンバーのラッパー要素に XML リーダーを配置し、ReadXml メソッドに制御を渡します。 メソッドは、開始タグと終了タグを含む要素全体を読み取る必要があります。 ReadXmlコードが要素が空の場合を処理していることを確認します。 さらに、 ReadXml 実装は、特定の方法で名前が付けられているラッパー要素に依存しないようにする必要があります。 シリアライザーによって選択される名前は異なる場合があります。

たとえば、Object 型のデータ メンバーにIXmlSerializableコンテンツ タイプをポリモーフィックに割り当てることができます。 また、型インスタンスが null になることも許可されます。 最後に、オブジェクト グラフの保持を有効にし、NetDataContractSerializerを使用して、IXmlSerializable型を使用できます。 これらすべての機能では、WCF シリアライザーが特定の属性をラッパー要素にアタッチする必要があります (XML スキーマ インスタンス名前空間では "nil" と "type"、WCF 固有の名前空間では "Id"、"Ref"、"Type"、"Assembly")。

ReadXml を実装するときに無視する属性

ReadXml コードに制御を渡す前に、デシリアライザーは XML 要素を調べ、これらの特殊な XML 属性を検出し、それらに対して動作します。 たとえば、"nil" が true場合、null 値は逆シリアル化され、 ReadXml は呼び出されません。 ポリモーフィズムが検出された場合、要素の内容は別の型であるかのように逆シリアル化されます。 ポリモーフィックに割り当てられた型の ReadXml の実装が呼び出されます。 いずれの場合も、 ReadXml 実装では、これらの特殊な属性はデシリアライザーによって処理されるため、無視する必要があります。

IXmlSerializable コンテンツ タイプのスキーマに関する考慮事項

スキーマと IXmlSerializable コンテンツ タイプをエクスポートするときに、スキーマ プロバイダー メソッドが呼び出されます。 XmlSchemaSetはスキーマ プロバイダー メソッドに渡されます。 このメソッドは、任意の有効なスキーマをスキーマ セットに追加できます。 スキーマ セットには、スキーマのエクスポートが行われる時点で既に認識されているスキーマが含まれています。 スキーマ プロバイダー メソッドは、スキーマ セットに項目を追加する必要がある場合、適切な名前空間を持つ XmlSchema が既にセットに存在するかどうかを判断する必要があります。 その場合、スキーマ プロバイダー メソッドは、既存の XmlSchemaに新しい項目を追加する必要があります。 それ以外の場合は、新しい XmlSchema インスタンスを作成する必要があります。 これは、 IXmlSerializable 型の配列が使用されている場合に重要です。 たとえば、名前空間 "B" で型 "A" としてエクスポートされる IXmlSerializable 型がある場合、スキーマ プロバイダー メソッドが呼び出される時点で、スキーマ セットに "ArrayOfA" 型を保持する "B" のスキーマが既に含まれている可能性があります。

コンテンツ タイプのスキーマ プロバイダー メソッドは、 XmlSchemaSetに型を追加するだけでなく、null 以外の値を返す必要があります。 指定したIXmlSerializable型に使用するスキーマ型の名前を指定するXmlQualifiedNameを返すことができます。 この修飾名は、型のデータ コントラクト名と名前空間としても機能します。 スキーマ プロバイダー メソッドから制御が戻ったときに、スキーマ セットに存在しない型をすぐに返すようにできます。 ただし、関連するすべての型がエクスポートされる (XsdDataContractExporterのすべての関連する型に対して Export メソッドが呼び出され、Schemas プロパティにアクセスされる) までに、その型がスキーマ セットに存在することが予想されます。 関連するすべてのExport呼び出しが行われる前に Schemas プロパティにアクセスすると、XmlSchemaExceptionが発生する可能性があります。 エクスポート プロセスの詳細については、「 クラスからのスキーマのエクスポート」を参照してください。

スキーマ プロバイダー メソッドは、使用する XmlSchemaType を返すこともできます。 型は匿名である場合とそうでない場合があります。 匿名の場合、IXmlSerializable型がデータ メンバーとして使用されるたびに、IXmlSerializable型のスキーマが匿名型としてエクスポートされます。 IXmlSerializable型には、引き続きデータ コントラクト名と名前空間があります。 (これは、「 データ コントラクト名 」の説明に従って決定されます。ただし、 DataContractAttribute 属性を使用して名前をカスタマイズすることはできません)。匿名でない場合は、 XmlSchemaSetのいずれかの型である必要があります。 このケースは、型の XmlQualifiedName を返すのと同じです。

さらに、型のグローバル要素宣言がエクスポートされます。 型に XmlRootAttribute 属性が適用されていない場合、要素の名前と名前空間はデータ コントラクトと同じになり、"nillable" プロパティは true。 これに対する唯一の例外は、スキーマ名前空間 (http://www.w3.org/2001/XMLSchema) です。型のデータ コントラクトがこの名前空間にある場合、対応するグローバル要素は空白の名前空間にあります。これは、スキーマ名前空間に新しい要素を追加することが禁止されているためです。 型に XmlRootAttribute 属性が適用されている場合、グローバル要素宣言は、 ElementNameNamespace 、および IsNullable プロパティを使用してエクスポートされます。 XmlRootAttributeが適用される既定値は、データ コントラクト名、空白の名前空間、および "nillable" がtrueされています。

同じグローバル要素宣言規則が、レガシ データセット型に適用されます。 XmlRootAttributeは、カスタム コードを介して追加されたグローバル要素宣言をオーバーライドできないことに注意してください。スキーマ プロバイダー メソッドを使用してXmlSchemaSetに追加するか、レガシ データセット型のGetSchemaを使用します。

IXmlSerializable 要素型

IXmlSerializable 要素型には、 IsAny プロパティが true に設定されているか、スキーマ プロバイダー メソッドから nullが返されます。

要素型のシリアル化と逆シリアル化は、コンテンツ タイプのシリアル化と逆シリアル化とよく似ています。 ただし、いくつかの重要な違いがあります。

  • WriteXml実装では、1 つの要素 (もちろん複数の子要素を含む可能性があります) を記述することが想定されています。 この 1 つの要素、複数の兄弟要素、または混合コンテンツの外部に属性を書き込むべきではありません。 要素が空の場合があります。

  • ReadXml実装では、ラッパー要素を読み取らてはなりません。 WriteXml生成される 1 つの要素を読み取ることが期待されます。

  • 要素型を定期的にシリアル化する場合 (データ コントラクトのデータ メンバーなど)、シリアライザーは、コンテンツ タイプと同様に、 WriteXmlを呼び出す前にラッパー要素を出力します。 ただし、最上位レベルで要素型をシリアル化する場合、DataContractSerializerまたはNetDataContractSerializerコンストラクターでシリアライザーを構築するときにルート名と名前空間が明示的に指定されていない限り、シリアライザーは通常、書き込みWriteXml要素の周囲にラッパー要素を出力しません。 詳細については、「 シリアル化と逆シリアル化」を参照してください。

  • 構築時にルート名と名前空間を指定せずに最上位レベルで要素型をシリアル化する場合、 WriteStartObjectWriteEndObject は基本的に何も行わず、 WriteObjectContent 呼び出し WriteXml。 このモードでは、シリアル化されるオブジェクトを null できず、ポリモーフィックに割り当てることはできません。 また、オブジェクト グラフの保持を有効にできず、 NetDataContractSerializer を使用できません。

  • 構築時にルート名と名前空間を指定せずに最上位レベルで要素型を逆シリアル化すると、 IsStartObject は要素の先頭が見つかると true を返します。 ReadObject verifyObjectNameパラメーターを true に設定すると、実際にオブジェクトを読み取る前のIsStartObjectと同じように動作します。 ReadObject 次に、 ReadXml メソッドに制御を渡します。

要素の種類に対してエクスポートされるスキーマは、前のセクションで説明した XmlElement 型の場合と同じですが、スキーマ プロバイダー メソッドはコンテンツ タイプと同様に、 XmlSchemaSet にスキーマを追加できます。 要素型で XmlRootAttribute 属性を使用することは許可されず、これらの型に対してグローバル要素宣言は生成されません。

XmlSerializer との違い

IXmlSerializable インターフェイスとXmlSchemaProviderAttribute属性とXmlRootAttribute属性も、XmlSerializerによって認識されます。 ただし、データ コントラクト モデルでのこれらの処理方法にはいくつかの違いがあります。 重要な違いを次の一覧にまとめます。

  • スキーマ プロバイダー メソッドは、 XmlSerializerで使用するには public である必要がありますが、データ コントラクト モデルで使用するためにパブリックである必要はありません。

  • スキーマ プロバイダー メソッドは、データ コントラクト モデルで IsAnytrue されているが、 XmlSerializerでは呼び出されない場合に呼び出されます。

  • コンテンツまたはレガシ データセット型に対して XmlRootAttribute 属性が存在しない場合、 XmlSerializer は空白の名前空間にグローバル要素宣言をエクスポートします。 データ コントラクト モデルでは、使用される名前空間は、通常、前に説明したようにデータ コントラクト名前空間です。

両方のシリアル化テクノロジで使用される型を作成する場合は、これらの違いに注意してください。

IXmlSerializable スキーマのインポート

IXmlSerializable型から生成されたスキーマをインポートする場合、いくつかの可能性があります。

  • 生成されたスキーマは、「データ コントラクト スキーマ リファレンス」の説明に従って、有効な データ コントラクト スキーマである可能性があります。 この場合、スキーマは通常どおりインポートでき、通常のデータ コントラクト型が生成されます。

  • 生成されたスキーマは、有効なデータ コントラクト スキーマではない可能性があります。 たとえば、スキーマ プロバイダー メソッドでは、データ コントラクト モデルでサポートされていない XML 属性を含むスキーマを生成できます。 この場合、スキーマを IXmlSerializable 型としてインポートできます。 このインポート モードは既定ではオンになっていませんが、簡単に有効にすることができます。たとえば、 /importXmlTypes コマンド ライン スイッチを ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) に切り替えます。 詳細については、「 スキーマをインポートしてクラスを生成する」を参照してください。 型インスタンスの XML を直接操作する必要があることに注意してください。 また、より広範なスキーマをサポートする別のシリアル化テクノロジの使用を検討することもできます。 XmlSerializerの使用に関するトピックを参照してください。

  • 新しい型を生成する代わりに、プロキシで既存の IXmlSerializable 型を再利用できます。 この場合、「型を生成するスキーマのインポート」トピックで説明されている参照型機能を使用して、再利用する型を示すことができます。 これは、再利用する型を含むアセンブリを指定する、svcutil.exeでの /reference スイッチの使用に対応します。

XmlSerializer の従来の動作

.NET Framework 4.0 以前では、XmlSerializer は C# コードをファイルに書き込むことで一時的なシリアル化アセンブリを生成しました。 その後、ファイルはアセンブリにコンパイルされました。 この動作により、シリアライザーの起動時間が遅くなるなど、望ましくない結果が生じることがありました。 .NET Framework 4.5 では、コンパイラを使用せずにアセンブリを生成するようにこの動作が変更されました。 一部の開発者は、生成された C# コードを確認したい場合があります。 この従来の動作を使用するように指定するには、次の構成を使用します。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.xml.serialization>
    <xmlSerializer tempFilesLocation='e:\temp\XmlSerializerBug' useLegacySerializerGeneration="true" />
  </system.xml.serialization>
  <system.diagnostics>
    <switches>
      <add name="XmlSerialization.Compilation" value="1" />
    </switches>
  </system.diagnostics>
</configuration>

XmlSerializerがパブリックでない新しいオーバーライドを使用して派生クラスをシリアル化できないなどの互換性の問題が発生した場合は、次の構成を使用して、XMLSerializerレガシ動作に戻すことができます。

<configuration>
  <appSettings>
    <add key="System:Xml:Serialization:UseLegacySerializerGeneration" value="true" />
  </appSettings>
</configuration>

上記の構成の代わりに、.NET Framework 4.5 以降のバージョンを実行しているコンピューターで次の構成を使用できます。

<configuration>
  <system.xml.serialization>
    <xmlSerializer useLegacySerializerGeneration="true"/>
  </system.xml.serialization>
</configuration>

<xmlSerializer useLegacySerializerGeneration="true"/> スイッチは、.NET Framework 4.5 以降のバージョンを実行しているコンピューターでのみ機能します。 上記の appSettings アプローチは、すべての .NET Framework バージョンで機能します。

こちらも参照ください