通过 ComVisible DLL 访问 SSL 加密的 WebResource 失败
Access to an SSL encrypted WebResource fails via a ComVisible DLL
我使用 C# 创建了一个 DLL,该 DLL 使用 WebRequest 来访问 WebService。此 DLL 被声明为 ComVisible,因此我可以将其与 Delphi 一起使用。
如果 WebRequest 未加密,则一切正常。但是当我使用 https 作为协议时,我收到以下错误消息:
The underlying connection was closed: An unexpected error occurred on a send.
Unable to read data from the transport connection: Eine vorhandene Verbindung wurde vom Remotehost geschlossen.
但是当我从 .NET 应用程序中使用同一个 DLL 时,它仍然有效。
我创建了一个最小示例项目来查看错误是否可重现,我遇到了同样的问题。
这是带有 webrequest 的代码
[Guid("D0AAE68A-D2C0-4015-8DE6-471879267418"), ClassInterface(ClassInterfaceType.AutoDual), ProgId("WebRequestTest")]
[ComVisible(true)]
public class ComClient
{
public bool Authenticate(string customer)
{
var request = WebRequest.Create(@"https://server.azurewebsites.net/api/authenticate?apikey=xxxx&customer=" + customer);
request.Method = "GET";
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
{
string responseString = streamReader.ReadToEnd();
Trace.WriteLine(responseString);
return true;
}
}
}
catch (Exception exc)
{
Trace.WriteLine(exc);
return false;
}
}
}
在delphi代码也是小而简单
procedure TForm1.btnTestClick(Sender: TObject);
var
client: TComClient;
begin
client := TComClient.Create(self);
if client.Authenticate('xxxxxxxx') then
Application.MessageBox('Ok', '', MB_OK + MB_ICONINFORMATION)
else
Application.MessageBox('Error', '', MB_OK + MB_ICONINFORMATION);
client.Free;
client := nil;
end;
为了使用纯 .NET 对此进行测试,我创建了一个小型单元测试,它可以正常运行。
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ComClient client = new ComClient();
bool result = client.Authenticate("xxxxxxxx");
Assert.IsTrue(result);
}
}
在我看来,当从 COM 应用程序使用 .NET 程序集时,.NET 框架没有完全初始化。
如前所述,如果我切换到 http 而不是 https,调用会正常工作。
我通过 Tav 的评论找到了解决方案。 ServicePointManager.SecurityProtocol 包含协议 TLS | TLS11 | .NET 应用程序的 TLS12,只有协议 SSL3 和 TLS 被指定为 COM 应用程序。
由于 Azure AppServices 默认配置为最低 TLS 版本为 1.2,因此您必须相应地重新配置 AppService 或在 COM 程序集中显式添加 TLS1.2。
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
我使用 C# 创建了一个 DLL,该 DLL 使用 WebRequest 来访问 WebService。此 DLL 被声明为 ComVisible,因此我可以将其与 Delphi 一起使用。 如果 WebRequest 未加密,则一切正常。但是当我使用 https 作为协议时,我收到以下错误消息:
The underlying connection was closed: An unexpected error occurred on a send.
Unable to read data from the transport connection: Eine vorhandene Verbindung wurde vom Remotehost geschlossen.
但是当我从 .NET 应用程序中使用同一个 DLL 时,它仍然有效。
我创建了一个最小示例项目来查看错误是否可重现,我遇到了同样的问题。
这是带有 webrequest 的代码
[Guid("D0AAE68A-D2C0-4015-8DE6-471879267418"), ClassInterface(ClassInterfaceType.AutoDual), ProgId("WebRequestTest")]
[ComVisible(true)]
public class ComClient
{
public bool Authenticate(string customer)
{
var request = WebRequest.Create(@"https://server.azurewebsites.net/api/authenticate?apikey=xxxx&customer=" + customer);
request.Method = "GET";
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
{
string responseString = streamReader.ReadToEnd();
Trace.WriteLine(responseString);
return true;
}
}
}
catch (Exception exc)
{
Trace.WriteLine(exc);
return false;
}
}
}
在delphi代码也是小而简单
procedure TForm1.btnTestClick(Sender: TObject);
var
client: TComClient;
begin
client := TComClient.Create(self);
if client.Authenticate('xxxxxxxx') then
Application.MessageBox('Ok', '', MB_OK + MB_ICONINFORMATION)
else
Application.MessageBox('Error', '', MB_OK + MB_ICONINFORMATION);
client.Free;
client := nil;
end;
为了使用纯 .NET 对此进行测试,我创建了一个小型单元测试,它可以正常运行。
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ComClient client = new ComClient();
bool result = client.Authenticate("xxxxxxxx");
Assert.IsTrue(result);
}
}
在我看来,当从 COM 应用程序使用 .NET 程序集时,.NET 框架没有完全初始化。 如前所述,如果我切换到 http 而不是 https,调用会正常工作。
我通过 Tav 的评论找到了解决方案。 ServicePointManager.SecurityProtocol 包含协议 TLS | TLS11 | .NET 应用程序的 TLS12,只有协议 SSL3 和 TLS 被指定为 COM 应用程序。 由于 Azure AppServices 默认配置为最低 TLS 版本为 1.2,因此您必须相应地重新配置 AppService 或在 COM 程序集中显式添加 TLS1.2。
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;