[在线上有大量文章之后,我创建了一个简单的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.dll和CSDLL.tlb文件。
接下来,我创建了一个简单的C ++控制台应用程序,如下所示:
#include "stdafx.h"
#include <Windows.h>
#import "C:\path\to\my\CSDLL.tlb" no_namespace
int main()
{
CoInitialize(NULL);
IMyClassPtr obj;
obj.CreateInstance(__uuidof(MyClass));
printf("Add result = %d\n", obj->Add(2, 5));
CoUninitialize();
getchar();
return 0;
}
如果运行此命令,则会在控制台窗口上打印出预期的结果。所以,那很好。
接下来,我修改了我的Add方法,以便它不添加2个整数,而是调用SOAP端点。我将代码包装在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响应的调用引发了异常,并显示以下消息:
异常消息:Message =“向https://server-address:port/path发出HTTP请求时发生错误。这可能是由于在HTTPS情况下未使用HTTP.SYS正确配置服务器证书。这也可能是由于客户端和服务器之间的安全绑定。内部异常消息:消息=“验证失败,因为远程方已关闭传输流。”
为什么从C ++控制台应用程序调用DLL而没有从C#控制台应用程序调用相同的DLL,为什么会出现此问题?我认为它必须具有安全性,因为如果调用简单的数学Add方法,两者都将执行得很好,但是如果调用执行SOAP请求的方法,则C#控制台应用程序将执行得很好,而C ++控制台应用程序将导致DLL引发异常?
经过大量阅读后,发现原因是SecurityProtocol设置为不同的SecurityProtocolType如果从C#vs C ++应用程序调用C#DLL。
为了解决,在发出任何请求之前,我必须像下面那样设置SecuritpProtocol:
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
}