2012-09-25 31 views
31

Làm cách nào để xóa không gian tên khỏi phản hồi xml dưới đây bằng API Web?Xóa không gian tên trong XML từ ASP.NET Web API

<ApiDivisionsResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Models.Api.Response"> 
<Divisions xmlns:d2p1="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Data.Entities"> 
<d2p1:Page>1</d2p1:Page> 
<d2p1:PageSize>10</d2p1:PageSize> 
<d2p1:Results xmlns:d3p1="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Models.Api.Response.Divisions"/> 
<d2p1:Total>0</d2p1:Total> 
</Divisions> 
</ApiDivisionsResponse> 
+0

Bạn có thể thử một cái gì đó như thế này: http: // stackoverflow.com/questions/29352015/how-can-i-create-custom-xml-namespace-attributes-khi-tiêu thụ-a-legacy-soap-se –

Trả lời

37

Lựa chọn 1 là để chuyển sang sử dụng XmlSerializer trong GlobalConfiguration:

config.Formatters.XmlFormatter.UseXmlSerializer = true; 

Lựa chọn 2 là để trang trí mô hình của bạn với

[DataContract(Namespace="")] 

(và nếu bạn làm như vậy, bạn muốn cần phải trang trí các thành viên với các thuộc tính [DataMember]).

+2

Tôi đã sử dụng UseXmlSerializer và bây giờ nó chỉ sử dụng JSON. –

+4

'[DataContract()]' thuộc tính yêu cầu tham chiếu đến ['System.Runtime.Serialization'] (http://msdn.microsoft.com/en-us/library/kd1dc9w5.aspx) thư viện – Andrew

+0

@MikeFlynn Tôi đã chạy vào cùng một vấn đề. Nếu XmlSerializer không thể tuần tự hóa đối tượng, nó sẽ thử Json. Không thực sự là một hành vi mặc định mong đợi IMO. Đặc biệt khi NetDataContractSerializer ném lỗi. – CDeutsch

20

Nếu bạn sẵn sàng trang trí cho mô hình của mình bằng XmlRoot, đây là cách hay để thực hiện. Giả sử bạn có một chiếc xe có cửa ra vào. Cấu hình WebAPI mặc định sẽ trở lại một cái gì đó như:

<car 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <doors> 
     <door> 
      <color>black</color> 
     </door> 
    </doors> 
</car> 

Đây là những gì bạn muốn:

<car> 
    <doors> 
     <door> 
      <color>black</color> 
     </door> 
    </doors> 
</car> 

Dưới đây là mô hình:

[XmlRoot("car")] 
public class Car 
{ 
    [XmlArray("doors"), XmlArrayItem("door")] 
    public Door[] Doors { get; set; } 
} 

Những gì bạn phải làm là tạo ra một XmlFormatter tùy chỉnh sẽ có một không gian tên trống nếu không có không gian tên được định nghĩa trong thuộc tính XmlRoot. Vì một số lý do, trình định dạng mặc định luôn thêm hai không gian tên mặc định.

public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter 
{ 
    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, 
              TransportContext transportContext) 
    { 
     try 
     { 
      var xns = new XmlSerializerNamespaces(); 
      foreach (var attribute in type.GetCustomAttributes(true)) 
      { 
       var xmlRootAttribute = attribute as XmlRootAttribute; 
       if (xmlRootAttribute != null) 
       { 
        xns.Add(string.Empty, xmlRootAttribute.Namespace); 
       } 
      } 

      if (xns.Count == 0) 
      { 
       xns.Add(string.Empty, string.Empty); 
      } 

      var task = Task.Factory.StartNew(() => 
       { 
        var serializer = new XmlSerializer(type); 
        serializer.Serialize(writeStream, value, xns); 
       }); 

      return task; 
     } 
     catch (Exception) 
     { 
      return base.WriteToStreamAsync(type, value, writeStream, content, transportContext); 
     } 
    } 
} 

Điều cuối cùng cần làm là thêm trình định dạng mới trong WebApiContext. Hãy chắc chắn xóa (hoặc xóa) XmlMediaTypeFormatter cũ

public static class WebApiContext 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     ... 
     config.Formatters.Clear(); 
     config.Formatters.Add(new CustomNamespaceXmlFormatter{UseXmlSerializer=true}); 
     ... 
    } 
} 
+0

Xin chào, tôi thích giải pháp của bạn, tuy nhiên tôi không nhận được điểm trong việc gọi thực hiện cơ sở nếu một ngoại lệ xảy ra. Bạn có thể giải thích tại sao bạn đã làm điều đó? Cảm ơn. –

+0

Thật không may, nó đã được một thời gian kể từ khi tôi đã hack trên này. Từ những gì tôi nhớ, tôi nghĩ rằng nó được dự định như một cách đơn giản bỏ qua việc loại bỏ các không gian tên XML và chỉ đơn giản gọi định dạng "bình thường". – pobed2

+3

Công việc tuyệt vời. Tuy nhiên, một lời cảnh báo: 'config.Formatters.Add (new IgnoreNamespacesXmlMediaTypeFormatter {UseXmlSerializer = true});' nên được đặt khác trong khi gửi dữ liệu 'POST',' FromBody' sẽ không thể 'serialize' được. –

5

Tôi thích câu trả lời của pobed2. Nhưng tôi cần CustomNamespaceXmlFormatter để cho phép tôi chỉ định không gian tên gốc mặc định sẽ được sử dụng khi thuộc tính XmlRoot bị thiếu cũng khi nó hiện diện và không có giá trị trong thuộc tính Namespace (nghĩa là thuộc tính được sử dụng để đặt chỉ tên phần tử gốc). Vì vậy, tôi đã tạo ra một phiên bản cải tiến, ở đây nó được trong trường hợp nó rất hữu ích cho ai đó:

public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter 
{ 
    private readonly string defaultRootNamespace; 

    public CustomNamespaceXmlFormatter() : this(string.Empty) 
    { 
    } 

    public CustomNamespaceXmlFormatter(string defaultRootNamespace) 
    { 
     this.defaultRootNamespace = defaultRootNamespace; 
    } 

    public override Task WriteToStreamAsync(
     Type type, 
     object value, 
     Stream writeStream, 
     HttpContent content, 
     TransportContext transportContext) 
    { 
     var xmlRootAttribute = type.GetCustomAttribute<XmlRootAttribute>(true); 
     if(xmlRootAttribute == null) 
      xmlRootAttribute = new XmlRootAttribute(type.Name) 
      { 
       Namespace = defaultRootNamespace 
      }; 
     else if(xmlRootAttribute.Namespace == null) 
      xmlRootAttribute = new XmlRootAttribute(xmlRootAttribute.ElementName) 
      { 
       Namespace = defaultRootNamespace 
      }; 

     var xns = new XmlSerializerNamespaces(); 
     xns.Add(string.Empty, xmlRootAttribute.Namespace); 

     return Task.Factory.StartNew(() => 
     { 
      var serializer = new XmlSerializer(type, xmlRootAttribute); 
      serializer.Serialize(writeStream, value, xns); 
     }); 
    } 
} 
+0

Như được giải thích trong [câu trả lời] (https://stackoverflow.com/a/23897411/3744182), để tránh rò rỉ bộ nhớ nghiêm trọng, một 'XmlSerializer' được xây dựng với một hàm tạo không mặc định phải được lưu trữ và tái sử dụng tĩnh. Xem thêm [tài liệu] (https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx#Remarks) có trạng thái * Nếu bạn sử dụng bất kỳ hàm tạo nào khác, nhiều phiên bản của cùng một hội đồng được tạo ra và không bao giờ dỡ bỏ, kết quả trong một rò rỉ bộ nhớ và hiệu suất kém. ... Nếu không, bạn phải lưu trữ bộ nhớ trong một Hashtable, * – dbc

3

Trong dự án mà giữ mô hình phản ứng đi đến Properties/AssemblyInfo.cs

Thêm

using System.Runtime.Serialization;

và tại phần dưới cùng thêm

[assembly: ContractNamespace("", ClrNamespace = "Project.YourResponseModels")] 

Thay thế Project.YourResponseModels bằng không gian tên thực tế nơi mô hình phản hồi được đặt. Bạn cần phải thêm một mỗi namespace

+0

Xin chào, trông giống như cách giải quyết khác và nên được coi là thực hành không tốt. Ví dụ, trong trường hợp cấu trúc lại dự án, 'YourResponseModels' của bạn có thể được chuyển từ không gian tên' Project.YourResponseModels' sang 'Project.AnotherPlace.YourResponseModels'. Mọi người nên ghi nhớ nó trong trường hợp tái cấu trúc. –

+0

Đây là cách tiếp cận cũ để làm cho các cơ quan XML sạch cho mục đích Web API, vì vậy nó sẽ không quan trọng khi bạn refactor, mã và thực thể được cấu trúc như bạn muốn, chỉ serializer sẽ xử lý bất cứ điều gì. Đối với tái cơ cấu tôi không nghĩ AssemblyInfo.cs sẽ chứa nhiều hơn 10-20 dòng, vẫn dễ dàng để duy trì. Ai sẽ sử dụng XML ngày này? Với WebAPI 2.0+ tất cả điều này được giải quyết, và JSON nên là định dạng duy nhất cho aps hiện đại. Nếu bạn giao diện với các hệ thống cũ, bạn vẫn có thể giữ các không gian tên XML tại chỗ. –

-2

này hoạt động hoàn hảo

public ActionResult JsonAction(string xxx) 
{ 
    XmlDocument xmlDoc2 = new XmlDocument(); 
    xmlDoc2.Load(xmlStreamReader); 

    XDocument d = XDocument.Parse(optdoc2.InnerXml); 
    d.Root.Attributes().Where(x => x.IsNamespaceDeclaration).Remove(); 

    foreach (var elem in d.Descendants()) 
    elem.Name = elem.Name.LocalName; 

    var xmlDocument = new XmlDocument(); 
    xmlDocument.Load(d.CreateReader()); 

    var jsonText = JsonConvert.SerializeXmlNode(xmlDocument); 
    return Content(jsonText); 
} 
Các vấn đề liên quan