WCF 服务同时支援 http:// 和 https://
WCF 服务同时支援 http:// 和 https://
摘要:用一个简单范例说明如何让 WCF 服务同时支援 HTTP 和 HTTPS。
工具:Visual Studio 2012 with Update 1
Step 1. 建立 WCF 服务
操作:
建立新项目,项目范本选择 ASP.NET Empty Web Application,命名为 WcfHttpsDemo。
加入新的 WCF 服务,命名为 MyService.svc。默认范本会帮我们产生 IMyService.cs 和 MyService.cs,里面有个 DoWork 方法。
此时的 web.config 内容会像这样:
<configuration><system.web><compilation debug="true" targetFramework="4.5" /><httpRuntime targetFramework="4.5" /></system.web><system.serviceModel><behaviors><serviceBehaviors><behavior name=""><serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /></behavior></serviceBehaviors></behaviors><serviceHostingEnvironment aspNetCompatibilityEnabled="true"multipleSiteBindingsEnabled="true" /></system.serviceModel></configuration>
如果是 HTTP,这样的默认组态就能用了,WCF 用户端应用程序只要加入此服务参考,便可顺利调用服务。但我们想要使用 HTTPS,而且是同时支援 HTTP 和 HTTPS,此默认组态当然就不够用了。
要让这个 WCF 服务接受 HTTP 和 HTTPS 请求,可在 web.config 的
<services><service name="WcfHttpsDemo.MyService"><endpoint address="" binding="basicHttpBinding" bindingConfiguration="HttpBinding" contract="WcfHttpsDemo.IMyService" /><endpoint address="" binding="basicHttpsBinding" bindingConfiguration="HttpsBinding" contract="WcfHttpsDemo.IMyService" /></service></services><bindings><basicHttpBinding><binding name="HttpBinding"><security mode="None"><transport clientCredentialType="None"></transport></security></binding></basicHttpBinding><basicHttpsBinding><binding name="HttpsBinding"><security mode="Transport"><transport clientCredentialType="None"></transport></security></binding></basicHttpsBinding></bindings>
注意两个 binding 参数的差异:HttpBinding 的安全模式(security 元素的 model 属性)为 "None",而 HttpsBinding 的安全模式为 "Transport"。如果将两个 binding 的安全模式设为相同,例如二者皆为 "Transport",在存取服务时会出现错误信息:
A binding instance has already been associated to listen URI 'https://michael-a43s/MyService.svc'. If two endpoints want to share the same ListenUri, they must also share the same binding object instance. The two conflicting endpoints were either specified in AddServiceEndpoint() calls, in a config file, or a combination of AddServiceEndpoint() and config.
还有一个要注意的地方,是当我们使用 IIS Express 作为开发时期的服务器时,必须把 ASP.NET 应用程序项目的 SSL Enabled 属性改为 True。你可以在 Solution Explorer 中点击项目名称,然后到属性窗口中设置 SSL Enabled 属性。参考下图:

少了此动作,在 web.config 中加入前述组态(支援 HTTP 和 HTTPS)之后,用浏览器存取 WSDL 时就会出现错误信息:
Could not find a base address that matches scheme https for the endpoint with binding BasicHttpsBinding. Registered base address schemes are [http].
Step 2. 部署 WCF 服务
部署到本机 IIS,站台名称取名 WcfDemo,系结 80 和 443 port。如下图:

在建立 HTTPS 系结时必须指定 SSL 凭证。在此范例中,我用的是 IIS Express 开发凭证:
试以浏览器查看 WSDL 文件,网址为 http://localhost/MyService.svc?wsdl。结果应该会先看到如下图的警告:

选择‘继续浏览此网站’之后,就会显示 WSDL。注意里面有两个

Step 3:撰写 WCF 用户端程序
操作:
建立一个 Windows Forms 应用程序项目。
加入服务参考,地址输入 http://localhost/MyService.svc。命名空间指定为 "Demo"。
接着修改 app.config 内容,如下:
<?xml version="1.0" encoding="utf-8" ?><configuration><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup><system.serviceModel><bindings><basicHttpBinding><binding name="BasicHttpBinding_IMyService"><security mode="None"><transport clientCredentialType="None"></transport></security></binding></basicHttpBinding><basicHttpsBinding><binding name="BasicHttpsBinding_IMyService"><security mode="Transport"><transport clientCredentialType="None"></transport></security></binding></basicHttpsBinding></bindings><client><endpoint name="BasicHttpBinding_IMyService" contract="Demo.IMyService"address="http://michael-a43s/MyService.svc"binding="basicHttpBinding"bindingConfiguration="BasicHttpBinding_IMyService" /><endpoint name="SecureHttpBinding_IMyService" contract="Demo.IMyService"address="https://michael-a43s/MyService.svc"binding="basicHttpsBinding"bindingConfiguration="BasicHttpsBinding_IMyService" /></client></system.serviceModel></configuration>
与服务器端的 web.config 类似,此用户端应用程序组态档中也有两组 binding 和 endpoint,分别设置 HTTP 和 HTTPS 的参数。不同的地方是这里的两个 endpoint 元素都有指定 name 参数,以便程序在建立 proxy 对象时能够明确指定使用哪一个 endpoint。
为了方便测试,我在 form 上面放一个 ComboBox,并预先把两个 endpoint 的名称塞给 ComboBox 的 Items 集合,参考下图:

接着撰写按钮 "Call MySevice" 点击事件的处理常式:
private void button1_Click(object sender, EventArgs e){var client = new Demo.MyServiceClient(comboBox1.Text);string s = client.DoWork("Michael");MessageBox.Show(s);}
执行看看。首先选择 BasicHttpBinding_IMyService,这应该没问题。接着改用 SecureHttpBinding_IMyService,结果按下 "Call MyService" 按钮之后却出现错误:
无法利用授权 'michael-a43s' 为 SSL/TLS 安全通道建立信任关系。
英文信息是 "Could not establish trust relationship for the SSL/TLS secure channel with authority 'michael-a43s'"。其中 'michael-a43s' 是我的本机电脑名称。
这是因为我在服务器端使用的 SSL 凭证是 IIS Express 开发版凭证的缘故。试过将 IIS Express 开发凭证从个人凭证区搬到‘受信任的根凭证授信单位’之下,还是出现同样错误。
碰到这个状况,一个暂时解法是强迫应用程序忽略凭证是否有效,范例如下:
private void Form1_Load(object sender, EventArgs e){ServicePointManager.ServerCertificateValidationCallback = (object s,System.Security.Cryptography.X509Certificates.X509Certificate certificate,System.Security.Cryptography.X509Certificates.X509Chain chain,System.Net.Security.SslPolicyErrors sslPolicyErrors) >={if (certificate.Subject.Contains("localhost")){return true;}return false;};}
这段源程序的作用是当 ServicePointManager 检查凭证时,若凭证主体(subject)名称包含 "localhost" 字样,就一律放行。注:IIS Express 开发凭证的主体名称是 "localhost"。
正式环境通常会安装有效的 SSL 凭证,应该就不会用到此临时解法吧。
Trouble Shooting
有一次,我将我的 ASP.NET 应用程序部署到第二台机器之后,存取该应用程序中的 WCF 服务时出现错误:
Could not find a base address that matches scheme http for the endpoint with binding BasicHttpBinding. Registered base address schemes are [https].
由于另一台机器也有部署相同的应用程序,源程序和组态档完全相同。经过比对之后,发现两个网站唯一的差别是第二台机器上的网站没有设置 HTTPS 系结。加上 HTTPS 系结并指定一个 SSL 凭证之后,问题便消失了。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/33942.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
