Adjust MVC 4 WebApi XmlSerializer to lose the nameSpace

前端 未结 4 1831
温柔的废话
温柔的废话 2020-12-05 15:28

I\'m working on a MVC WebAPI, that uses EF with POCO classes for storage. What I want to do is get rid of the namespace from the XML, so that the endpoints would return and

相关标签:
4条回答
  • 2020-12-05 16:06

    I have customized Boris's answer to MVC Webapi 5. Use either of the following http headers render the result using the CustomFormatter:

    accept: application/xml

    accept: text/xml

    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 :

    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);
                            }
                        });
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-05 16:10

    It's been awhile since I messed with MVC 4, but we ended up replacing the default formatter with the XmlSerializer like so:

    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.

    0 讨论(0)
  • 2020-12-05 16:29

    This answer here is spot on the mark Remove namespace in XML from ASP.NET Web API.\

    If you don't want to decorate your POCO's at all use the 1st option:

    config.Formatters.XmlFormatter.UseXmlSerializer = true;
    

    If you use option 2, you may need to add a reference to System.Runtime.Serialization

    Assuming a post like this with Accept set correct:

    GET http:// ANY OLD SERVER/api/foos/5 Accept: 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)

    //(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):

    <Foo xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Bar>Test</Bar></Foo>
    
    0 讨论(0)
  • 2020-12-05 16:30

    Maybe you could try with this:

    Replace default XmlFormatter with your own:

    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:

    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.

    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.

    0 讨论(0)
提交回复
热议问题