silverLight如要与用户取得更丰富的互动,与DB的频繁交互一定不可避免的。sil做为客户端程序,在客户端置入数据库连接代码是不安全也不可能的,就像js、as不可能放入数据库连接一样。现在sil最多的情况是采取webService 技术如WCF来作为对自身后台数据传输支持。
WCF是一款微软针对windows通讯高度封装的工具、产品,内含在.net Framework2.X以上,使用wcf服务编程,可以很轻易的用VS2005以上的微软编程IDE构建出需要的通讯服务,比如sil所需要的webservice。
接着上次做好的界面规划,小生继续完成这个登录界面与后台 .net 代码的交互。
一、建立wcf项目,便于SL对数据库进行操作。
在sil解决方案资源管理器中,添加新建WCF项目:
把项目命名为:TestWCF 。
在项目文件列表中,可以发现其中的服务接口类:IService.vb,这个类是专定义向外暴露的ws方法,也就是外部调用wcf服务的大门,在接口中定义的方法,符合wcf安全标准的外部程序皆可调用。接口方法的实现类为 Service1.svc ,访问这个服务实现类,即得到反映接口方法详情的WSDL文件。
sl客户端得到用户输入名字及密码后,发送到WCF站点,通过WCF对用户名密码进行安全性校验,判断输入是否通过。
1:打开IService.vb ,加入核对用户输入的接口方法:
- ......
- Function GetUserPass(ByVal uname As String, ByVal upass As String) As Integer
- ......
2:定义了接口方法,则必须在其实现类实现加入的核对输入方法,打开 Service1.svc 加入方法:
- Public Function GetUserPass(ByVal uname As String, ByVal pass As String) As Integer Implements IService1.GetUserPass
- Dim backint As Integer = 0
- Try
- If uname.Trim().Equals("admin888") Then
- If pass.Trim().Equals("123456") Then
- backint = 1
- Else
- backint = 2
- End If
- Else
- backint = 3
- End If
- Catch es As Exception
- backint = 4
- End Try
- Return backint
- End Function
只是为了简便如此核对,当然 admin / 123456 的加密发送、解密核对、从DB读取数据等都可加入。
这时可以按下vs08"启动调试",系统会随即2个虚拟IIS,分属两个不同端口,一个端口承载sl项目,一个端口承载wcf项目。
而系统关联默认浏览器会打开sl项目首页,但不会对wcf服务页面做出反应。新建一个浏览器进程,输入与wcf服务相关的端口站点。如小生的wcf虚拟IIS端口为2368,则可以试着打开 http://localhost:2368/service1.svc ,如无错误则可以看到:
此链接是一个webservice服务wsdl说明文件地址,专供外部调用。至于wcf服务深层运行机制,小生正准备抽时间跟大家一起学习进步,^_^。点击wsdl链接,浏览器会打开wsdl的xml说明文档,可在其中的 wsdl:message wsdl:porttype/wsdl:operation 节点检查是否存在期望调用的webService暴露出来的方法,如存在则表示WCF搭建ws成功。
这样WCF服务搭建成功,开始回头设置SL调用WCF服务。
二、SL与WCF的交互。
1:WCF默认是"wsHttpBinding",但SL支持且只支持 "basicHttpBinding" 绑定。
因此,打开 TestWCF 项目下的 web.config 文件,找到<system.serviceModel>节点,此节点下均用于 webService 暴露方法的定义。在节点下找到
- ......
- <endpoint address="mex" binding="wsHttpBinding" contract="IMetadataExchange"/>
- ......
将其中的 binding 属性更改为:basicHttpBinding ,更改后如下:
- ......
- <endpoint address="mex" binding="basicHttpBinding" contract="IMetadataExchange"/>
- ......
2:之前在"调试"模式中可以看到wsdl文件,皆因web.config中开启了暴露元数据,因此在开发时必须保证此节点为true,部署应用时为false,否则部署也可随意查看服务接口方法,对安全会带来隐患。
- ......
- <serviceMetadata httpGetEnabled="true"/>
- ......
3:SL调用WCF,可以看作是不同网域、不同平台、不同语言的A站点与B站点不同异构平台的webservice应用,是跨域的web操作,而默认中的iis服务器,基于安全不允许这样随意跨域访问,因此需要在web站点根目录中增加相应的配置文件 crossdomain.xml、clientaccesspolicy.xml 进行设置。
如小生WCF服务程序URL为:http://localhost:2368/Service1.svc ,则上述2个文件需要放置在 http://localhost:2368/ 映射的相应目录下。
(1):crossdomain.xml
- <?xml version="1.0" encoding="utf-8" ?>
- <cross-domain-policy>
- <allow-access-from domain="*" />
- <!-- 意为:允许来自任意域名对本web服务站点的任意跨域访问,如要限制跨域访问站点:可将"*"更改为相应域名,多个域名则为多个<allow-access-from ... />节点 -->
- </cross-domain-policy>
(2):clientaccesspolicy.xml
- <?xml version="1.0" encoding="utf-8"?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers="*">
- <domain uri="*"/>
- </allow-from>
- <grant-to>
- <resource path="/" include-subpaths="true"/>
- </grant-to>
- </policy>
- </cross-domain-access>
- </access-policy>
?:到这里找到的SL资料有说到放2文件放任意一个文件都可跨域访问,而任意文件都可让flash跨域访问,但小生实验中是2文件必须都放上才行的,具体原因尚未明朗。
4:WCF的web.config、xml跨域文件配置好以后,意味着sl调用wcf服务的服务端配置完毕,接下来开始配置sl客户端。
在SL项目右键添加服务引用:
单击前往:
确定后,解决方案资源管理器中SL项目会多出Service References相关程序资源。
WCF服务内含输入校验函数:GetUserPass(var1,var2),则需要在客户端通过服务引用对WCF进行调用。
在SL项目中打开page.xaml.vb类,找到btn_ok_Click()事件,在一系列错误判断之后加入如下调用WCF服务端的客户端代码:
- Dim binding As New BasicHttpBinding()
- Dim endPoint As New EndpointAddress("http://localhost:2368/Service1.svc")
- '定义服务引用地址
- Dim client As New ServiceReference1.Service1Client(binding, endPoint)
- '定义服务引用对象
- Dim ev As New EventHandler(Of GetUserPassCompletedEventArgs)(AddressOf client_GetUserPassCompleted)
- AddHandler client.GetUserPassCompleted, AddressOf client_GetUserPassCompleted
- '对服务引用中的输入校验方法:GetUserPass 进行注册事件动作
- client.GetUserPassAsync(Me.txt_uname.Text, Me.txt_upwd.Password)
- '异步调用注册事件
再新建过程:client_GetUserPassCompleted:
- Sub client_GetUserPassCompleted(ByVal sender As Object, ByVal e As GetUserPassCompletedEventArgs)
- Dim h1 As New GridLength(20)
- Dim h2 As New GridLength(10)
- Dim backint As Integer = 0
- Try
- If e.Error Is Nothing Then
- backint = Integer.Parse(e.Result.ToString())
- Else
- backint = 4
- End If
- Catch es As Exception
- backint = 5
- End Try
- Select Case backint
- Case 1
- Me.errname.Height = h1
- Me.lbl_err_uname.Text = "输入正确"
- Case 2
- Me.errpass.Height = h1
- Me.lbl_err_upass.Text = "密码错误"
- Case 3
- Me.errverify.Height = h1
- Me.lbl_err_uverlfy.Text = "用户名错误"
- Case 4
- Me.errall.Height = h1
- Me.lbl_err_uall.Text = "数据库错误"
- Case 5
- Me.lbl_err_uall.Text = "未知错误"
- End Select
- End Sub
启动调试,在输入框中输入"admin888"、"123456",则SL客户端会跨域调用WCF服务方法:GetUserPass校验,最后显示输入正确!