简体   繁体   English

调整MVC 4 WebApi XmlSerializer以丢失nameSpace

[英]Adjust MVC 4 WebApi XmlSerializer to lose the nameSpace

I'm working on a MVC WebAPI, that uses EF with POCO classes for storage. 我正在开发一个MVC WebAPI,它使用EF和POCO类进行存储。 What I want to do is get rid of the namespace from the XML, so that the endpoints would return and accept xml objects without it. 我想要做的是从XML中删除命名空间,以便端点返回并接受没有它的xml对象。 (json works just fine) (json工作得很好)

<ACCOUNT xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Platform.Services.AccountService.Data">
<id>22</id>
<City i:nil="true"/>
<Country i:nil="true"/>
<Email>testas@email.com</Email>
<Phone i:nil="true"/> ...

I would like this to work 我希望这能奏效

 <ACCOUNT>
    <id>22</id>
    <City i:nil="true"/>
    <Country i:nil="true"/>
    <Email>testas@email.com</Email>
    <Phone i:nil="true"/> ...

Hopefully without having to decorate the POCO's with a bunch of attributes. 希望无需用一堆属性来装饰POCO。

I've set up a test solution for this, and indeed, these methods are beeing hit (must be some other problem in my system). 我已经为此设置了一个测试解决方案,实际上,这些方法很受欢迎(必须是我系统中的其他一些问题)。 Anyways - the result that I get using this solutions is this: 无论如何 - 我使用这个解决方案的结果是:

<ArrayOfAccount>
<Account>
<id>22</id>
<name>TestAcc</name>
<parentid xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" d3p1:nil="true"/>
<status_id xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" d3p1:nil="true"/>
<Email>Test@Test.com</Email>
</Account>
</ArrayOfAccount>

Got rid of the schema on top, but the properties are now messed up :( Here's a link to a sample project 摆脱了顶部的架构,但现在搞砸了属性:(这是一个示例项目的链接

This answer here is spot on the mark Remove namespace in XML from ASP.NET Web API .\\ 这里的答案是从ASP.NET Web API中标记删除XML中的命名空间

If you don't want to decorate your POCO's at all use the 1st option: 如果您根本不想装饰您的POCO,请使用第一个选项:

config.Formatters.XmlFormatter.UseXmlSerializer = true;

If you use option 2, you may need to add a reference to System.Runtime.Serialization 如果使用选项2,则可能需要添加对System.Runtime.Serialization的引用

Assuming a post like this with Accept set correct: 假设这样的帖子接受设置正确:

GET http:// ANY OLD SERVER/api/foos/5 Accept: application/xml GET http:// ANY OLD SERVER / api / foos / 5接受:application / xml

Controller 调节器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Web.Http;

namespace CutomXmlFormater.Controllers
{
//[DataContract(Namespace = "")]
public class Foo
{
    //[DataMember]
    public string Bar { get; set; }
}

public class FoosController : ApiController
{
    // GET api/foos/5
    public Foo Get(int id)
    {
        return new Foo() { Bar = "Test" };
    }
}

} }

Config (App_Start/WebApiConfig) 配置(App_Start / WebApiConfig)

//(Use this is you don't go the data contact and model annotation route)
config.Formatters.XmlFormatter.UseXmlSerializer = true;

Result 结果

Either (With annotation and data contact): (带注释和数据联系):

<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Bar>Test</Bar></Foo>

Or (with XML serialiser route): 或者(使用XML序列化程序路由):

<Foo xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Bar>Test</Bar></Foo>

Maybe you could try with this: 也许你可以试试这个:

Replace default XmlFormatter with your own: 将默认的XmlFormatter替换为您自己的:

GlobalConfiguration.Configuration.Formatters.Add(new CustomXmlFormatter());
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

And impement it using XmlSerializer, with specifying empty namespace during serialization, like this: 并使用XmlSerializer强制它,在序列化期间指定空命名空间,如下所示:

public CustomXmlFormatter()
{
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
    Encoding = new UTF8Encoding(false, true);
}

protected override bool CanReadType(Type type)
{
    if (type == (Type)null)
        throw new ArgumentNullException("type");

    if (type == typeof(IKeyValueModel))
        return false;

    return true;
}

protected override bool CanWriteType(Type type)
{
    return true;
}

protected override Task OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext)
{
    return Task.Factory.StartNew(() =>
            {
                using (var streamReader = new StreamReader(stream, Encoding))
                {
                    var serializer = new XmlSerializer(type);
                    return serializer.Deserialize(streamReader);
                }
            });
}

protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, System.Net.TransportContext transportContext)
{
    var serializer = new XmlSerializer(type);
    return Task.Factory.StartNew(() =>
            {
                using (var streamWriter = new StreamWriter(stream, Encoding))
                {
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("", "");
                    serializer.Serialize(streamWriter, value, ns);
                }
            });
    }
}

Custom XML serializer was stolen from here , and as such is untested. 自定义XML序列化程序从这里被盗,因此未经测试。

This should serialize objects w/o writing the namespace. 这应该序列化没有编写命名空间的对象。 I'm not sure if it will work OOTB for deserialization, you'd may have to experiment with XmlSerializer.Deserialize() overload that provides events and handle UnknownElement or UnknownNode event. 我不确定它是否可以用于反序列化OOTB,你可能不得不尝试提供事件并处理UnknownElementUnknownNode事件的XmlSerializer.Deserialize() 重载

It's been awhile since I messed with MVC 4, but we ended up replacing the default formatter with the XmlSerializer like so: 自从我搞砸MVC 4以来已经有一段时间了,但我们最终用XmlSerializer替换了默认的格式化程序,如下所示:

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = GetSerializeSettings();
        GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
    }

    internal JsonSerializerSettings GetSerializeSettings()
    {
        return new JsonSerializerSettings
                           {
                               Formatting = Formatting.Indented,
                               ContractResolver = new CamelCasePropertyNamesContractResolver(),
                               Converters = new List<JsonConverter> { new IsoDateTimeConverter() }
                           };
    }

This might help... I know we also customized the property names using attributes on the POCOs which you said you don't want to do, but that's because we wanted them to be camel-cased. 这可能会有所帮助......我知道我们还使用你说你不想做的POCO上的属性来定制属性名称,但那是因为我们希望它们是驼峰式的。

I have customized Boris's answer to MVC Webapi 5. Use either of the following http headers render the result using the CustomFormatter: 我已经定制了Boris对MVC Webapi 5的回答。使用以下任一http头使用CustomFormatter渲染结果:

accept: application/xml 接受:application / xml

accept: text/xml 接受:text / xml

WebApiConfig.cs : WebApiConfig.cs:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        GlobalConfiguration.Configuration.Formatters.Add(new CustomXmlFormatter());
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
    }
}

CustomXmlFormatter.cs : CustomXmlFormatter.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml.Serialization;

namespace Custom.Formatter
{
    public class CustomXmlFormatter: MediaTypeFormatter
    {
        private  UTF8Encoding encoder;

        public CustomXmlFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
            encoder = new UTF8Encoding(false, true);
        }

        public override bool CanReadType(Type type)
        {
            if (type == (Type)null)
                throw new ArgumentNullException("type");

            //Type filtering
            if (type == typeof(SendEmailMessageResponse) || type == typeof(SendSmsMessageResponse))
                return true;
            else
                return false;
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger)
        {
            return Task.Factory.StartNew(() =>
                    {
                        using (var streamReader = new StreamReader(stream, encoder))
                        {
                            var serializer = new XmlSerializer(type);
                            return serializer.Deserialize(streamReader);
                        }
                    });
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream stream,    HttpContent content, TransportContext transportContext)
        {
            var serializer = new XmlSerializer(type);
            return Task.Factory.StartNew(() =>
                    {
                        using (var streamWriter = new StreamWriter(stream, encoder))
                        {
                            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                            ns.Add("", "");
                            serializer.Serialize(streamWriter, value, ns);
                        }
                    });
        }
    }
}

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

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