2009-07-09 63 views
6

我寫了一個相當簡單的小C#web服務,通​​過WCF從獨立的EXE託管。代碼 - 有點簡化 - 看起來像這樣:如何從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導入單元編譯得很好。我必須手工初始化代理由於WSDL不包含一個URL(注意額外「/ CoreServices」如圖所示的C#代碼):

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);」。錯誤是「無法處理該消息,因爲該內容類型‘文本/ XML;字符集=‘UTF-8’不是預期的類型’應用/肥皂+ xml的;字符集= UTF-8

我懷疑我在某個地方出現了一個愚蠢的小錯誤,可能是在導入WSDL或連接選項時出現錯誤。誰能幫忙?

回答

4

找到了解決方案。這是多個部分,需要對C#端進行一些更改,更多的是德爾福方面。請注意,這是用Delphi 2007和Visual Studio 2008測試的。

C#端: 使用BasicHttpBinding而不是WSHttpBinding。

修正步驟1

​​

這種變化將解決上的Delphi側的應用/肥皂+ xml的錯誤。

2007年德爾福方: 運行鍼對修改後的C#Web服務現在會產生這樣的錯誤:

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).'

要解決此問題,添加SOAPActions到所有支持的接口。以下是我的代碼示例;這必須畢竟由進口從 - 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到PAS文件初始化的所有InvRegistry內部。

修復步驟3

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

在這一點上,數據包將走個來回Delphi和C#之間 - 但參數將不能正常工作。 C#將接收所有參數作爲空值,並且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]; 

而現在 - 我的2007年德爾福應用程序可以跟C#,獨立的,非IIS,WCF Web服務!

0

我在delphi中使用C#web服務時也面臨同樣的問題。
Delphi 7.0/2005/2007不支持新的WSDL定義。
爲此,您需要下載最新的WSDL導入程序(WSDLImp.exe)。它還將提供更新的delphi源代碼傳遞文件的源代碼。

+0

你知道我可以在哪裏下載最新的WSDLImp.exe嗎?我檢查了Embarcadero網站,但找不到任何超出它的錯誤修復引用。 – 2009-07-21 14:46:42

1

這是由於SOAP版本不匹配造成的。 C#服務期待SOAP12消息並從Delphi應用程序接收SOAP11消息。根據你的情況,你需要改變雙方中的任何一個。我不能真正評論德爾福方面。在WCF端,您可以使用默認爲SOAP11的BasicHttpBinding,或者如果您需要更多控制,請使用指定SOAP11消息類型的CustomBinding。

+0

將C#服務器切換到BasicHttpBinding確實解決了application/soap + xml問題。但是,它打開了一大堆新的錯誤:空白的SOAPAction值,參數沒有被讀取。我現在正在處理這些問題。 – 2009-07-21 14:48:06

+0

我在WCF與其他環境進行互操作時得到了一個不太完美的分數。因此,如果您的Delphi代碼允許您輕鬆切換到SOAP12,那麼SOAP11似乎不易與SOAP12交互,所以我會建議您探索該選項。 – Maurice 2009-07-21 18:40:24

0

謝謝 - 這有很大的幫助。我遇到了更多的皺紋。對我來說,問題#2(SOAPAction)全部被堵塞,因爲OperationName不匹配。 .Net小組標準化在SOAPAction結束時放置「In」,但不是操作。
因此yadda.yadda.com/whatever/services/%operationName% 確實需要是 yadda.yadda.com/whatever/services/%operationName%In 在這種情況下。

我花了很長時間才發現,但最終我發現通過與SoapUI並行測試,發現SOAPAction與錯誤響應中返回的SOAPAction不同。我解決了這個問題,並且工作。但是這是在經歷了一段時間的努力之後,試圖首先找出DefaultSOAPAction中的內容。再一次,SoapUI在這裏很有幫助。
因此,無論如何,如果您發現此錯誤: 「由於EndpointDispatcher中的ContractFilter不匹配,無法在接收方處理操作(無論)...」 第一步是填充DefaultSOAPAction,並且如果問題仍然存在,請將錯誤報告中的錯誤與真正應該存在的錯誤進行比較。
HTH,Chris