Jas*_*ger 6 c# delphi wcf web-services
我编写了一个相当简单的小型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();
Run Code Online (Sandbox Code Playgroud)
其余的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);
}
Run Code Online (Sandbox Code Playgroud)
我可以轻松地创建使用此服务的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;
Run Code Online (Sandbox Code Playgroud)
上面的代码在遇到"CoreI.AuthenticateUser(Auth);"时会产生错误.错误是" 无法处理消息,因为内容类型'text/xml; charset ="utf-8"不是预期类型'application/soap + xml; charset = utf-8. "
我怀疑我在某处有一个愚蠢的小错误,可能是在导入WSDL或连接选项之类的时候.有人可以帮忙吗?
找到了解决方案。它由多个部分组成,需要对 C# 端进行一些更改,而对 Delphi 端则需要进行更多更改。请注意,这是使用 Delphi 2007 和 Visual Studio 2008 进行测试的。
C# 方面:使用 BasicHttpBinding 而不是 WSHttpBinding。
修复步骤 1
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.None;
Run Code Online (Sandbox Code Playgroud)
此更改将解决 Delphi 端的 application/soap+xml 错误。
Delphi 2007 方面:针对修改后的 C# Web 服务运行现在将生成如下错误:
由于 EndpointDispatcher 上的 ContractFilter 不匹配,无法在接收方处处理带有消息“带有 Action 的消息”的异常类 ERemotableException。这可能是因为合同不匹配(发送者和接收者之间的操作不匹配)或发送者和接收者之间的绑定/安全不匹配。检查发送方和接收方是否具有相同的合同和相同的绑定(包括安全要求,例如消息、传输、无)。
要解决此问题,请将 SOAPActions 添加到所有支持的接口。这是我的代码中的示例;这必须在 import-from-WSDL-PAS-file 的初始化部分进行所有 InvRegistry 更改之后完成:
修复步骤 2
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IVMProvisionCore), 'http://Cisco.VMProvision.Core/CoreServices/%operationName%');
Run Code Online (Sandbox Code Playgroud)
类型名称和 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);
Run Code Online (Sandbox Code Playgroud)
此时,数据包将在 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];
Run Code Online (Sandbox Code Playgroud)
现在 - 我的 Delphi 2007 应用程序可以与 C#、独立、非 IIS、WCF Web 服务通信!