如何消费托管,WCF,C#的Web服务从2007年德尔福非IIS? [英] How to consume non-IIS hosted, WCF, C# web service from Delphi 2007?

查看:135
本文介绍了如何消费托管,WCF,C#的Web服务从2007年德尔福非IIS?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个相当简单的小的C#Web服务,从通过WCF一个独立的EXE主办。代码 - 一定程度的简化 - 看起来是这样的:

I've written a fairly simple little C# web service, hosted from a standalone EXE via WCF. The code - somewhat simplified - looks like this:

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。

The rest of the C# code; the class VMPService above implements 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是一个不同的问题。我可以使用WSDL进口商在Delphi中来检索WSDL(在这种情况下)的http:// bernard3:8000 / VMWareProvisioning /服务? WSDL 进口单位编译就好了。我必须手工初始化代理,因为WSDL不包含一个URL(注意额外/ CoreServices,如图C#代码):

I can easily create a Visual Studio 2008 client application that consumes this service. No problems. But using Delphi 2007 is a different issue. I can use the WSDL importer in Delphi to retrieve the WSDL from (in this case) http://bernard3:8000/VMWareProvisioning/Service?wsdl The import unit compiles just fine. I have to initialize the proxy by hand since the WSDL doesn't contain a URL (notice the extra "/CoreServices" as shown in the C# code):

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进口或在连接选项或东西。谁能帮助?

I suspect that I've got a stupid little error somewhere, perhaps during the import of the WSDL or in the connection options or something. Can anyone help?

推荐答案

找到了解决办法。它的多个部分,并要求到C#一侧的一些变化,更多的德尔福的一面。注意,这是用Delphi 2007和Visual Studio 2008测试

Found the solution. It's multiple parts and requires a few changes to the C# side, more to the Delphi side. Note that this was tested with Delphi 2007 and Visual Studio 2008.

C#的一面:
使用basicHttpBinding的,而不是WsHttpBinding的

C# side: Use BasicHttpBinding rather than WSHttpBinding.

修正第1步

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

这变化将解决对德尔福端应用程序/肥皂+ XML错误。

This change will resolve the application/soap+xml errors on the Delphi side.

2007年德尔福方:
运行针对修改后的C#Web服务现在将产生这样的错误:

Delphi 2007 side: Running against the modified C# web service will now generate errors like this:

与消息''与动作
中的消息Exception类ERemotableException
不能在
接收机进行处理,由于在EndpointDispatcher一个ContractFilter
不匹配。
,这可能是因为无论是
合同不匹配(失配操作
发送者和接收者之间)或者
结合的
发送器和接收器之间的/安全不匹配。检查
发送者和接收者有相同的
合同,相同的绑定
(包括安全要求,如:
信息,运输,无)。

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的变化来完成:

To resolve this problem, add SOAPActions to all your supported interfaces. Here's the example from my code; this must be done AFTER all of the InvRegistry changes made by the import-from-WSDL-PAS-file's initialization section:

修正第2步

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



类型名称和URL应该从德尔福得到从WSDL和/或生成的导入文件实际的WSDL检查。上面的例子是我自己的项目。这些代码更改之后,那么你的错误:

The type name and URL should be obtainable from the Delphi generated import file from the WSDL and/or an inspection of the actual WSDL. The above example was for my own project. After these code changes, then you'll the error:

Exception类ERemotableException
与消息格式化抛出一个$ B尝试反序列化
消息$ b例外:在
操作请求消息的反序列化
主体错误....

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东西。

This error is resolved by adding the following code (credits to http://www.bobswart.nl/weblog/Blog.aspx?RootId=5:798). Again, this new code must be after all the InvRegistry stuff in the initialization of the WSDL-to-PAS file.

修正第3步​​

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



在这一点上,数据包将走个来回Delphi和C#之间 - 但参数将不能正常工作正常。 C#的将接收所有的参数,空值和德尔福似乎并没有被正确接收响应参数。最终的代码的步骤是使用一个稍微定制THTTPRIO对象,将允许文字参数。窍门这部分是为了确保后得到了界面上的选项适用;之前这样做是行不通的。下面是从我的例子(只是代码片段)的代码。

At this point, packets will go back and forth between Delphi and C# - but parameters won't work properly. The C# will receive all parameters as nulls and Delphi doesn't seem to be receiving response parameters properly. The final code step is to use a slightly customized THTTPRIO object that will allow for literal parameters. The trick to this part is to make sure that the option is applied AFTER the interface has been obtained; doing it before won't work. Here's the code from my example (just snippets).

修正第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服务!

And now - my Delphi 2007 app can talk to the C#, stand-alone, non-IIS, WCF web service!

这篇关于如何消费托管,WCF,C#的Web服务从2007年德尔福非IIS?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆