2009-07-09 5 views
6

Ich habe einen ziemlich einfachen kleinen C# -Webdienst geschrieben, der von einer eigenständigen EXE über WCF gehostet wird. Der Code - etwas vereinfacht - sieht wie folgt aus:Wie kann ich einen nicht von IIS gehosteten WCF-, C# -Webdienst von Delphi 2007 verwenden?

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(); 

Der Rest des C# -Code; Die obige Klasse VMPService implementiert VMProvisionCore.IVMProvisionCore.

Ich kann problemlos eine Visual Studio 2008-Clientanwendung erstellen, die diesen Dienst verwendet. Keine Probleme. Die Verwendung von Delphi 2007 ist jedoch ein anderes Problem. Ich kann das WSDL-Importer in Delphi verwenden, um die WSDL von (in diesem Fall) http://bernard3:8000/VMWareProvisioning/Service?wsdl abzurufen. Die Importeinheit kompiliert einfach gut. Ich habe den Proxy von Hand zu initialisieren, da die WSDL keine URL enthält (beachten Sie die extra „/ Coreservices“, wie in der C# -Code dargestellt):

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; 

Der obige Code wird einen Fehler erzeugen, wenn er trifft der "CoreI.AuthenticateUser (Auth);". Der Fehler ist "Kann die Nachricht nicht verarbeiten, da der Inhaltstyp 'text/xml; charset = "UTF-8" war nicht der erwartete Typ' application/soap + xml;. Charset = utf-8"

I vermute, dass ich irgendwo einen dummen kleinen Fehler habe, vielleicht beim Import der WSDL oder in den Verbindungsoptionen oder sowas. Kann jemand helfen?

Antwort

4

Die Lösung gefunden. Es besteht aus mehreren Teilen und erfordert einige Änderungen auf der C# -Seite, mehr auf der Delphi-Seite. Beachten Sie, dass dies mit Delphi 2007 und Visual Studio 2008 getestet wurde.

C# -Seite: Verwenden Sie BasicHttpBinding statt WSHttpBinding.

Fix Schritt 1

BasicHttpBinding myBinding = new BasicHttpBinding(); 
myBinding.Security.Mode = BasicHttpSecurityMode.None; 

Diese Änderung der Anwendung/soap + xml Fehler auf der Delphi-Seite lösen wird.

Delphi 2007 Seite: Rennen gegen die modifizierte C# Web-Service wird nun Fehler wie diese erzeugen:

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

um dieses Problem zu beheben, fügen Sie SOAPActions auf alle Ihre unterstützten Schnittstellen.Hier ist das Beispiel aus meinem Code; Dies muss der Import-von-WSDL-PAS-Datei des Initialisierungssektion gemacht, nachdem alle der InvRegistry Änderungen erfolgen:

Fix Schritt 2

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

Der Typname und URL sollte erreichbar sein aus die von Delphi generierte Importdatei von der WSDL und/oder eine Inspektion der eigentlichen WSDL. Das obige Beispiel war für mein eigenes Projekt. Nach diesen Änderungen am Code, dann werden Sie den Fehler:

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

Dieser Fehler wird durch Hinzufügen des folgenden Codes (Gutschriften http://www.bobswart.nl/weblog/Blog.aspx?RootId=5:798) aufgelöst. Auch dieser neue Code muss nach der InvRegistry-Prozedur in der Initialisierung der WSDL-zu-PAS-Datei vorhanden sein.

Fix Schritt 3

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

An diesem Punkt werden Pakete gehen hin und her zwischen Delphi und C# - aber Parameter funktionieren nicht richtig. Das C# empfängt alle Parameter als Nullen, und Delphi scheint die Antwortparameter nicht korrekt zu empfangen. Der letzte Code-Schritt besteht darin, ein leicht angepasstes THTTPRIO-Objekt zu verwenden, das literale Parameter erlaubt. Der Trick dieses Teils besteht darin, sicherzustellen, dass die Option angewendet wird, NACHDEM die Schnittstelle erhalten wurde; es vorher zu tun wird nicht funktionieren. Hier ist der Code aus meinem Beispiel (nur Schnipsel).

Fix Schritt 4

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

Und jetzt - meine Delphi 2007 App auf die C# sprechen kann, stand-alone, nicht-IIS, WCF Web-Service!

0

Ich habe auch das gleiche Problem konfrontiert, wenn C# -Webdienst in Delphi.
Delphi 7.0/2005/2007 unterstützt keine neuen WSDL-Definitionen.
Dazu müssen Sie den neuesten WSDL-Importer (WSDLImp.exe) herunterladen. Es wird auch Quellcode für aktualisierte Delphi-Quellcode-Pass-Dateien bereitstellen.

+0

Wissen Sie, wo ich die neuesten WSDLImp.exe herunterladen kann? Ich habe die Embarcadero-Website überprüft, konnte jedoch nichts finden, das über Bugfix-Referenzen hinausgeht. –

1

Dies wird durch eine SOAP-Versionskonflikt verursacht. Der C# -Dienst erwartet eine SOAP12-Nachricht und empfängt eine SOAP11-Nachricht von Ihrer Delphi-App. Abhängig von Ihrer Situation müssen Sie eine der beiden Seiten wechseln. Ich kann die Seite von Delphi nicht wirklich kommentieren. Auf der WCF-Seite können Sie BasicHttpBinding verwenden, das standardmäßig SOAP11 verwendet. Wenn Sie mehr Kontrolle benötigen, verwenden Sie eine CustomBinding, die den Nachrichtentyp SOAP11 angibt.

+0

Das Umschalten des C# -Servers auf BasicHttpBinding löste tatsächlich das application/soap + xml-Problem. Es hat jedoch eine ganze Reihe neuer Fehler geöffnet: leere SOAPAction-Werte, Parameter wurden nicht gelesen. Ich arbeite jetzt an denen. –

+0

Ich hatte eine weniger perfekte Punktzahl auf WCF Interop mit anderen Umgebungen.SOAP11 scheint weniger interoperabel zu sein als SOAP12. Wenn Sie also mit Ihrem Delphi-Code leicht zu SOAP12 wechseln können, würde ich vorschlagen, diese Option zu erkunden. – Maurice

0

Danke - das hat sehr geholfen. Ich hatte Probleme mit ein paar mehr Falten. Für mich war das Problem # 2 (SOAPAction) allesamt verpfuscht, weil der OperationName nicht übereinstimmte. Die .Net-Gruppe standardisierte die Platzierung von "In" am Ende der SOAPAction, nicht aber die Operation.
Also yadda.yadda.com/whatever/services/%operationName% muss wirklich yadda.yadda.com/whatever/services/%operationName%In In diesem speziellen Fall sein.

Es hat eine ganze Weile gedauert, das zu erkennen, aber ich habe schließlich durch paralleles Testen mit SoapUI festgestellt, dass es andere SOAPActions als die in der Fehlerantwort zurückkehrenden hatte. Ich habe das behoben und es hat funktioniert. Aber das war nach einer Weile kämpfen, um herauszufinden, was in der DefaultSOAPAction in erster Linie sein sollte. Auch hier war SoapUI hilfreich.
So jedenfalls, wenn Sie feststellen, dass Sie diesen Fehler erhalten: "Aktion (was auch immer) kann nicht am Empfänger verarbeitet werden, aufgrund eines ContractFilter Mismatch am EndpointDispatcher ..." Der erste Schritt ist das Auffüllen der DefaultSOAPAction und Wenn die Probleme bestehen bleiben, vergleichen Sie den Bericht, der im Fehler enthalten ist, mit dem, was wirklich da sein sollte.
HTH, Chris

+0

Hmm, ich bekomme: "Der Name des Eingabeelement-Wrappers stimmt nicht mit dem Namen der Operation überein" in der importierten Einheit von wsdl tool. Vielleicht ist das das Problem, du hast geschrieben ..? Wie hast du diesen Fehler behoben? Auf C# oder Delphi Seite? – John

Verwandte Themen