1

Web サービス/Web クライアント アーキテクチャから WCF アーキテクチャへの移行に苦労しています。オブジェクトは非常に複雑で、多数のネストされた xsd とさまざまな名前空間があります。プロキシ クラスは、30 以上の webmethods を持つ元の wsdl に Web 参照を追加し、不足している SOAPFault オブジェクトを生成するために xsd.exe を使用することによって生成されます。私のパイロット WCF サービスは、元のメソッドの 1 つの正確な構文に一致する 1 つの webmethod のみで構成されています。1 つのオブジェクトをパラメーターとして、1 つの他のオブジェクトを結果値として返します。XMLSerializerFormat属性を使用して、これらのプロキシ クラスを使用して WCF インターフェイスを作成しましServiceContractた。OperationContractActionReplyAction、すべて適切な名前空間を持つ。SoapUI を使用して着信クライアント メッセージを作成します。元の WSDL ファイルからプロジェクトを生成し (SoapUI プロジェクトに 30 以上のメソッドを持たせる)、実装された WebMethod で新しい Request を 1 つ作成し、URL を wcf Web サービスに変更してメッセージを送信しました。で (Reply-)Action が指定されているためOperationContractAttribute、メッセージは実際に受信され、オブジェクトに適切に逆シリアル化されます。

これまで (40 時間のグーグル検索) を実現するために、多くのフラストレーションから、WCF の「ラップされたタグ」が削除され、ネストされた型の名前空間が修正され、生成された wsdl get がフラット化されたカスタム エンドポイントを使用することになりました (より良いためにMS VisualStudio 以外のツールとの互換性があります)。

インターフェイス コードは次のとおりです。

[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document, SupportFaults = true)]
[ServiceContract(Namespace = Constants.NamespaceStufZKN)]
public interface IOntvangAsynchroon
{

    [OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/zakLk01", Name = "zakLk01")]
    [FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)]
    Bv03Bericht zakLk01([XmlElement("zakLk01", Namespace = Constants.NamespaceStufZKN)] ZAKLk01 zakLk011);

コードで Webclient を使用してメッセージを送信すると、すべてが機能します。私の問題は、WCF クライアントを使用する場合です。私ChannelFactory<IOntvangAsynchroon>はメッセージを送信するために使用します。しかし、生成された xml は異なって見えます: メソッドのパラメーター名が含まれています! これを理解するのに多くの時間がかかりましたが、次のようになります。

正しい xml (剥がされた石鹸の封筒):

<soap:Body>
  <zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310">
    <stuurgegevens>
      <berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode>
      <zender xmlns="http://www.egem.nl/StUF/StUF0301">
        <applicatie>ONBEKEND</applicatie>
      </zender>
    </stuurgegevens>
    <parameters>
    </parameters>
  </zakLk01>
</soap:Body>

不適切な XML:

<soap:Body>
  <zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310">
    <zakLk011>
    <stuurgegevens>
      <berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode>
        <zender xmlns="http://www.egem.nl/StUF/StUF0301">
          <applicatie>ONBEKEND</applicatie>
        </zender>
      </stuurgegevens>
      <parameters>
      </parameters>
    </zakLk011>
  </zakLk01>
</soap:Body>

zakLk011要素に注意してください。私のインターフェイスのメソッドのパラメーターの名前です! だから今は ですzakLk011が、私のパラメータ名が だったときzakLk01、xmlには上記のタグの魔法のような複製が含まれているように見えましたが、名前空間はありませんでした。もちろん、それがパラメーター名であることに気付く前に、何が起こっていたのかに夢中になっていることを想像できます!

実際に WCF サービスを作成しましたが、WCF クライアントを使用してメッセージを送信できなくなりました。明確にするために: メソッドは Web サービスで WCF クライアントを使用して呼び出されますが、パラメーター オブジェクトは空です。カスタム エンドポイントを使用して着信 xml をログに記録しているため、メッセージが正常に受信されていることがわかりますが、構文が間違っているだけです。

WCF クライアント コード:

ZAKLk01 stufbericht = MessageFactory.CreateZAKLk01();
ChannelFactory<IOntvangAsynchroon> factory = new ChannelFactory<IOntvangAsynchroon>(new BasicHttpBinding(), new EndpointAddress("http://localhost:8193/Roxit/Link/zkn0310"));
factory.Endpoint.Behaviors.Add(new LinkEndpointBehavior());
IOntvangAsynchroon client = factory.CreateChannel();
client.zakLk01(stufbericht);

私は生成されたクライアントを使用していません。慣れているように、Web サービス (共有ライブラリ) を参照するだけです。

編集:サービス参照を生成すると、重複したクラスが生成されます(理由がわからない..)。ただし、これらの重複が削除されると、クライアントは正しい xml でメッセージを送信します。しかし、私のアーキテクチャには共有ライブラリが必要なので、これは役に立ちません。

誰でも私を助けてもらえますか?これについては何もグーグルできません...

4

2 に答える 2

0

わかりました、私はそれを自分で理解しました。動作する WCF クライアント (サービス リファレンス) を既に作成しており、生成されたコードをよく見て、何が起こっているのかを把握しました。これは、WCF が Webservice メソッドの DECLARATION で使用されるすべてのクラスをラップする方法に関係しています (そのため、メソッドで言及されたクラスのプロパティで使用されるクラスはラップされません)。私の場合、ZAKLk01 クラスの本体は、パラメーター名を XMLElement-name として使用して、XMLElement タグでラップされます。この動作を取り除くために、生成されたプロキシ クラス ZAKLk01 および Bv03Bericht にラッパー クラスを使用しています。これは、生成されたクラスが新しい WCF クライアントの Service References プロキシ クラスで行うのと同じです。これらのラッパー クラスは、MessageContractAttributes で装飾されています。

これらのラッパー クラスの 1 つの例を挙げると、次のようになります。

[MessageContract(IsWrapped = false)]
public partial class zakLk01Request
{

    [MessageBodyMember(Namespace = Constants.NamespaceStufZKN, Order = 0)]
    public ZAKLk01 zakLk01;

    public zakLk01Request()
    {
    }

    public zakLk01Request(ZAKLk01 zakLk01)
    {
        this.zakLk01 = zakLk01;
    }
}

私の Interface メソッドは次のようになります。

[OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/Bv03Bericht")]
[FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)]
zakLk01Response zakLk01(zakLk01Request zakLk01);

XMLElement タグがなくても、(正しい xml を生成する) 機能がラッパー クラスに置き換えられ、よりクリーンになりました。

ラップされていない xml を受け取ることができた理由は、カスタム メッセージ インスペクターに、既存のすべてのクラスに MessageContract タグを追加する (または多くのラッパー クラスを作成する) ことなく、ラップされていない xml メッセージを受け入れることを意図したコードが含まれていたためです (どこかでグーグル検索しました)。 、それはうまくいきました。コードスニペット:

MessageDescription.Body.WrapperName = null;

しかし、クラスをまだラップしている私の(最初の)WCFクライアントから送信されたラップされたメッセージを受信して​​も、もちろんうまくいきませんでした...

私がまだ理解していないのは、これらの Action 属性がどのように機能するかです。それらを指定しないと、生成された wsdl にメソッドが含まれません。さて、今は重要ではありません。ようやく先に進むことができるので、Action 属性についてはまた別の機会にいじるつもりです。

于 2010-06-02T12:54:38.830 に答える
0

提案: WCF を使い始めたばかりの場合は、「WCF のやり方」から始めてください。それを正しく行う方法がわかれば、物事を変え始めることができます。現時点では、問題のどの程度が WCF に起因しているか、WCF の経験不足に起因するかはわかりません。

を使用せずに、ゼロから始めることをお勧めします[XmlSerializerFormat]ServiceContract単一の で を作成するだけOperationContractです。FaultContractそれがどのように機能するかを確認できるように、少なくとも 1 つ含めてください。

「サービス参照の追加」を使用して WCF クライアントを作成し、それが機能することを確認します。

次に、(元の WSDL ではなく) WCF サービスの WSDL を使用して SOAPUI プロジェクトを作成します。それが機能することを確認してください。

それから、物事を変え始めることができます。試してみてください[XmlSerializerFormat][Xml*]さまざまな属性を追加してみてください。何が壊れているかがわかるまで、ゆっくりと物事を変え始めます。

于 2010-06-02T06:58:34.547 に答える