2011-07-13 10 views
1

リストの形のかなり大量のデータを受け入れて返すことができるWCFサービスがあります。<リスト >。WCF出力で重複するxmlns宣言を削除する

<d:ArrayOfanyType> 
    <d:anyType i:type="e:string" xmlns:e="http://www.w3.org/2001/XMLSchema">PJ123</d:anyType> 
    <d:anyType i:type="e:double" xmlns:e="http://www.w3.org/2001/XMLSchema">2</d:anyType> 
    <d:anyType i:type="e:string" xmlns:e="http://www.w3.org/2001/XMLSchema">216565</d:anyType> 
    <d:anyType i:type="e:dateTime" xmlns:e="http://www.w3.org/2001/XMLSchema">1993-09-10T00:00:00</d:anyType> 
    <d:anyType i:type="e:string" xmlns:e="http://www.w3.org/2001/XMLSchema">Timesheet W/E 11/9/93 Franklin</d:anyType> 
    <d:anyType i:type="e:string" xmlns:e="http://www.w3.org/2001/XMLSchema">CONSULT OF</d:anyType> 
    <d:anyType i:type="e:double" xmlns:e="http://www.w3.org/2001/XMLSchema">25</d:anyType> 
    <d:anyType i:type="e:double" xmlns:e="http://www.w3.org/2001/XMLSchema">0</d:anyType> 
    <d:anyType i:type="e:double" xmlns:e="http://www.w3.org/2001/XMLSchema">25</d:anyType> 
    </d:ArrayOfanyType> 

したがって、各列のすべての値が大きく、メッセージのサイズが増加定義された「E」の名前空間を有している:私の問題は、典型的な行の出力は次のように見えるということです。私はこれの背後にある理由は、DataContractSerializerは2つのパスを作る必要はありませんが、それは多大なメッセージサイズを犠牲にして少し処理性能を得るために余裕があるように見えることです。私はデータ構造をどのように変更できるか考えましたが、フィールドは実際には何でもあり、<anyType>要素の使用を避けることはできません。

WCFパイプラインを傍受し、これらの名前空間宣言を削除/再編成する方法を知っている人はいますか?

+0

メッセージのサイズがまったく問題ない場合はどうすればよいですか?パフォーマンスに影響しなかった場合はどうなりますか?その場合に余分な名前空間宣言が気になるでしょうか? –

+0

WCFは、[メッセージの書式設定を許可します](http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageformatter.aspx)には当てはまりますが、オーバーヘッドが発生していますこの最適化を実行する。この最適化は、維持するコードが増えたことを除いて、ゼロサムゲームと思われます。 –

+0

ジョン、私はあなたがその質問にどこに行くのかはかなり分かっていませんが...はい、私はまだ少し気になります。私はすでにHTTP圧縮を使用しているので、実際にはおそらくそれを処理していますが、その原則です! ;) – mackie

答えて

2

カスタムエンコーダを使用すると、その時点で必要なだけXMLを再生できます。ジョン・サンダースが指摘するように、これは(おそらく重要な)パフォーマンス・ヒットを招くが、確かにうまくいく。下のコードは、あなたがそれをどうやってやるのかを示しています。

public class StackOverflow_6681219 
{ 
    [ServiceContract] 
    public interface ITest 
    { 
     [OperationContract] 
     List<List<object>> GetData(); 
    } 
    public class Service : ITest 
    { 
     public List<List<object>> GetData() 
     { 
      return new List<List<object>> 
      { 
       new List<object> 
       { 
        "PJ123", 
        2.0, 
        "216565", 
        new DateTime(1993, 9, 10), 
        "Timesheet W/E 11/9/93 Franklin", 
        "CONSULT OF", 
        25.0, 
        0.0, 
        25.0 
       } 
      }; 
     } 
    } 
    class MyEncodingBindingElement : MessageEncodingBindingElement 
    { 
     MessageEncodingBindingElement inner; 
     public MyEncodingBindingElement(MessageEncodingBindingElement inner) 
     { 
      this.inner = inner; 
     } 

     public override MessageEncoderFactory CreateMessageEncoderFactory() 
     { 
      return new MyEncoderFactory(this.inner.CreateMessageEncoderFactory()); 
     } 

     public override MessageVersion MessageVersion 
     { 
      get { return this.inner.MessageVersion; } 
      set { this.inner.MessageVersion = value; } 
     } 

     public override BindingElement Clone() 
     { 
      return new MyEncodingBindingElement(this.inner); 
     } 

     public override bool CanBuildChannelListener<TChannel>(BindingContext context) 
     { 
      return context.CanBuildInnerChannelListener<TChannel>(); 
     } 

     public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) 
     { 
      context.BindingParameters.Add(this); 
      return context.BuildInnerChannelListener<TChannel>(); 
     } 

     class MyEncoderFactory : MessageEncoderFactory 
     { 
      MessageEncoderFactory inner; 
      public MyEncoderFactory(MessageEncoderFactory inner) 
      { 
       this.inner = inner; 
      } 

      public override MessageEncoder Encoder 
      { 
       get { return new MyEncoder(this.inner.Encoder); } 
      } 

      public override MessageVersion MessageVersion 
      { 
       get { return this.inner.MessageVersion; } 
      } 
     } 

     class MyEncoder : MessageEncoder 
     { 
      MessageEncoder inner; 
      public MyEncoder(MessageEncoder inner) 
      { 
       this.inner = inner; 
      } 

      public override string ContentType 
      { 
       get { return this.inner.ContentType; } 
      } 

      public override string MediaType 
      { 
       get { return this.inner.MediaType; } 
      } 

      public override bool IsContentTypeSupported(string contentType) 
      { 
       return this.inner.IsContentTypeSupported(contentType); 
      } 

      public override MessageVersion MessageVersion 
      { 
       get { return this.inner.MessageVersion; } 
      } 

      public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) 
      { 
       return this.inner.ReadMessage(buffer, bufferManager, contentType); 
      } 

      public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) 
      { 
       throw new NotImplementedException(); 
      } 

      public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) 
      { 
       const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; 
       const string SchemaNamespace = "http://www.w3.org/2001/XMLSchema"; 
       const string ArraysNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; 
       const string SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; 
       ArraySegment<byte> temp = this.inner.WriteMessage(message, maxMessageSize, bufferManager, messageOffset); 
       MemoryStream ms = new MemoryStream(temp.Array, temp.Offset, temp.Count); 
       XmlDocument doc = new XmlDocument(); 
       doc.Load(ms); 
       bufferManager.ReturnBuffer(temp.Array); 
       XmlAttribute rootAttr = doc.CreateAttribute("xmlns", "sch", XmlnsNamespace); 
       rootAttr.Value = SchemaNamespace; 
       doc.DocumentElement.Attributes.Append(rootAttr); 
       XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable); 
       nsManager.AddNamespace("arrays", ArraysNamespace); 
       foreach (XmlNode arrayItem in doc.SelectNodes("//arrays:anyType", nsManager)) 
       { 
        XmlAttribute toRemove = null; 
        XmlAttribute typeAttr = null; 
        foreach (XmlAttribute attr in arrayItem.Attributes) 
        { 
         if (attr.Prefix == "xmlns" && attr.Value == SchemaNamespace) 
         { 
          toRemove = attr; 
         } 
         else if (attr.LocalName == "type" && attr.NamespaceURI == SchemaInstanceNamespace) 
         { 
          typeAttr = attr; 
         } 
        } 

        if (toRemove != null) 
        { 
         arrayItem.Attributes.Remove(toRemove); 
         if (typeAttr != null) 
         { 
          string prefix = toRemove.LocalName; 
          typeAttr.Value = typeAttr.Value.Replace(prefix + ":", "sch:"); 
         } 
        } 
       } 
       ms = new MemoryStream(); 
       doc.Save(ms); 
       byte[] buffer = bufferManager.TakeBuffer((int)ms.Length + messageOffset); 
       Array.Copy(ms.GetBuffer(), 0, buffer, messageOffset, (int)ms.Length); 
       return new ArraySegment<byte>(buffer, messageOffset, (int)ms.Length); 
      } 

      public override void WriteMessage(Message message, Stream stream) 
      { 
       throw new NotImplementedException(); 
      } 
     } 
    } 
    static Binding ReplaceEncoding(Binding original) 
    { 
     CustomBinding custom = new CustomBinding(original); 
     for (int i = 0; i < custom.Elements.Count; i++) 
     { 
      MessageEncodingBindingElement mebe = custom.Elements[i] as MessageEncodingBindingElement; 
      if (mebe != null) 
      { 
       custom.Elements[i] = new MyEncodingBindingElement(mebe); 
       break; 
      } 
     } 

     return custom; 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     Binding binding = ReplaceEncoding(new BasicHttpBinding()); 
     host.AddServiceEndpoint(typeof(ITest), binding, ""); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress)); 
     ITest proxy = factory.CreateChannel(); 
     Console.WriteLine(proxy.GetData()); 

     ((IClientChannel)proxy).Close(); 
     factory.Close(); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 
関連する問題