如何使用Delphi 2007中的非IIS托管,WCF,C#Web服务?

时间:2009-07-09 02:37:00

标签: c# wcf web-services delphi

我编写了一个相当简单的小型C#Web服务,通​​过WCF从独立的EXE托管。代码 - 有点简化 - 看起来像这样:

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。

namespace VMProvisionCore
{
[ServiceContract(Namespace = "http://Cisco.VMProvision.Core", ProtectionLevel = System.Net.Security.ProtectionLevel.None)]
public interface IVMProvisionCore
{
    [OperationContract]
    bool AuthenticateUser(string username, string password);
}

我可以轻松创建使用此服务的Visual Studio 2008客户端应用程序。没问题。但是使用Delphi 2007是一个不同的问题。我可以使用Delphi中的WSDL导入器从(在这种情况下)http://bernard3:8000/VMWareProvisioning/Service?wsdl中检索WSDL导入单元编译得很好。我必须手动初始化代理,因为WSDL不包含URL(注意C#代码中显示的额外“/ CoreServices”):

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“不是预期的类型'application / soap + xml; charset = utf-8。

我怀疑我在某处有一个愚蠢的小错误,可能是在导入WSDL或连接选项之类的时候。有人可以帮忙吗?

4 个答案:

答案 0 :(得分:4)

找到解决方案。它是多个部分,需要对C#端进行一些更改,对Delphi端更多。请注意,这是使用Delphi 2007和Visual Studio 2008测试的。

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

修复第1步

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

此更改将解决Delphi端的application / soap + xml错误。

Delphi 2007方面: 针对修改后的C#Web服务运行现在将生成如下错误:

  

异常类ERemotableException   消息'带有动作的消息   ''无法处理   接收者,由于ContractFilter   EndpointDispatcher不匹配。   这可能是因为a   合同不匹配(不匹配的行动   发送者和接收者之间)或a   绑定/安全性不匹配   发件人和接收者。检查一下   发送者和接收者都一样   合同和相同的约束力   (包括安全要求,例如   消息,传输,无)。'

要解决此问题,请将SOAPActions添加到所有支持的接口。这是我的代码中的示例;这必须在import-from-WSDL-PAS-file的初始化部分所做的所有InvRegistry更改之后完成:

修复第2步

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

类型名称和URL应该可以从Delphi生成的WSDL导入文件和/或实际WSDL的检查中获得。上面的例子是我自己的项目。这些代码更改后,您将收到错误:

  

异常类ERemotableException   消息'格式化程序扔了一个   尝试反序列化时出现异常   消息:反序列化时出错   请求消息的主体   操作....

通过添加以下代码(http://www.bobswart.nl/weblog/Blog.aspx?RootId=5:798的信用)解决了此错误。同样,这个新代码必须在WSDL-to-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];

现在 - 我的Delphi 2007应用程序可以与C#,独立,非IIS,WCF Web服务进行通信!

答案 1 :(得分:1)

这是由SOAP版本不匹配引起的。 C#服务期待SOAP12消息并从您的Delphi应用程序接收SOAP11消息。根据您的情况,您需要更改双方中的任何一方。我无法真正评论德尔福方面。在WCF端,您可以使用默认为SOAP11的BasicHttpBinding,或者,如果需要更多控制,请使用指定SOAP11的消息类型的CustomBinding。

答案 2 :(得分:0)

在delphi中使用C#Web服务时,我也遇到了同样的问题 Delphi 7.0 / 2005/2007不支持新的WSDL定义。
为此,您需要下载最新的WSDL Importer(WSDLImp.exe)。它还将提供更新的delphi源代码传递文件的源代码。

答案 3 :(得分:0)

谢谢 - 这帮了很多忙。我有几个皱纹的麻烦。对我来说,问题#2(SOAPAction)都被搞砸了,因为OperationName不匹配。 .Net小组标准化了在SOAPAction结尾处放置“In”,但没有标准化操作 所以yadda.yadda.com/whatever/services/%operationName% 真的需要 yadda.yadda.com/whatever/services/%operationName%In 在这个具体案例中。

我花了很长时间才发现这一点,但我终于注意到与SoapUI并行测试,它与错误响应中返回的SOAPActions有不同的SOAPActions。我解决了这个问题,并且有效。但这是在经过一段时间努力试图弄清楚DefaultSOAPAction应该是什么之后。再次,SoapUI在这里很有帮助。
所以无论如何,如果你发现你收到这个错误: “由于EndpointDispatcher上的ContractFilter不匹配,无法在接收方处理动作(无论如何)...” 第一步是填充DefaultSOAPAction,如果问题仍然存在,请将错误中报告的内容与实际应该存在的内容进行比较。
HTH,克里斯

相关问题