简体   繁体   English

ASP.NET Web API中的XML命名空间

[英]XML Namespaces in ASP.NET Web API

I am currently working on a project that requires me to output XML from its endpoints along with JSON. 我目前正在开发一个项目,要求我从端点和JSON输出XML。 I have the following model: 我有以下型号:

[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; }
}

The output is as follows when success is not null: 当success不为null时,输出如下:

<serviceResponse>
<authenticationSuccess />
</serviceResponse>

Now, I can see that obviously, I don't have a prefix assigned to the namespace I told the elements to be a part of. 现在,我可以看到,显然,我没有为命名空间分配前缀,我告诉元素是其中的一部分。 My issue is that I cannot find a place to add the namespace prefixes in MVC4 using the media formatter. 我的问题是我找不到使用媒体格式化程序在MVC4中添加名称空间前缀的地方。 I have the following in my global.asax: 我在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)));

I made a custom serializer based on XmlSerializer in an attempt to intercept the writing request and tack the namespace list on there. 我创建了一个基于XmlSerializer的自定义序列化程序,试图拦截写入请求并在那里添加命名空间列表。 The issue with this method is that right now I have breakpoints inside every overrideable method and none of them are tripped when serializing which leads me to believe that my serializer isn't being used. 这个方法的问题是,现在我在每个可重写方法中都有断点,并且在序列化时没有一个断点导致我相信我的序列化器没有被使用。

Is there some built in way to accomplish what I want to do or am I stuck re-implementing the XmlMediaTypeFormatter to pass in namespaces when it serializes objects? 是否有一些内置的方法来完成我想要做的事情,或者我是否在重新实现XmlMediaTypeFormatter以在序列化对象时传入命名空间?

As a followup answer: The easiest solution for me was to write my own XmlMediaTypeFormatter . 作为后续答案:对我来说最简单的解决方案是编写自己的XmlMediaTypeFormatter As it turns out, its not nearly as intimidating as I thought. 事实证明,它并不像我想象的那样令人生畏。

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);
        });
    }
}

Here is the formatter as a gist: https://gist.github.com/kcuzner/eef239003d4f99dfacea 以下是格式化程序: https//gist.github.com/kcuzner/eef239003d4f99dfacea

The formatter works by exposing the XmlSerializerNamespaces that the XmlSerializer is going to use. 该格式的工作原理是暴露XmlSerializerNamespacesXmlSerializer是要使用。 This way I can add arbitrary namespaces as needed. 这样我就可以根据需要添加任意名称空间。

My top model looks as follows: 我的顶级模型如下:

[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; }
}

In my Global.asax I added the following to place my formatter on the top of the list: 在我的Global.asax我添加了以下内容以将格式化程序放在列表顶部:

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

After adding the formatter and making sure my attributes were set up properly, my XML was properly namespaced. 添加格式化程序并确保我的属性设置正确后,我的XML被正确命名。

In my case, I needed to add the cas namespace linking to http://www.yale.edu/tp/cas . 在我的例子中,我需要添加链接到http://www.yale.edu/tp/cascas命名空间。 For others using this, just change/replicate the Add call to your heart's content adding namespaces. 对于使用此功能的其他人,只需将Add调用更改/复制到心脏内容添加命名空间即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM