2012-01-27 9 views
1

私はFlattened WSDLのWCFサービスを持っています。もう一方の消費者は、nillable = "true"属性がそれらをホーミングしていると伝えています。私はサービス契約でEmitDefaultValue = falseを設定しようとしましたが、動作の変化に気付かなかった。WCF WSDL + Nillable Attributes

確かに、私はこのレベルでWSDL生成を掘り起こす必要はなかったので、少し失われています。おそらく私の問題を解決するかもしれない下に掲示されたコードのビットで行われるべき微調整がありますか?私が少なくとも正しい場所にいるなら、私は調査を続けます。

WSDLからnillable = "true"属性を削除する簡単な方法はありますか?意図しない結果が生じることはありますか?ありがとう!

public class FlatWsdl : IWsdlExportExtension, IEndpointBehavior 
{ 
    public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context) 
    { 
     XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas; 

     foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments) 
     { 
      List<XmlSchema> importsList = new List<XmlSchema>(); 

      foreach (XmlSchema schema in wsdl.Types.Schemas) 
      { 
       AddImportedSchemas(schema, schemaSet, importsList); 
      } 

      wsdl.Types.Schemas.Clear(); 

      foreach (XmlSchema schema in importsList) 
      { 
       RemoveXsdImports(schema); 
       wsdl.Types.Schemas.Add(schema); 
      } 
     } 
    } 

    ...omitted the rest of FlatWsdl.cs for brevity... 
} 
+0

あなたがあなた自身のWsdlExportExtensionを記述する必要があります。 サンプルについては、この回答を参照してください:http://stackoverflow.com/questions/10602749/setting-nillable-false-with-wcf/23366064#23366064 – Vizu

答えて

1

これを達成するための直接的な簡単な方法はありません。あなた自身で実装するには、WsdlExporterを使用する必要があります。

IWSDLExportExtensionのMSDNの例を見てください:それは予期しない結果をもたらすかどうかは

EDIT :-)あなたの意図に依存します。それはあなたが望むものを正確に行うことを可能にします。確かに、それを正しくするのはちょっと面倒ですが、あなたは正しい方向に向かっています。

+0

私は最後に行動をとることを選びませんでしたが、もし私がNillable属性を削除するには、ExportEndpointメソッドでWsdlExporterを使用します。 –

+0

.Net 4.5ではこの動作にいくつかの変更がありますか?私は今、同じ状況に直面しています。プロジェクトにIWSDLExportExtensionを持たないでください。 – DoomerDGR8

1

私たちのためにインターネットを検索した後、私と私のチームは異なるアプローチで、nillable = "true"を取り除くことに決めました。私たちがしたことは以下の通りでした:

  1. アプリケーションの起動時に特別なHttpModuleが登録されました。
  2. このモジュールは、BeginRequestイベントへのハンドラを登録しました。
  3. WSDLまたはXSDが要求された場合(クエリ文字列を調べることによってチェックされている場合)、フックされたハンドラはデフォルトのResponse.Filterをデコレータ(ストリーム)に置き換えます。
  4. このデコレータは、文書の終わりに達するまで、書かれたデータをバッファします。
  5. すべてのデータが書き込まれると、デコレータはそのデータに基づいてXDocumentを構築し、そのドキュメントを参照して(ドキュメントの追加など)、nillable = "false"に設定します。

これはすべてかなりかわいいです。

Response.Filterを使用するアイデアは、hereです。ここで

はHttpModuleをです:

public class WsdlInterceptionHttpModule : IHttpModule 
{ 
    public void Init(HttpApplication application) 
    { 
     application.BeginRequest += (sender, e) => 
     { 
      var context = application.Context; 

      if (IsRequestForWsdl(context.Request)) 
      { 
       context.Response.Filter = 
        new WsdlAnnotationsFilterDecorator(context.Response.Filter); 
      } 
     }; 
    } 

    private static bool IsRequestForWsdl(HttpRequest request) { ... } 
} 

ここWsdlAnnotationsFilterDecoratorです:すべての魔法が起こる場所

public class WsdlAnnotationsFilterDecorator : Stream 
{ 
    private const string DefinitionsEndOfFileMarker = "</wsdl:definitions>"; 
    private const string SchemaEndOfFileMarker = "</xs:schema>"; 

    private readonly Stream inputStream; 
    private readonly StringBuilder responseXml = new StringBuilder(); 
    private bool firstWrite = true; 
    private string endOfFileMarker = DefinitionsEndOfFileMarker; 

    public WsdlAnnotationsFilterDecorator(Stream inputStream) 
    { 
     this.inputStream = inputStream; 
     this.responseXml = new StringBuilder(); 
    } 

    public override bool CanRead { get { return true; } } 
    public override bool CanSeek { get { return true; } } 
    public override bool CanWrite { get { return true; } } 
    public override long Length { get { return 0; } } 
    public override long Position { get; set; } 

    public override void Close() 
    { 
     inputStream.Close(); 
    } 

    public override void Flush() 
    { 
     inputStream.Flush(); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
     return inputStream.Seek(offset, origin); 
    } 

    public override void SetLength(long length) 
    { 
     inputStream.SetLength(length); 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     return inputStream.Read(buffer, offset, count); 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     string valueToWrite = UTF8Encoding.UTF8.GetString(buffer, offset, count); 

     SetEndOfFileMarker(valueToWrite); 

     if (!valueToWrite.EndsWith(this.endOfFileMarker)) 
     { 
      responseXml.Append(valueToWrite); 
     } 
     else 
     { 
      responseXml.Append(valueToWrite); 

      string finalXml = responseXml.ToString(); 

      finalXml = WsdlAnnotator.Annotate(finalXml); 

      byte[] data = UTF8Encoding.UTF8.GetBytes(finalXml); 

      inputStream.Write(data, 0, data.Length); 
     } 
    } 

    private void SetEndOfFileMarker(string valueToWrite) 
    { 
     if (firstWrite) 
     { 
      int definitionTagIndex = valueToWrite.IndexOf("<wsdl:definitions"); 
      int schemaTagIndex = valueToWrite.IndexOf("<xs:schema"); 

      if (definitionTagIndex > -1 || schemaTagIndex > -1) 
      { 
       firstWrite = false; 

       if (definitionTagIndex > -1 && schemaTagIndex > -1) 
       { 
        endOfFileMarker = 
         definitionTagIndex < schemaTagIndex 
          ? DefinitionsEndOfFileMarker : SchemaEndOfFileMarker; 
       } 
       else if (definitionTagIndex > -1) 
       { 
        endOfFileMarker = DefinitionsEndOfFileMarker; 
       } 
       else if (schemaTagIndex > -1) 
       { 
        endOfFileMarker = SchemaEndOfFileMarker; 
       } 
      } 
     } 
    } 
} 

WsdlAnnotatorは次のとおりです。

internal static class WsdlAnnotator 
{ 
    internal static string Annotate(string xml) 
    { 
     XDocument document = XDocument.Parse(xml); 

     try 
     { 
      // Your magic here. 
     } 
     catch (Exception ex) 
     { 
      throw new InvalidOperationException(
       ex.Message + " Document: " + document.ToString(), ex); 
     } 

     return document.ToString(SaveOptions.None); 
    }