在银光中国网(SilverlightChina.Net)有一篇"Silverlight与常用数据库互操作系列"文章,其中介绍了使用Silverlight存取不同数据库的方法和步骤。但是对于Silverlight存取MS SQL介绍的不够全面,这里我想介绍Silverlight如何通过WCF访问MSSQL数据库存储过程的。希望对大家能够有所帮助。
我们要实现, 用户输入用户名和密码后,点击登录按钮,传递用户名和密码到服务器端, 通过WCF访问MSSQL数据库,调用存储过程,在服务器端对用户名和密码进行匹配,匹配成功,则返回登录成功,否则,则是失败。
在文章开始前,我们需要做一下准备工作,
- 开发环境需求: VS2008 SP1, Silverlight 3 Develop Tools for VS2008 SP1, 客户端Silverlight 3 Runtime, MSSQL 2005 SP3 ;
- 建立例程数据库 SilverlightDemo,在数据库中建立一个新表 Users,包含以下字段;

添加内容到Users表,为了方便起见,密码全部使用明文,在正式项目中,建议对密码字段进行加密使用。

这里,我们验证用户名和密码,有两种简单方式,
一是使用存储过程读取用户名和密码,然后在服务器端进行用户名和密码匹配校验,如果查找到匹配数据,则返回登录成功,否则,则是登录失败;
二是传用户名和密码到存储过程中,在数据库存储过程中进行判断,使用Select语句进行查找,对应用户名和密码,如果查找到匹配结果,则返回用户ID, 服务器端接收到用户ID,则返回登录成功,否则,则是失败;
在本例中,主要是对Silverlight访问数据库进行讲述,所以,对于验证方法,不进行详细描述和讲解,如果有问题,可以留言给我,我们继续讨论,这里,我将使用第一种验证方法。 为此,建立一个简单的存储过程:
1
CREATE
PROCEDURE
[
dbo
]
.
[
Login
]
2
(
@UserName
Varchar
(
30
))
3
AS
4
5
Select
cUserName, cPassword
6
From
Users
7
Where
cUserName
=
@UserName
8
9
RETURN
10
11
SET
NOCOUNT
ON
在完成上面的准备工作后,开始建立新的Silverlight项目,
1. 建立一个新项目"SilverlightDBDemo",

2. 在MainPage中建立简单的登录界面,如下:

3. 在Web项目中添加新选项

4. 添加一个简单的用户信息类Users,作为WCF的契约成员,当我们从数据库中读取信息后,将赋值给该类的契约成员,方便客户端进行调用;

VS2008将自动生成Users类代码,在类命名前添加数据契约属性[DataContract()]。 为了能够使绑定数据返回修改通知,这里需要继承INotifyPropertyChanged接口,该步骤不添加对本教程也没有影响,为了以后例程代码完整性,这里我继承了该接口。在接口上点击右键,生成代码。

代码如下:
1
namespace
SilverlightDBDemo.Web
2
{
3
[DataContract()]
4
public
class
Users : INotifyPropertyChanged
5
{
6
7
#region
INotifyPropertyChanged Members
8
9
public
event
PropertyChangedEventHandler PropertyChanged;
10
11
#endregion
12
}
13
}
14
5. 在Users类中,添加契约成员
1
private
string
userName;
2
[DataMember()]
3
public
string
UserName
4
{
5
get
{
return
userName; }
6
set
{ userName
=
value;}
7
}
8
9
private
string
password;
10
[DataMember()]
11
public
string
Password
12
{
13
get
{
return
password; }
14
set
{ password
=
value; }
15
}
6. 建立构造函数 public Users(string sUserName,string sPassword),传递用户名和密码给契约成员;
1
using
System;
2
using
System.ComponentModel;
3
using
System.Runtime.Serialization;
4
5
namespace
SilverlightDBDemo.Web
6
{
7
[DataContract()]
8
public
class
Users : INotifyPropertyChanged
9
{
10
private
string
userName;
11
[DataMember()]
12
public
string
UserName
13
{
14
get
{
return
userName; }
15
set
{ userName
=
value;}
16
}
17
18
private
string
password;
19
[DataMember()]
20
public
string
Password
21
{
22
get
{
return
password; }
23
set
{ password
=
value; }
24
}
25
26
public
Users(
string
sUserName,
string
sPassword)
27
{
28
UserName
=
sUserName;
29
Password
=
sPassword;
30
}
31
32
#region
INotifyPropertyChanged Members
33
34
public
event
PropertyChangedEventHandler PropertyChanged;
35
36
#endregion
37
}
38
}
7. 添加"Silverlight-enabled WCF Service",修改服务名字为 DBService.svc,需要注意的是,WCF service对于Silverlight仅支持BasicHttpBinding,而VS2008自动生成是customBinding,很多朋友说使用了"Silverlight-enabled WCF Service",链接数据库仍旧失败,无法找到远程服务器,是因为没有使用BasicHttpBinding进行通讯,造成的失败。
后文我将讲述如何修改。

8. 添加后,在Web服务器端会有DBService.svc和DBService.svc.cs文件出现,VS2008将自动更新Web项目的类库引用;

9. 双击进入DBService.svc.cs文件,可以看到以下代码:
1
using
System;
2
using
System.Linq;
3
using
System.Runtime.Serialization;
4
using
System.ServiceModel;
5
using
System.ServiceModel.Activation;
6
using
System.Collections.Generic;
7
using
System.Text;
8
9
namespace
SilverlightDBDemo.Web
10
{
11
[ServiceContract(Namespace
=
""
)]
12
[AspNetCompatibilityRequirements(RequirementsMode
=
AspNetCompatibilityRequirementsMode.Allowed)]
13
public
class
DBService
14
{
15
[OperationContract]
16
public
void
DoWork()
17
{
18
//
Add your operation implementation here
19
return
;
20
}
21
22
//
Add more operations here and mark them with [OperationContract]
23
}
24
}
这里我们没有修改ServiceContract命名空间,所以保持默认为空,AspNet的兼容需求模式我们保持默认。在正式项目中,我们习惯将所有的[OperationContract]函数放入一个接口文件中,这样方便扩展以及维护,在本例,为了方便大家理解,就不把[OperationContract]放入接口文件。 在VS2008自动生成代码下面直接添加数据库访问代码。
10. 在添加服务器端数据库访问代码前,需要修改Web.Config文件。和Asp.Net项目一样,在链接数据库前,我们首先需要在Web.Config中配置数据库连接字符串,请自行替换数据库登录ID和密码
1
<
appSettings
>
2
<
add
key
="DbServiceConnectionString"
value
="Data Source=(Local);Initial Catalog=SilverlightDemo;User Id=dev;Password=dev;"
/>
3
</
appSettings
>
11. 前文已经说过,Silverlight仅支持使用BasicHttpBinding通过WCF service进行通讯,而VS2008自动生成的代码是customBinding,所以,我们也需要在Web.Config中进行修改.下面是VS2008自动生成的Web.Config部分代码,划线部分是下面要修改的部分。
1
<
system.serviceModel
>
2
<
behaviors
>
3
<
serviceBehaviors
>
4
<
behavior
name
="SilverlightDBDemo.Web.DBServiceBehavior"
>
5
<
serviceMetadata
httpGetEnabled
="true"
/>
6
<
serviceDebug
includeExceptionDetailInFaults
="False"
/>
7
</
behavior
>
8
</
serviceBehaviors
>
9
</
behaviors
>
10
<
bindings
>
11
<
customBinding
>
12
<
binding
name
="customBinding0"
>
13
<
binaryMessageEncoding
/>
14
<
httpTransport
/>
15
</
binding
>
16
</
customBinding
>
17
</
bindings
>
18
<
serviceHostingEnvironment
aspNetCompatibilityEnabled
="true"
/>
19
<
services
>
20
<
service
behaviorConfiguration
="SilverlightDBDemo.Web.DBServiceBehavior"
21
name
="SilverlightDBDemo.Web.DBService"
>
22
<
endpoint
address
=""
binding
="customBinding"
bindingConfiguration
="customBinding0"
23
contract
="SilverlightDBDemo.Web.DBService"
/>
24
<
endpoint
address
="mex"
binding
="mexHttpBinding"
contract
="IMetadataExchange"
/>
25
</
service
>
26
</
services
>
27
</
system.serviceModel
>
这里我们需要修改以下几个地方:
首先删除customBinding,从上面代码,第10行,到17行,使用下面代码替换:
1
<
bindings
>
2
<
basicHttpBinding
>
3
<
binding
name
="BasicHttpBinding_IDataService"
4
maxBufferPoolSize
="2147483647"
5
maxReceivedMessageSize
="2147483647"
6
maxBufferSize
="2147483647"
>
7
<
readerQuotas
8
maxArrayLength
="2147483647"
9
maxBytesPerRead
="2147483647"
10
maxDepth
="2147483647"
11
maxNameTableCharCount
="2147483647"
12
maxStringContentLength
="2147483647"
/>
13
</
binding
>
14
</
basicHttpBinding
>
15
</
bindings
>
其中那些2147483647之类的属性可以删除,但是如果读取数据库中的大型表格,就需要设置缓冲池之类的尺寸了。这里,我们已经使用了basicHttpBinding. Binding name我使用了BasicHttpBinding_DBService,大家可以随意更换,下面将用到。
然后修改22行和23行的代码,将endpoint中的binding,内容修改为basicHttpBinding,bindingConfiguration的内容修改为BasicHttpBinding_DBService。
1
<
endpoint
address
=""
binding
="basicHttpBinding"
bindingConfiguration
="BasicHttpBinding_DBService"
2
contract
="SilverlightDBDemo.Web.DBService"
/>
12. 现在我们可以在DBService.svc.cs中添加存取数据库代码,对用户名和密码进行简单匹配,这里不再着重讲述如何条件匹配登录信息。这里演示了如何调用数据库存储过程。完成存取数据库代码后,成功编译Web项目。代码有点长,这里折叠起来。
代码
1
private
string
connectionString
=
WebConfigurationManager.AppSettings[
"
DbServiceConnectionString
"
];
2
3
[OperationContract]
4
public
bool
GetUser(
string
cUserName,
string
cPassword)
5
{
6
SqlConnection conn
=
new
SqlConnection(connectionString);
7
SqlCommand cmd
=
new
SqlCommand(
"
Login
"
, conn);
8
cmd.CommandType
=
CommandType.StoredProcedure;
9
cmd.Parameters.AddWithValue(
"
@UserName
"
, cUserName);
10
11
try
12
{
13
conn.Open();
14
SqlDataReader reader
=
cmd.ExecuteReader(CommandBehavior.SingleRow);
15
if
(reader.Read())
16
{
17
Users user
=
new
Users((
string
)reader[
"
cUserName
"
],
18
(
string
)reader[
"
cPassword
"
]);
19
if
(user.Password
==
cPassword)
20
{
21
return
true
;
22
}
23
else
24
{
25
return
false
;
26
}
27
}
28
else
29
{
30
return
false
;
31
}
32
}
33
finally
34
{
35
conn.Close();
36
}
37
}
13. 在SilverlightDBDemo客户端,点击右键添加服务引用

14. 在弹出窗口中,点击"Discover",查找本地WCF service。在地址栏会自动搜索到本地的Service引用,在Services树形框中我们可以看到,在服务器端建立的DBService.svc,双击打开,可以看到,我们建立的GetUser函数,以及默认的DoWork函数。修改下面的命名空间为"DBService",方便调用。

15. 点击"Advanced.."高级按钮,确认选中"Reuse types in referenced assembiles",如下图,

16. 然后,点击确定,会在客户端中生成DBService服务引用。
17. 在生成DBService服务引用后,VS2008会自动生成一个ServiceReferences.ClientConfig文件。
我们需要留意查看一下该文件内容。其中,bindings信息是basicHttpBinding,而endpoint内容和Web.Config中的内容相同。这里我们不需要修改任何代码。
1
<
configuration
>
2
<
system.serviceModel
>
3
<
bindings
>
4
<
basicHttpBinding
>
5
<
binding
name
="BasicHttpBinding_DBService"
maxBufferSize
="2147483647"
6
maxReceivedMessageSize
="2147483647"
>
7
<
security
mode
="None"
>
8
<
transport
>
9
<
extendedProtectionPolicy
policyEnforcement
="Never"
/>
10
</
transport
>
11
</
security
>
12
</
binding
>
13
</
basicHttpBinding
>
14
</
bindings
>
15
<
client
>
16
<
endpoint
address
="http://localhost/SilverlightDBDemo.Web/DBService.svc"
17
binding
="basicHttpBinding"
bindingConfiguration
="BasicHttpBinding_DBService"
18
contract
="DBService.DBService"
name
="BasicHttpBinding_DBService"
/>
19
</
client
>
20
</
system.serviceModel
>
21
</
configuration
>
22
18. 下面我们将在客户端调用该服务引用,获取数据库的返回值,根据返回值,我们将简单判断登录是否成功。
进入MainPage.xaml.cs中,建立GetUser方法。该代码中EndpointAddress是最重要的,出现没有发现远程服务器错误,和这里设置也有关系。在client_GetUserCompleted中,e.Result代表了数据库返回值。可以接受任何值,大家可以根据需要进行值类型转换。每次,用户点击登陆按钮,Silverlight客户端都会向服务器端请求验证,返回结果会在提示信息栏显示。
1
private
void
GetUser()
2
{
3
EndpointAddress address
=
new
EndpointAddress(
new
Uri(Application.Current.Host.Source,
"
/SilverlightDBDemo.Web/DBService.svc
"
));
4
DBServiceClient client
=
new
DBServiceClient(
new
BasicHttpBinding(), address);
5
client.GetUserCompleted
+=
client_GetUserCompleted;
6
client.GetUserAsync(txtUsername.Text, pbPassword.Password);
7
}
8
9
private
void
client_GetUserCompleted(
object
sender, GetUserCompletedEventArgs e)
10
{
11
try
12
{
13
if
(e.Result)
14
{
15
tbMessage.Text
=
"
登录成功!
"
;
16
}
17
else
18
{
19
tbMessage.Text
=
"
登录失败!
"
;
20
}
21
}
22
catch
(Exception error)
23
{
24
tbMessage.Text
=
error.ToString();
25
}
26
}
27
28
private
void
btLogin_Click(
object
sender, RoutedEventArgs e)
29
{
30
GetUser();
31
}
登录成功如下图:

到这里为止,我想你已经学会了如何使用WCF存取MSSQL数据库了。如果有问题,可以留言给我,或者到Silverlight开发QQ群100844510来讨论。
代码下载
本文为原创文章,第一次发布在 银光中国网(SilverlightChina.Net)
如需转载,请注明出处,谢谢。