【问题标题】:Web api - xml prefixesWeb api - xml 前缀
【发布时间】:2017-06-28 06:04:29
【问题描述】:

美好的一天,通过使用 web api,我需要获得以下 xml 响应(带有所有前缀):

  <test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ai="www.something.org">
    <ai:name>Ann</name>
    </test>

这是类:

[XmlRoot(ElementName = "test")]
    public class Test
    {
        [XmlAttribute(AttributeName = "ai")]
        public const string Ai = "www.something.org";
        [XmlElement(ElementName = "name",Namespace = Ai)]
        public string Name { get; set; }

        public Test(string name)
        {
            Name = name;
        }
        public Test() { }
    }

问题是如果你自己使用xmlSerializer,你可以使用

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("ai", "www.something.org");

但这里的序列化是由 web api 请求本身进行的:

[HttpGet]
[Route("test")]
public Test Testing()
{
 return new Test("Ann");
}

我得到的是没有 ai 属性,也没有命名空间的前缀。

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <name xmlns="www.something.org">
    Ann
    </name>

编辑。如果我覆盖 XmlMediaTypeFormatter,我会得到正确的 xml 响应:

public class CustomXmlFormatter : XmlMediaTypeFormatter
    {
        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
            TransportContext transportContext)
        {
            var serializer = new XmlSerializer(type);
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("ai", "www.something.org");

            return Task.Factory.StartNew(() =>
            {
                using (var streamWriter = new StreamWriter(writeStream, Encoding.UTF8))
                {
                    serializer.Serialize(streamWriter, value,ns);
                }
            });
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        }
    }

但是如果我有 2 个请求,每个请求都有不同的命名空间 - 但是这个格式化程序将始终显示它们。有没有办法删除未使用的命名空间?

【问题讨论】:

    标签: c# asp.net-web-api xml-serialization


    【解决方案1】:

    如果您像这样定义自定义 xml 格式化程序:

    public class CustomXmlFormatter : XmlMediaTypeFormatter
    {
        public XmlSerializerNamespaces Namespaces { get; }
    
        public CustomXmlFormatter()
        {
            Namespaces = new XmlSerializerNamespaces();
        }
    
        public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            var serializer = new XmlSerializer(type);
    
            var xmlWriter = new XmlTextWriter(writeStream, Encoding.UTF8)
            {
                Namespaces = true
            };
    
            serializer.Serialize(xmlWriter, value, Namespaces);
    
            return Task.FromResult(true);
        }
    }
    

    然后您可以创建一个IControllerConfiguration 使用此格式化程序并添加您的命名空间:

    public class MyControllerConfig : Attribute, IControllerConfiguration
    {
        private readonly string _prefix;
        private readonly string _ns;
    
        public MyControllerConfig(string prefix, string ns)
        {
            _prefix = prefix;
            _ns = ns;
        }
    
        public void Initialize(HttpControllerSettings controllerSettings,
                                HttpControllerDescriptor controllerDescriptor)
        {
            var formatter = new CustomXmlFormatter { UseXmlSerializer = true };
            formatter.Namespaces.Add(_prefix, _ns);
            controllerSettings.Formatters.Clear();
            controllerSettings.Formatters.Add(formatter);
        }
    }
    

    然后在你的控制器上使用它:

    [MyControllerConfig("ai", Ns.Ai)]
    public class MyController : ApiController
    {
        [HttpGet]
        [Route("test")]
        public IHttpActionResult Testing()
        {
            return Ok(new Test("Ann"));
        }
    }
    
    public class Ns
    {
        public const string Ai = "www.something.org";
    }
    
    [XmlRoot(ElementName = "test")]
    public class Test
    {
        [XmlElement(ElementName = "name", Namespace = Ns.Ai)]
        public string Name { get; set; }
    
        public Test(string name)
        {
            Name = name;
        }
        public Test() { }
    }
    

    【讨论】:

    • Ty,这很有帮助。最后一个问题 - 我不能将它用于名称空间的 List,而不仅仅是一个吗?我的意思是我应该在哪里声明这个列表,太愚蠢了=\
    • 不幸的是,您不能将列表或数组作为属性的构造函数参数。但是,您可以为一组命名空间创建一个 IControllerConfiguration-attribute,然后为另一组命名空间创建一个不同的 IControllerConfiguration-attribute。这样解释好吗?
    • @peco 不错的帖子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 2022-12-07
    相关资源
    最近更新 更多