以编程方式创建的 Web 服务在客户端服务调用时失败
Programmatically created web service fails on client service call
我创建了一个控制台应用程序项目来以编程方式托管 Web 服务,但是当我尝试为我的 Web 服务创建客户端代理并在其上调用方法时,出现以下错误:
An error occurred while making the HTTP request to
https://localhost:8000/FileRetrievalPoC. This could be due to the fact
that the server certificate is not configured properly with HTTP.SYS
in the HTTPS case. This could also be caused by a mismatch of the
security binding between the client and the server.
其内部异常:
The underlying connection was closed: An unexpected error occurred on
a send.
其内部异常:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host.
其内部异常:
An existing connection was forcibly closed by the remote host
Program.cs:
class Program
{
static void Main(string[] args)
{
var address = "https://localhost:8000/FileRetrievalPoC";
Console.WriteLine("Starting a service at {0}...", address);
FileRetrievalService.Start(address, StoreLocation.LocalMachine, StoreName.My, "localhost");
Console.WriteLine("Service started.");
Console.WriteLine("Press Enter to create a new proxy client and call the Get method.");
Console.WriteLine("Press Escape to end the application.");
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Enter)
{
var proxy = FileRetrievalService.Connect(address, "localhost", "exampleUsername", "examplePassword", StoreLocation.LocalMachine, StoreName.My, "localhost");
proxy.Get(@"C:\Users\User\Desktop\Document.txt");
((IClientChannel)proxy).Close();
}
else if (key.Key == ConsoleKey.Escape)
break;
}
FileRetrievalService.Stop();
}
}
IFileRetrieval.cs:
[ServiceContract]
public interface IFileRetrieval
{
[OperationContract]
string Get(string path);
[OperationContract]
void Set(string path, string contents);
}
FileRetrievalService.cs:
class FileRetrievalService : IFileRetrieval
{
private static BasicHttpsBinding _binding = new BasicHttpsBinding()
{
Name = "FileRetrievalPoC",
HostNameComparisonMode = HostNameComparisonMode.Exact,
Security = new BasicHttpsSecurity()
{
Message = new BasicHttpMessageSecurity()
{
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
ClientCredentialType = BasicHttpMessageCredentialType.UserName
},
Mode = BasicHttpsSecurityMode.TransportWithMessageCredential,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows
}
},
SendTimeout = TimeSpan.FromMinutes(1),
CloseTimeout = TimeSpan.FromMinutes(1),
OpenTimeout = TimeSpan.FromMinutes(1),
ReceiveTimeout = TimeSpan.FromMinutes(1)
};
private static ChannelFactory<IFileRetrieval> _channelFactory;
private static ServiceHost _host;
public static void Start(string address, StoreLocation location, StoreName name, string subject)
{
_host = new ServiceHost(typeof(FileRetrievalService));
_host.Credentials.ServiceCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_host.AddServiceEndpoint(typeof(IFileRetrieval), _binding, address);
_host.Open();
}
public static void Stop()
{
if (_host != null)
_host.Close();
if (_channelFactory != null)
_channelFactory.Close();
}
public static IFileRetrieval Connect(string address, string domain, string username, string password, StoreLocation location, StoreName name, string subject)
{
if (_channelFactory == null)
_channelFactory = new ChannelFactory<IFileRetrieval>(_binding, address);
_channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_channelFactory.Credentials.UserName.UserName = username;
_channelFactory.Credentials.UserName.Password = password;
_channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
return _channelFactory.CreateChannel();
}
public string Get(string path)
{
throw new NotImplementedException();
}
public void Set(string path, string contents)
{
throw new NotImplementedException();
}
}
这一切都是以编程方式完成的,我查看了 Stack Overflow 但找不到发生这种情况的充分理由。有谁知道问题出在哪里?您可以将此源代码添加到一个新的控制台应用程序中,然后 运行 它在您的本地计算机上进行尝试,并亲眼见证它的发生。它是SSL证书吗?如果是这样,我怎样才能因为这里的错误原因而变得更加冗长?这不是一个很有帮助的例外。
编辑:我想我可能在这里漏掉了一步,such as using netsh
to bind a certificate to my machine's port。
我的问题是 I did not use netsh
to bind the certificate to my machine's port。打开管理命令提示符并调用:
netsh http add sslcert ipport=0.0.0.0:8000 appid=<A randomly generated GUID for your application> certhash=<Your localhost certificate's thumbprint from the default MY store, which is under Local Machine -> Personal, which you can get from the MMC Certificates snap-in>
下一步是确保它在客户端受信任的人之下。至少,对我来说是这样,因为我使用的是我为 localhost
测试目的生成的自签名证书。因此,例如,如果您从 Comodo 或 Verisign 或其他一些 CA 获得证书,您的证书可能根本不需要这个,因为根 CA 将被信任,通常默认情况下 Windows,因为根 CA public 这些证书开箱即用,位于证书 MMC 管理单元的受信任的根证书颁发机构部分。
然后,您需要做的就是确保您的计算机凭据正确无误。我正在使用 Windows 身份验证,因此它会尝试断言我的凭据有效(这些在我调用 Connect 方法的代码中指定)。
随着年龄的增长,我发现我越来越倾向于自己回答问题...
编辑:您只需使用 Trusted People 商店即可完成所有这些操作。如果你确实想这样做,那么在我上面的代码中使用 StoreName.TrustedPeople
,在你的 netsh
命令中,指定 certstorename=TrustedPeople
,否则它默认为 MY
,这是 Personal
存储在证书 MMC 管理单元中。
此外,要删除已绑定的 SSL 证书,请使用 netsh http delete sslcert ipport=0.0.0.0:8000
此外,我的代码不需要设置客户端证书即可运行,因此可以从 Connect
方法中删除。如果你们中的任何人计划在生产中使用它,还需要进一步加强。
我创建了一个控制台应用程序项目来以编程方式托管 Web 服务,但是当我尝试为我的 Web 服务创建客户端代理并在其上调用方法时,出现以下错误:
An error occurred while making the HTTP request to https://localhost:8000/FileRetrievalPoC. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
其内部异常:
The underlying connection was closed: An unexpected error occurred on a send.
其内部异常:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
其内部异常:
An existing connection was forcibly closed by the remote host
Program.cs:
class Program
{
static void Main(string[] args)
{
var address = "https://localhost:8000/FileRetrievalPoC";
Console.WriteLine("Starting a service at {0}...", address);
FileRetrievalService.Start(address, StoreLocation.LocalMachine, StoreName.My, "localhost");
Console.WriteLine("Service started.");
Console.WriteLine("Press Enter to create a new proxy client and call the Get method.");
Console.WriteLine("Press Escape to end the application.");
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Enter)
{
var proxy = FileRetrievalService.Connect(address, "localhost", "exampleUsername", "examplePassword", StoreLocation.LocalMachine, StoreName.My, "localhost");
proxy.Get(@"C:\Users\User\Desktop\Document.txt");
((IClientChannel)proxy).Close();
}
else if (key.Key == ConsoleKey.Escape)
break;
}
FileRetrievalService.Stop();
}
}
IFileRetrieval.cs:
[ServiceContract]
public interface IFileRetrieval
{
[OperationContract]
string Get(string path);
[OperationContract]
void Set(string path, string contents);
}
FileRetrievalService.cs:
class FileRetrievalService : IFileRetrieval
{
private static BasicHttpsBinding _binding = new BasicHttpsBinding()
{
Name = "FileRetrievalPoC",
HostNameComparisonMode = HostNameComparisonMode.Exact,
Security = new BasicHttpsSecurity()
{
Message = new BasicHttpMessageSecurity()
{
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
ClientCredentialType = BasicHttpMessageCredentialType.UserName
},
Mode = BasicHttpsSecurityMode.TransportWithMessageCredential,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows
}
},
SendTimeout = TimeSpan.FromMinutes(1),
CloseTimeout = TimeSpan.FromMinutes(1),
OpenTimeout = TimeSpan.FromMinutes(1),
ReceiveTimeout = TimeSpan.FromMinutes(1)
};
private static ChannelFactory<IFileRetrieval> _channelFactory;
private static ServiceHost _host;
public static void Start(string address, StoreLocation location, StoreName name, string subject)
{
_host = new ServiceHost(typeof(FileRetrievalService));
_host.Credentials.ServiceCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_host.AddServiceEndpoint(typeof(IFileRetrieval), _binding, address);
_host.Open();
}
public static void Stop()
{
if (_host != null)
_host.Close();
if (_channelFactory != null)
_channelFactory.Close();
}
public static IFileRetrieval Connect(string address, string domain, string username, string password, StoreLocation location, StoreName name, string subject)
{
if (_channelFactory == null)
_channelFactory = new ChannelFactory<IFileRetrieval>(_binding, address);
_channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_channelFactory.Credentials.UserName.UserName = username;
_channelFactory.Credentials.UserName.Password = password;
_channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
return _channelFactory.CreateChannel();
}
public string Get(string path)
{
throw new NotImplementedException();
}
public void Set(string path, string contents)
{
throw new NotImplementedException();
}
}
这一切都是以编程方式完成的,我查看了 Stack Overflow 但找不到发生这种情况的充分理由。有谁知道问题出在哪里?您可以将此源代码添加到一个新的控制台应用程序中,然后 运行 它在您的本地计算机上进行尝试,并亲眼见证它的发生。它是SSL证书吗?如果是这样,我怎样才能因为这里的错误原因而变得更加冗长?这不是一个很有帮助的例外。
编辑:我想我可能在这里漏掉了一步,such as using netsh
to bind a certificate to my machine's port。
我的问题是 I did not use netsh
to bind the certificate to my machine's port。打开管理命令提示符并调用:
netsh http add sslcert ipport=0.0.0.0:8000 appid=<A randomly generated GUID for your application> certhash=<Your localhost certificate's thumbprint from the default MY store, which is under Local Machine -> Personal, which you can get from the MMC Certificates snap-in>
下一步是确保它在客户端受信任的人之下。至少,对我来说是这样,因为我使用的是我为 localhost
测试目的生成的自签名证书。因此,例如,如果您从 Comodo 或 Verisign 或其他一些 CA 获得证书,您的证书可能根本不需要这个,因为根 CA 将被信任,通常默认情况下 Windows,因为根 CA public 这些证书开箱即用,位于证书 MMC 管理单元的受信任的根证书颁发机构部分。
然后,您需要做的就是确保您的计算机凭据正确无误。我正在使用 Windows 身份验证,因此它会尝试断言我的凭据有效(这些在我调用 Connect 方法的代码中指定)。
随着年龄的增长,我发现我越来越倾向于自己回答问题...
编辑:您只需使用 Trusted People 商店即可完成所有这些操作。如果你确实想这样做,那么在我上面的代码中使用 StoreName.TrustedPeople
,在你的 netsh
命令中,指定 certstorename=TrustedPeople
,否则它默认为 MY
,这是 Personal
存储在证书 MMC 管理单元中。
此外,要删除已绑定的 SSL 证书,请使用 netsh http delete sslcert ipport=0.0.0.0:8000
此外,我的代码不需要设置客户端证书即可运行,因此可以从 Connect
方法中删除。如果你们中的任何人计划在生产中使用它,还需要进一步加强。