WCF,HTTPS与HTTP

有两个样本

对于HTTP :

using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceModel.Security; namespace ConsoleApplication1 { internal class Program { private static void Main(string[] args) { string addressHttps = String.Format("http://{0}:51222", Dns.GetHostEntry("").HostName); var wsHttpBinding = new BasicHttpBinding(); var serviceHost = new ServiceHost(typeof (HelloWorldService), new Uri(addressHttps)); Type endpoint = typeof (IHelloWorldService); serviceHost.AddServiceEndpoint(endpoint, wsHttpBinding, "hello"); Uri uri = new Uri(serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri + "/mex"); var smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; smb.HttpGetUrl = uri; serviceHost.Description.Behaviors.Add(smb); Console.Out.WriteLine("Mex address " + smb.HttpGetUrl); try { serviceHost.Open(); string address = serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri; Console.WriteLine("Listening @ {0}", address); Console.WriteLine("Press enter to close the service"); Console.ReadLine(); serviceHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("A commmunication error occurred: {0}", ce.Message); Console.WriteLine(); } catch (Exception exc) { Console.WriteLine("An unforseen error occurred: {0}", exc.Message); Console.ReadLine(); } } } [ServiceContract] public interface IHelloWorldService { [OperationContract] string SayHello(string name); } public class HelloWorldService : IHelloWorldService { #region IHelloWorldService Members public string SayHello(string name) { return string.Format("Hello, {0}", name); } #endregion } } 

对于HTTPS

 using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceModel.Security; namespace ConsoleApplication1 { internal class Program { private static void Main(string[] args) { string addressHttps = String.Format("https://{0}:51222", Dns.GetHostEntry("").HostName); var wsHttpBinding = new BasicHttpBinding(); wsHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport; var serviceHost = new ServiceHost(typeof (HelloWorldService), new Uri(addressHttps)); Type endpoint = typeof (IHelloWorldService); serviceHost.AddServiceEndpoint(endpoint, wsHttpBinding, "hello"); serviceHost.Credentials.ServiceCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "nameofsertificate"); serviceHost.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck; Uri uri = new Uri(serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri + "/mex"); var smb = new ServiceMetadataBehavior(); smb.HttpsGetEnabled = true; smb.HttpsGetUrl = uri; serviceHost.Description.Behaviors.Add(smb); Console.Out.WriteLine("Mex address " + smb.HttpsGetUrl); try { serviceHost.Open(); string address = serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri; Console.WriteLine("Listening @ {0}", address); Console.WriteLine("Press enter to close the service"); Console.ReadLine(); serviceHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("A commmunication error occurred: {0}", ce.Message); Console.WriteLine(); } catch (Exception exc) { Console.WriteLine("An unforseen error occurred: {0}", exc.Message); Console.ReadLine(); } } public static bool ValidateCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { foreach (X509ChainStatus chainStatus in chain.ChainStatus) { if (chainStatus.Status == X509ChainStatusFlags.Revoked) { return true; } } } return false; } } [ServiceContract] public interface IHelloWorldService { [OperationContract] string SayHello(string name); } public class HelloWorldService : IHelloWorldService { #region IHelloWorldService Members public string SayHello(string name) { return string.Format("Hello, {0}", name); } #endregion } } 

这些示例正在启动而没有错误,但如果我尝试创建客户端,我有两种不同的情况:

HTTP – 使用地址创建客户端成功

 http://localhost:51222/hello/mex 

HTTPS失败了。 HTTPS的地址是:

 https://localhost:51222/hello/mex 

HTTPS的错误消息是:

下载https://localhost:51222/hello/mex 。 底层连接已关闭:发送时发生意外错误。 身份validation失败,因为远程方已关闭传输流。 元数据包含无法解析的引用: https://localhost:51222/hello/mex 。 将HTTP请求发送到https://localhost:51222/hello/mex发生错误。 这可能是由于在HTTPS情况下使用HTTP.SYS未正确配置服务器证书。 这也可能是由客户端和服务器之间的安全绑定不匹配引起的。 底层连接已关闭:发送时发生意外错误。 身份validation失败,因为远程方已关闭传输流。 如果在当前解决方案中定义了服务,请尝试构建解决方案并再次添加服务引用。

我在哪里弄错了?

我找到了解决方案如何解决这个问题。 所以,正确的服务器代码是:

 using System; using System.Net; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; using System.ServiceModel.Description; namespace ConsoleApplication1 { internal class Program { private static void Main(string[] args) { string addressHttps = String.Format("https://{0}:9010", Dns.GetHostEntry("").HostName); var wsHttpBinding = new BasicHttpBinding(); wsHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport; wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; var serviceHost = new ServiceHost(typeof (HelloWorldService), new Uri(addressHttps)); Type endpoint = typeof (IHelloWorldService); serviceHost.AddServiceEndpoint(endpoint, wsHttpBinding, "hello"); serviceHost.Credentials.ServiceCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "sergiiz2"); var smb = new ServiceMetadataBehavior(); smb.HttpsGetEnabled = true; smb.HttpsGetUrl = new Uri(serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri + "/mex"); serviceHost.Description.Behaviors.Add(smb); Console.Out.WriteLine(smb.HttpsGetUrl); try { serviceHost.Open(); string address = serviceHost.Description.Endpoints[0].ListenUri.AbsoluteUri; Console.WriteLine("Listening @ {0}", address); Console.WriteLine("Press enter to close the service"); Console.ReadLine(); serviceHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("A commmunication error occurred: {0}", ce.Message); Console.WriteLine(); } catch (Exception exc) { Console.WriteLine("An unforseen error occurred: {0}", exc.Message); Console.ReadLine(); } } } [ServiceContract] public interface IHelloWorldService { [OperationContract] string SayHello(string name); } public class HelloWorldService : IHelloWorldService { #region IHelloWorldService Members public string SayHello(string name) { return string.Format("Hello, {0}", name); } #endregion } } 

以及与证书相关的一些案例: – 生成证书:

 makecert -r -pe -n "CN=%hostname%" -b 01/01/2000 -e 01/01/2050 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 
  • 将url添加到收听中

    httpcfg set urlacl -u https:// *:9010 / -a D:(A ;; GX ;;; S-1-5-21-1144070942-1563683482-3278297161-1114)

  • 对http.sys说要知道端口9010上的ssl证书

    httpcfg set ssl / i 0.0.0.0:9010 / h 8c6e12be537186​​0adfb84cd2ed2351a900731bb8 / g“{a2c24c79-b0ef-4783-8ed8-d93836fec137}”

    并且所有工作都没有问题。

看看这个答案: 如何以编程方式为自托管WCF服务安装SSL证书 。

你是否正在使httpsGetUri与你的mex端点地址相同? httpsGetUri用于发布WSDL,而不是为mex端点提供服务。 你应该清楚这一点。