2009-07-09 18 views
6

私はWCF経由でスタンドアロンEXEからホストされている、とてもシンプルな小さなC#Webサービスを作成しました。コードは若干単純化されていますが、次のようになります。Delphi 2007の非IISホスト型WCF、C#Webサービスの使用方法

namespace VMProvisionEXE 
{ 
class EXEWrapper 
{ 
    static void Main(string[] args) 
    { 
     WSHttpBinding myBinding = new WSHttpBinding(); 
     myBinding.Security.Mode = SecurityMode.None; 

     Uri baseAddress = new Uri("http://bernard3:8000/VMWareProvisioning/Service"); 
     ServiceHost selfHost = new ServiceHost(typeof(VMPService), baseAddress); 

     try 
     { 
      selfHost.AddServiceEndpoint(typeof(IVMProvisionCore), myBinding, "CoreServices"); 

      ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); 
      smb.HttpGetEnabled = true; 
      smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy12; 
      selfHost.Description.Behaviors.Add(smb); 

      // Add MEX endpoint 
      selfHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 

      selfHost.Open(); 
      Console.WriteLine("The service is ready."); 
      Console.ReadLine(); 

残りのC#コード。上記のクラスVMPServiceはVMProvisionCore.IVMProvisionCoreを実装しています。

このサービスを使用するVisual Studio 2008クライアントアプリケーションを簡単に作成できます。問題はありません。しかし、Delphi 2007を使用することは別の問題です。 DelphiでWSDLインポータを使用してWSDLを取得することができます(この場合)http://bernard3:8000/VMWareProvisioning/Service?wsdlインポートユニットはうまくコンパイルされます。私は(C#のコードに示すように、余分な「/ CoreServicesに」の注意)WSDLのURLが含まれていないので、手動でプロキシを初期化する必要があります。

var 
    Auth: AuthenticateUser; 
    AuthResponse: AuthenticateUserResponse; 
    CoreI: IVMProvisionCore; 
begin 
    CoreI:= GetIVMProvisionCore(False, 'http://bernard3:8000/VMWareProvisioning/Service/CoreServices'); 
    Auth:= AuthenticateUser.Create; 
    try 
    Auth.username:= 'test'; 
    Auth.password:= 'test'; 
    AuthResponse:= CoreI.AuthenticateUser(Auth); 
    finally 
    FreeAndNIL(Auth); 
    end; 

それがヒットしたときに上記のコードはエラーを生成します。 "CoreI.AuthenticateUser(Auth);"と入力します。エラーがある "がメッセージを処理できないため、コンテンツタイプ 'text/xmlで;のcharset = "UTF-8" はなかった、予想されるタイプ' アプリケーション/石鹸+ xmlの;のcharset = UTF-8"

IおそらくWSDLのインポート中や接続オプションなどの中で、私はどこかで愚かな小さなエラーが発生していると思われます。誰も助けることができますか?

答えて

4

解決策が見つかりました。これは複数の部分で構成されており、C#側にはいくつかの変更が必要です。これはDelphi 2007とVisual Studio 2008でテストされています。

C#側: WSHttpBindingではなくBasicHttpBindingを使用してください。

修正ステップ1

​​

この変更は、Delphi側のアプリケーション/石鹸+ xmlのエラーを解決します。

デルファイ2007側:すべてのサポートされているインターフェイスにSOAPActionsを追加し、この問題を解決するには

Exception class ERemotableException with message 'The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).'

:修正C#のWebサービスに対して実行 は今、このようなエラーが発生します。ここに私のコードの例があります。これは輸入から-WSDL-PAS-ファイルの初期化セクションによって作られたInvRegistryの変更のすべての後に行われる必要があります。

修正ステップ2

InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IVMProvisionCore), 'http://Cisco.VMProvision.Core/CoreServices/%operationName%'); 

タイプ名とURLはから入手する必要があります

DelphiはWSDLからインポートファイルを生成したり、実際のWSDLを検査したりしました。上記の例は自分のプロジェクトのためのものでした。これらのコードの変更の後、あなたはエラーがよ:

Exception class ERemotableException with message 'The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation....

このエラーは、次のコード(http://www.bobswart.nl/weblog/Blog.aspx?RootId=5:798にクレジット)を追加することで解決されます。ここでも、この新しいコードは、WSDL-to-PASファイルの初期化ですべてのInvRegistryの後になければなりません。この時点で

修正ステップ3

InvRegistry.RegisterInvokeOptions(TypeInfo(IVMProvisionCore), ioDocument); 

、パケットは、DelphiとC#の間を行き来します - しかし、パラメータが正しく動作しません。 C#はすべてのパラメータをnullとして受け取り、Delphiは応答パラメータを適切に受け取っていないようです。最後のコードステップでは、少しカスタマイズされたTHTTPRIOオブジェクトを使用して、リテラルパラメータを使用できます。この部分へのトリックは、インタフェースが取得された後にオプションが適用されることを確認することです。前にやってもうまくいきません。私の例のコードは次のとおりです(スニペットのみ)。

修正ステップ4

var 
    R: THTTPRIO; 
    C: IVMProvisionCore; 
begin 
    R:= THTTPRIO.Create(NIL); 
    C:= GetIVMProvisionCore(False, TheURL, R); 
    R.Converter.Options:= R.Converter.Options + [soLiteralParams]; 

そして今 - 私のDelphi 2007のアプリケーションは、C#のに話すことができるスタンドアローン、非IIS、WCF Webサービス!

0

デルファイでC#Webサービスを使用しているときにも同じ問題が発生しました。
Delphi 7.0/2005/2007は、新しいWSDL定義をサポートしていません。
これには、最新のWSDL Importer(WSDLImp.exe)をダウンロードする必要があります。また、更新されたデルファイソースコードパスファイルのソースコードも提供します。

+0

最新のWSDLImp.exeはどこからダウンロードできますか?私はEmbarcaderoのWebサイトをチェックしましたが、バグ修正以外の参照は見つかりませんでした。 –

1

これは、SOAPバージョンの不一致が原因です。 C#サービスは、SOAP12メッセージを期待しており、DelphiアプリケーションからSOAP11メッセージを受信して​​います。状況に応じて、どちらか一方を変更する必要があります。私は本当にデルファイ側にコメントすることはできません。 WCF側では、デフォルトでSOAP11に設定されているBasicHttpBindingを使用できます。さらに制御が必要な場合は、SOAP11のメッセージタイプを指定してCustomBindingを使用します。

+0

C#サーバーをBasicHttpBindingに切り替えると、実際にapplication/soap + xmlの問題が解決されました。しかし、それは空白のSOAPAction値、パラメータが読み込まれないという、新しいエラーの大部分を開いた。私は今それらに取り組んでいます。 –

+0

WCFの他の環境との相互運用性については、あまり理想的ではありませんでした。SOAP11はSOAP12との相互作用が少ないと思われるので、DelphiコードでSOAP12に簡単に切り替えることができれば、そのオプションを調べることをお勧めします。 – Maurice

0

ありがとうございました - これは多くの助けとなりました。私はもう少しシワに悩まされました。私にとっては、OperationNameが一致しなかったので、#2(SOAPAction)の問題がすべて解決されました。 .Netグループは、SOAPActionの終わりに "In"を配置することを標準化しましたが、Operationは配置しませんでした。
だからyadda.yadda.com/whatever/services/%operationName% は実際には である必要があります。yadda.yadda.com/whatever/services/%operationName%In この特定のケースでは、

それを見分けるのはかなり時間がかかりましたが、最終的にSoapUIと並行してテストすることで、エラー応答に戻ってくるものとは異なるSOAPActionsがあることに気付きました。私はそれを修正し、それは働いた。しかし、これは、最初にDefaultSOAPActionに何が含まれるべきかを把握しようとしている間にかなり苦労した後でした。ここでも、SoapUIは役に立ちました。 このエラーが発生した場合は、 "EndpointDispatcherでContractFilterの不一致が原因で受信者で処理できないアクション" ... 最初の手順はDefaultSOAPActionを設定することです。問題が解決しない場合は、エラーで報告されたものと実際に何があるべきかを比較してください。
HTH、Chris

+0

ええと、wsdlツールでインポートされたユニットの "入力エレメントラッパー名が操作の名前と一致しません"というメッセージが表示されます。たぶんそれは問題です、あなたが書いた..?どのようにそのエラーを修正しましたか? C#またはデルファイ側ですか? – John

関連する問題