5

私は現在、JSON と共にエンドポイントから XML を出力する必要があるプロジェクトに取り組んでいます。私は次のモデルを持っています:

[DataContract(Namespace="http://www.yale.edu/tp/cas")]
[XmlType("serviceResponse")]
[XmlRoot(Namespace="http://www.yale.edu/tp/cas")]
public class ServiceResponse
{
    [XmlElement("authenticationSuccess")]
    public AuthenticationSuccess Success { get; set; }

    [XmlElement("authenticationFailure")]
    public AuthenticationFailure Failure { get; set; }
}

success が null でない場合、出力は次のようになります。

<serviceResponse>
<authenticationSuccess />
</serviceResponse>

ここで、明らかに、要素が含まれるように指定した名前空間にプレフィックスが割り当てられていないことがわかります。私の問題は、メディア フォーマッタを使用して MVC4 に名前空間プレフィックスを追加する場所が見つからないことです。global.asax に次のものがあります。

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
GlobalConfiguration.Configuration.Formatters.XmlFormatter.RemoveSerializer(typeof(Models.ServiceResponse));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer(typeof(Models.ServiceResponse), new Infrastructure.NamespaceXmlSerializer(typeof(Models.ServiceResponse)));

XmlSerializer に基づくカスタム シリアライザーを作成して、書き込み要求をインターセプトし、そこに名前空間リストを追加しようとしました。このメソッドの問題は、現在、すべてのオーバーライド可能なメソッド内にブレークポイントがあり、シリアライズ時にそれらのいずれもトリップされないため、シリアライザーが使用されていないと思われることです。

私がやりたいことを達成するための組み込みの方法はありますか、それともオブジェクトをシリアル化するときに名前空間を渡すために XmlMediaTypeFormatter を再実装するのに行き詰まっていますか?

4

1 に答える 1

4

フォローアップの回答として:私にとって最も簡単な解決策は、自分で書くことでしたXmlMediaTypeFormatter。結局のところ、私が思っていたほど威圧的ではありませんでした。

public class NamespacedXmlMediaTypeFormatter : XmlMediaTypeFormatter 
{
    const string xmlType = "application/xml";
    const string xmlType2 = "text/xml";

    public XmlSerializerNamespaces Namespaces { get; private set; }

    Dictionary<Type, XmlSerializer> Serializers { get; set; }

    public NamespacedXmlMediaTypeFormatter()
        : base()
    {
        this.Namespaces = new XmlSerializerNamespaces();
        this.Serializers = new Dictionary<Type, XmlSerializer>();
    }

    public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
    {
        lock (this.Serializers)
        {
            if (!Serializers.ContainsKey(type))
            {
                var serializer = new XmlSerializer(type);
                //we add a new serializer for this type
                this.Serializers.Add(type, serializer);
            }
        }

        return Task.Factory.StartNew(() =>
        {
            XmlSerializer serializer;
            lock (this.Serializers)
            {
                serializer = Serializers[type];
            }

            var xmlWriter = new XmlTextWriter(writeStream, Encoding.UTF8);
            xmlWriter.Namespaces = true;
            serializer.Serialize(xmlWriter, value, this.Namespaces);
        });
    }
}

要点としてのフォーマッターは次のとおりです。https://gist.github.com/kcuzner/eef239003d4f99dfacea

フォーマッタは、 が使用する を公開するXmlSerializerNamespacesことで機能XmlSerializerします。このようにして、必要に応じて任意の名前空間を追加できます。

私の最上位モデルは次のようになります。

[XmlRoot("serviceResponse", Namespace="http://www.yale.edu/tp/cas")]
public class ServiceResponse
{
    [XmlElement("authenticationSuccess")]
    public CASAuthenticationSuccess Success { get; set; }

    [XmlElement("authenticationFailure")]
    public CASAuthenticationFailure Failure { get; set; }
}

Global.asaxのフォーマッターをリストの一番上に配置するために、次を追加しました。

var xmlFormatter = new Infrastructure.NamespacedXmlMediaTypeFormatter();
xmlFormatter.Namespaces.Add("cas", "http://www.yale.edu/tp/cas");
GlobalConfiguration.Configuration.Formatters.Insert(0, xmlFormatter);

フォーマッタを追加し、属性が適切に設定されていることを確認した後、XML は適切に名前空間化されました。

私の場合、にcasリンクする名前空間を追加する必要がありましたhttp://www.yale.edu/tp/casAddこれを使用している他の人は、ネームスペースを追加して、心のコンテンツへの呼び出しを変更/複製するだけです。

于 2014-10-20T22:53:00.867 に答える