C# DLL 从C++应用程序调用 SOAP Web 服务

C# DLL Calling SOAP Web Service From C++ App

本文关键字:SOAP Web 服务 调用 应用程序 DLL C++      更新时间:2023-10-16

在大量在线文章之后,我创建了一个简单的 C# DLL 类库,其中只有一个名为 Add 的方法。 它接受 2 个整数并返回如下所示的整数。 我还转到项目属性>生成>并选择了"注册 COM 互操作"选项:

namespace CSDLL
{
[ComVisible(true)]
public interface IMyClass
{
int Add(int x, int y);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MyClass : IMyClass
{
public int Add(int x, int y)
{
return x + y;
}
}
}

我成功地构建了它(作为管理员(,它生成了CSDLL.dllCSDLL.tlb文件。

接下来,我创建了一个简单的C++控制台应用程序,如下所示:

#include "stdafx.h"
#include <Windows.h>
#import "C:pathtomyCSDLL.tlb" no_namespace
int main()
{
CoInitialize(NULL);
IMyClassPtr obj;
obj.CreateInstance(__uuidof(MyClass));
printf("Add result = %dn", obj->Add(2, 5));
CoUninitialize();
getchar();
return 0;
}

如果我运行它,我会在控制台窗口上打印预期结果。 所以,这一切都很好。

接下来,我修改了Add方法,以便它调用 SOAP 终结点,而不是添加 2 个整数。 我将代码包装在try...catch 如果 SOAP 按预期执行,我返回 1,如果它没有返回我期望的内容,则返回 0,并且我从 catch 块内返回 2,这意味着有一个这样的异常:

public int Add()
{
try
{
BasicHttpsBinding binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.UseDefaultWebProxy = false;
EndpointAddress address = new EndpointAddress(myEndPointString);
// create service myService by passing it binding and endpoint address
// pass necessary parameters to the service
// set ClientCredentials for my service
// get response from the service
MyServiceResponse resp = myService.DoSomething();
if (resp.acknowledged)
{
return 1;
}
else
{
return 0;
}
}
catch (Exception ex)
{
// just return 2 in case of an exception
return 2;
}
}

如果我从C++控制台应用程序调用这个修改后的 DLL,它总是返回 2 = 这意味着我上面的代码抛出了一些异常并咳嗽。 我使用的是.NET Framework 4.8。

但是,如果我从通过添加对上述 C# DLL 的引用创建的 C# 控制台应用程序调用它,则对Add的调用返回 1 = 意味着它成功执行,我希望从中获得结果。

因此,同一个 C# DLL 返回 2 个不同的结果,具体取决于它是从C++还是 C# 控制台应用程序调用的。

设置一些断点并调试我的 DLL 后,我发现对DoSomething响应的调用抛出异常,并显示以下消息:

异常消息: 消息 ="向 https://server-address:port/path 发出 HTTP 请求时出错。这可能是由于在 HTTPS 情况下,服务器证书未使用 HTTP.SYS 正确配置。这也可能是由客户端和服务器之间的安全绑定不匹配引起的。 内部异常消息: 消息 ="身份验证失败,因为远程方已关闭传输流。

如果从C++控制台应用调用 DLL,而不是从 C# 控制台应用调用相同的 DLL,为什么会出现此问题? 我想它必须与安全性做一些事情,因为如果调用简单的数学Add方法,两者都会执行得很好,但如果调用执行 SOAP 请求的方法,C# 控制台应用程序将执行得很好C++而控制台应用程序会导致 DLL 抛出异常?

经过大量阅读,事实证明这样做的原因是SecurityProtocol被设置为不同的SecurityProtocolType如果从 C# 与 C++ 应用程序调用 C# DLL。

为了解决,在提出任何请求之前,我必须设置如下SecurityProtocol

if (ServicePointManager.SecurityProtocol == (SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls))
{
// This was crucial to do to make web service call work when C# DLL is called 
// from a C++ app.  It turns out that if webservice call is made:
//   1) from C# console app calling C# DLL that makes web service call, 
//      the SecurityProtocol is set to TLS | TLS11 | TLS12 | TLS13
//   2) from C++ console app calling C# DLL that makes web service call,
//      the SecurityProtocol is set to SSL3 | TLS
// In case of 2) above, the call would throw exception as explained above
// whereas 1) would work just fine.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls 
| SecurityProtocolType.Tls11 
| SecurityProtocolType.Tls12; 
// TLS13 was not available for some reason, so did not set it here
}