如何消费托管,WCF,C#的Web服务从2007年德尔福非IIS? [英] How to consume non-IIS hosted, WCF, C# web service from Delphi 2007?
问题描述
我写了一个相当简单的小的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屋!