一、简单介绍下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结点),在这里我就不罗列系统默认的配置了,只列出我自己的配置来与大家一起分析。
- <system.serviceModel>
- 这是第一部分:配置行为
- <behaviors>
- <serviceBehaviors>
- <behavior name="DataCmdBehavior 行为配置的ID">
- <serviceMetadata httpGetEnabled="true" />
- <serviceDebug includeExceptionDetailInFaults="false" />
- </behavior>
- </serviceBehaviors>
- </behaviors>
- 这是第二部分:配置绑定
- <bindings>
- <basicHttpBinding>
- <binding name="bHttpBind 绑定配置的ID">
- <readerQuotas /> 这些都可以根据情况增加参数
- <security>
- <transport>
- <extendedProtectionPolicy policyEnforcement="Never" />
- </transport>
- </security>
- </binding>
- </basicHttpBinding>
- </bindings>
- 这是第三部分:配置服务
- <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
- <services>
- <service behaviorConfiguration="DataCmdBehavior 写行为配置ID" name="DataCmd 服务合同类">
- <endpoint address="" binding="basicHttpBinding" bindingConfiguration="bHttpBind 写端口配置的ID"
- contract="IDataCmd 服务合同接口" />
- </service>
- </services>
- </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");
- }
- }
到这里,整个例子就讲完了。希望这篇文章对大家有所帮助。