13

ストレージに POCO クラスで EF を使用する MVC WebAPI に取り組んでいます。私がやりたいのは、XML から名前空間を取り除くことです。これにより、エンドポイントはそれなしで xml オブジェクトを返し、受け入れることができます。(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"/> ...

これを機能させたい

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

うまくいけば、POCO をたくさんの属性で装飾する必要がなくなります。

このためのテスト ソリューションをセットアップしましたが、実際、これらのメソッドはヒットしています (私のシステムには別の問題があるはずです)。とにかく - このソリューションを使用して得た結果は次のとおりです。

<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>

上部のスキーマを削除しましたが、プロパティが台無しになりました:(サンプルプロジェクトへのリンクは次のとおりです

4

4 に答える 4

13

ここでのこの回答は、ASP.NET Web API から XML の名前空間を削除するというマークにスポットを当てています。\

POCO をまったく装飾したくない場合は、最初のオプションを使用します。

config.Formatters.XmlFormatter.UseXmlSerializer = true;

オプション 2 を使用する場合は、への参照を追加する必要がある場合があります。System.Runtime.Serialization

Acceptが正しく設定された次のような投稿を想定します。

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

コントローラ

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

}

構成 (App_Start/WebApiConfig)

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

結果

いずれか (注釈とデータ コンタクトあり):

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

または (XML シリアライザー ルートを使用):

<Foo xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Bar>Test</Bar></Foo>
于 2012-10-01T09:59:31.357 に答える
6

多分あなたはこれで試すことができます:

デフォルトの XmlFormatter を独自のものに置き換えます。

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

次のように、シリアル化中に空の名前空間を指定して、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);
                }
            });
    }
}

カスタム XML シリアライザーはhereから盗まれたため、テストされていません。

これにより、名前空間を書き込まずにオブジェクトをシリアル化する必要があります。逆シリアル化のためにOOTBで機能するかどうかはわかりません。イベントを提供し、 UnknownElementまたはUnknownNodeイベントを処理XmlSerializer.Deserialize() するオーバーロードを試してみる必要があるかもしれません。

于 2012-09-27T09:39:42.880 に答える
1

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

これは役立つかもしれません...あなたがやりたくないと言ったPOCOの属性を使用してプロパティ名をカスタマイズしたことも知っていますが、それはそれらをキャメルケースにしたかったからです。

于 2012-10-05T12:50:06.600 に答える
0

MVC Webapi 5 に対する Boris の回答をカスタマイズしました。次のいずれかの http ヘッダーを使用して、CustomFormatter を使用して結果をレンダリングします。

受け入れる: アプリケーション/xml

受け入れる: テキスト/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);
                        }
                    });
        }
    }
}
于 2014-02-19T05:20:16.140 に答える