关于在SL下实现WCF通信的文章很多,因此我着重从我的实践上讲解,这样可能易懂一些。
一、简单介绍下WCF
全名:Windows Communication Foundation 从Dotnet Framework 3.0开始出现,WCF通信提供了用HTTP、TCP和IPC信道进行通信的多个方法。WCF提供的信道使用DCOM进行通信。WCF适合于要独立于平台快速的发送消息。服务提供一个端点,包括三个:合同Contract、绑定Binding和地址Endpoint。合同定义了服务提供的操作(接口及实现),绑定控制协议和编码信息(如SL支持的basicHttpBinding)、地址给出服务的位置(地址及目标名)。WCF支持SOAP(Simple Object Access Protocol)、WSDL(Web Services Description Language)。
二、开始实现在SL下的WCF。
我们要做一个用户登陆的例子,具体流程为:SL调用WCF服务,服务中通过ADO调用存储过程进行登陆验证,把结果返回到本地SL。
1、首先写一个SQL表:
CREATE
TABLE
UserInfoTable
(
UserName
NVARCHAR
(
20
)
PRIMARY
KEY
,
UserPsw
NVARCHAR
(
15
)
)
2、写个简单的存储过程:
SQL登陆存储过程
SET
ANSI_NULLS
ON
GO
SET
QUOTED_IDENTIFIER
ON
GO
--
=============================================
--
Author: 寻雨
--
Create date: 2010-4-1-12:45
--
Description: 验证用户登陆情况.登陆成功则返回0,登陆失败返回1;
--
=============================================
CREATE
PROCEDURE
sp_Login
@UserNum
NVARCHAR
(
20
),
@UserPsw
NVARCHAR
(
15
)
AS
BEGIN
IF
EXISTS
(
SELECT
*
FROM
UserInfoTable
WHERE
UserNum
=
@UserNum
AND
UserPsw
=
@UserPsw
)
RETURN
0
;
RETURN
1
;
END
GO
3、开始建立WCF服务
1、新建WCF服务
在Web端右键,新建,“启用Silverlight功能的WCF服务”,自己输入一个名字,我这里例子名为DataCmd。可以看到App_Code里多了DataCmd.cs,外面多了DataCmd.svc。打开这个SVC文件我们可以看到:
<%
@ ServiceHost Language
=
"
C#
"
Debug
=
"
true
"
Service
=
"
DataCmd
"
CodeBehind
=
"
~/App_Code/DataCmd.cs
"
%>
只有一行,Service指服务类的全名,就是在代码文件中被标记为[ServiceContract]的类(称为服务合同),CodeBehind指的是服务类的代码文件。此地要注意,服务类的代码文件放入App_Code,但SVC绝对不可以放入App_Code,否则会造成403无法访问的错误,因为App_Code自动编译,为了代码安全外面无法访问。
2、实现服务合同
在App_Code里新建一个接口,取名IDataCmd.cs,具体代码如下:注意命名空间
代码
using
System.ServiceModel;
///
<summary>
///
DataCmd.svc的服务合同接口.
///
</summary>
[ServiceContract]
public
interface
IDataCmd
{
///
<summary>
///
验证登陆
///
</summary>
[OperationContract]
bool
LoginByUserInfo(
string
userNum,
string
userPsw);
///
<summary>
///
插入新用户
///
</summary>
[OperationContract]
bool
RegNewUser(
string
userNum,
string
userPsw,
string
realName,
string
className,
string
phone);
}
服务合同类中存放服务的实现,一般建议将所有的服务函数写成一个接口。因此我们除了一开始自动生成的服务合同类DataCmd.cs外,创建了IDataCmd.cs的接口。这样我们只用在接口中标记[ServiceContract]和[OperationContract]。用户也可以按生成的DataCmd.cs的样式写服务合同类,只不过用接口会方便一些而已。在改写DataCmd.cs前,我先介绍一下我写的SqlAdapt,是一个简单的Sql访问类,访问数据库时会用到,其他的不多说了,SqlAdapt代码如下:
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Data.SqlClient;
using
System.Data;
///
<summary>
///
用于处理Sql通信 请在Using语句块中使用.类会自动关闭连接.否则需要主动调用Close(); 仅单线程安全.
///
</summary>
public
class
SqlAdapt : IDisposable
{
private
SqlConnection SqlConn;
private
SqlCommand SqlComm;
public
SqlAdapt(
string
SqlConnKey)
{
try
{
SqlConn
=
new
SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[SqlConnKey].ToString());
}
catch
{
try
{
SqlConn
=
new
SqlConnection(System.Configuration.ConfigurationManager.AppSettings[SqlConnKey].ToString());
}
catch
{
throw
new
Exception(
"
The SqlConnKey Is Wrong!
"
);
}
}
SqlConn.Open();
SqlComm
=
SqlConn.CreateCommand();
}
public
int
ExecuteNonQuery(
string
tSql)
{
SqlComm.CommandType
=
CommandType.Text;
SqlComm.CommandText
=
tSql;
return
SqlComm.ExecuteNonQuery();
}
public
void
AddParams(SqlParameter sqlParam)
{
SqlComm.Parameters.Add(sqlParam);
}
public
void
AddParams(
string
ParamName,
object
Params, SqlDbType SqlType,
int
Size, ParameterDirection PD)
{
SqlParameter sqlParam
=
new
SqlParameter(ParamName, Params);
sqlParam.SqlDbType
=
SqlType;
sqlParam.Size
=
Size;
sqlParam.Direction
=
PD;
SqlComm.Parameters.Add(sqlParam);
}
public
void
AddParams(
string
ParamName,
object
Params, SqlDbType SqlType , ParameterDirection PD)
{
SqlParameter sqlParam
=
new
SqlParameter(ParamName, Params);
sqlParam.SqlDbType
=
SqlType;
sqlParam.Direction
=
PD;
SqlComm.Parameters.Add(sqlParam);
}
public
object
ExecuteProcedure(
string
pSql)
{
SqlComm.CommandType
=
CommandType.StoredProcedure;
SqlComm.CommandText
=
pSql;
SqlComm.Parameters.Add(
new
SqlParameter(
"
@RETURN_VALUE
"
,
""
)).Direction
=
ParameterDirection.ReturnValue;
SqlComm.ExecuteNonQuery();
return
SqlComm.Parameters[
"
@RETURN_VALUE
"
].Value;
}
public
void
ExecProc(
string
pSql)
{
SqlComm.CommandType
=
CommandType.StoredProcedure;
SqlComm.CommandText
=
pSql;
SqlComm.ExecuteNonQuery();
}
public
void
Close()
{
SqlComm.Parameters.Clear();
if
(SqlConn.State
!=
ConnectionState.Closed)
{
SqlConn.Close();
}
}
public
SqlParameter GetParam(
string
paramName)
{
return
SqlComm.Parameters[paramName];
}
public
SqlParameterCollection GetParamCollection {
get
;
set
; }
public
void
Dispose()
{
SqlComm.Parameters.Clear();
if
(SqlConn.State
!=
ConnectionState.Closed)
{
SqlConn.Close();
}
}
}
下面是我改写后的DataCmd.cs,实现了IDataCmd接口。对SQL访问请参照上面的代码。
代码
using
System;
using
System.Linq;
using
System.Runtime.Serialization;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.Collections.Generic;
using
System.Text;
using
System.Data;
[AspNetCompatibilityRequirements(RequirementsMode
=
AspNetCompatibilityRequirementsMode.Allowed)]
public
class
DataCmd : IDataCmd
{
#region
IDataCmd 成员
public
bool
LoginByUserInfo(
string
userNum,
string
userPsw)
{
using
(SqlAdapt sql
=
new
SqlAdapt(
"
SqlConnectionString
"
))
{
sql.AddParams(
"
@UserNum
"
, userNum, SqlDbType.NVarChar,
20
, ParameterDirection.Input);
sql.AddParams(
"
@UserPsw
"
, userPsw, SqlDbType.NVarChar,
15
, ParameterDirection.Input);
return
(int)sql.ExecuteProcedure("sp_Login")==0?true:false;
}
}
public
bool
RegNewUser(
string
userNum,
string
userPsw,
string
realName,
string
className,
string
phone)
{
throw
new
NotImplementedException();
}
#endregion
}
一切都完成后,我们可以执行下这个svc。如果没有意外,会显示已创建服务,并让你测试。这里可以用命令行测试下自己的数据库存取是否正确。
3、下面为大家讲解下基于SL的WCF简单配置。打开Web.Config后,我取出与WCF有关的部分(ServiceModel结点),在这里我就不罗列系统默认的配置了,只列出我自己的配置来与大家一起分析。
代码
1
<
system.serviceModel
>
2
这是第一部分:配置行为
3
<
behaviors
>
4
<
serviceBehaviors
>
5
6
<
behavior name
=
"
DataCmdBehavior 行为配置的ID
"
>
7
<
serviceMetadata httpGetEnabled
=
"
true
"
/>
8
<
serviceDebug includeExceptionDetailInFaults
=
"
false
"
/>
9
</
behavior
>
10
11
</
serviceBehaviors
>
12
</
behaviors
>
13
这是第二部分:配置绑定
14
<
bindings
>
15
<
basicHttpBinding
>
16
<
binding name
=
"
bHttpBind 绑定配置的ID
"
>
17
<
readerQuotas
/>
这些都可以根据情况增加参数
18
<
security
>
19
<
transport
>
20
<
extendedProtectionPolicy policyEnforcement
=
"
Never
"
/>
21
</
transport
>
22
</
security
>
23
</
binding
>
24
</
basicHttpBinding
>
25
</
bindings
>
26
这是第三部分:配置服务
27
<
serviceHostingEnvironment aspNetCompatibilityEnabled
=
"
true
"
/>
28
<
services
>
29
30
<
service behaviorConfiguration
=
"
DataCmdBehavior 写行为配置ID
"
name
=
"
DataCmd 服务合同类
"
>
31
<
endpoint address
=
""
binding
=
"
basicHttpBinding
"
bindingConfiguration
=
"
bHttpBind 写端口配置的ID
"
32
contract
=
"
IDataCmd 服务合同接口
"
/>
33
</
service
>
34
35
</
services
>
36
</
system.serviceModel
>
从代码可以看出,前两部分是为第三部分做准备的。如果要配置多个WCF只用多增加结点就可以了。
4、 SL端的配置
接下来要配置客户端的东西了,在SL项目中的引用,右键“添加服务引用”,之后点发现,找到我们刚创建的服务,添加进来就可以。当然,要写好命名空间。
之后会生成一个叫“Service References ”的文件夹,在里面可以看到刚添加的服务,双击可以打开对象管理器,看到它所有的成员。
下面我来写客户端,当单击一个按扭时,以TextBox和PasswordBox中数据为用户和密码,调用WCF服务,进行验证。并针对结果,用MessageBox给出不同的对话框。代码如下:
代码
private
void
Log_MouseLeftButtonDown(
object
sender, System.Windows.Input.MouseButtonEventArgs e)
{
//
进行登陆
DataCmdClient dcClient
=
new
DataCmdClient();
dcClient.LoginByUserInfoCompleted
+=
new
EventHandler
<
LoginByUserInfoCompletedEventArgs
>
(dcClient_LoginByUserInfoCompleted);
dcClient.LoginByUserInfoAsync(UserNameBox.Text, PasswordBox.Password);
}
void
dcClient_LoginByUserInfoCompleted(
object
sender, LoginByUserInfoCompletedEventArgs e)
{
if
(e.Result)
{
MessageBox.Show(
"
GOOD Login
"
);
}
else
{
MessageBox.Show(
"
Bad Can't In
"
);
}
}
到这里,整个例子就讲完了。希望这篇文章对大家有所帮助。