NHibernate+WCF项目实战
第一篇、项目介绍与搭建;
第二篇、使用NHibernate实现数据访问并进行单元测试;
第三篇、使用WCF对外提供Webservices接口并进行单元测试;
第四篇、使用WAS对Webservices接口进行压力测试。
开发环境
我的开发环境是VS2008 SP1+SQLServer 2005
NHibernate版本是2.1.0.4000
NUnit版本是2.5.2
Microsoft Web Application Stress Tool 版本是1.1
本节概要
上一篇完成了用户操作的三个方法,本篇将通过WCF以webservices的方式对外提供接口。同时使用NUnit对webservices中的方法进行单元测试。
另,上一篇对NHibernate的使用还有很多地方值的改善,同时也感谢园友李永京的指点。
开发契约 contract
Contract项目为类库项目,该项目下会包含WCF中的ServiceContract,这是一些被加上Attribute [ServiceContract]的接口。同时接口中的方法也需要加上Attribute [OperationContract]。
另,考虑到下一篇要对接口进行压力测试,所以接口中的方法也加上Attribute [WebGet],可以通过get方式访问方法。
下面就开始定义UserInfo的Contract—IuserInfo接口。
using
System.ServiceModel;
System.ServiceModel.Web;//webGet
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;

using
System.ServiceModel;
using
System.ServiceModel.Web;
//
webGet
namespace
Lee.Contract

{
[ServiceContract]
public interface IUserInfo

{
[OperationContract]
[WebGet]
bool AddUserInfo(string name, string description, string state);
[OperationContract]
[WebGet]
bool ExistUserInfo(string name);
[OperationContract]
[WebGet]
bool UpdateUserInfo(string name, string description, string state);
}
}
开发服务 Services
Services项目也是类库项目,该项目主要是对Contract的具体实现,同时会调用DAL提供的数据访问层方法。
using
添加对Lee.Model项目的引用。
添加对Lee.DAL项目的引用。
添加对Lee. Contract项目的引用。
我们实现的UserInfo的三个方法中都是返回了Bool值,如果方法返回对象,这时就需要添加对Lee.Model项目的引用。
另,如果要在WCF中传递对象,需要为实体类添加Attribute [DataContract]和[Serializable]。属性需要添加Attribute [DataMember]。
下面是Lee.Services中的UserInfo 服务类
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;

using
Lee.DAL;
using
Lee.Model;
using
Lee.Contract;

namespace
Lee.Services

{
public class UserInfo:IUserInfo

{

/**//// <summary>
/// 添加用户
/// </summary>
/// <param name="name">用户名称</param>
/// <param name="description">用户描述</param>
/// <param name="state">状态</param>
/// <returns>True-操作成功|False-操作失败</returns>
public bool AddUserInfo(string name, string description, string state)

{
UserInfoDAL dal =new UserInfoDAL();
return dal.AddUserInfo(name,description,state);
}

/**//// <summary>
/// 检查用户是否存在
/// </summary>
/// <param name="name">用户名称</param>
/// <returns>True-用户存在|False-用户不存在</returns>
public bool ExistUserInfo(string name)

{
UserInfoDAL dal =new UserInfoDAL();
return dal.ExistUserInfo(name);
}

/**//// <summary>
/// 更新用户信息
/// </summary>
/// <param name="name">用户名称</param>
/// <param name="description">用户描述</param>
/// <param name="state">状态</param>
/// <returns>True-操作成功|False-操作失败</returns>
public bool UpdateUserInfo(string name, string description, string state)

{
UserInfoDAL dal = new UserInfoDAL();
return dal.UpdateUserInfo(name, description, state);
}
}
}
开发宿主 Hosting
Hosting项目为WCF服务应用程序,该项目会自动添加对System.Runtime.Serialization和System.ServiceModel的引用。
using
添加对Lee. Contract项目的引用。
添加对Lee. Services项目的引用。
详细步骤
1)添加 UserInfo.svc;
2)删除文件 UserInfo.svc.cs;
3)双击打开 UserInfo.svc
<%@ ServiceHost Language="C#" Debug="true" Service="Lee.Hosting.UserInfo" CodeBehind="UserInfo.svc.cs" %>
修改为:
<%@ ServiceHost Language="C#" Debug="true" Service="Lee.Services.UserInfo" CodeBehind="Lee.Services.UserInfo.cs" %>
4)修改Web.config;
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
connectionStrings
>
<
add
name
="SQLConnection"
connectionString
="Database=XX;User ID=sa;Password=saas;Server=XX;"
providerName
="System.Data.SqlClient"
/>
</
connectionStrings
>
<
system.serviceModel
>
<
serviceHostingEnvironment
aspNetCompatibilityEnabled
="false"
/>
<
services
>
<
service
behaviorConfiguration
="Lee.Hosting.UserInfoBehavior"
name
="Lee.Services.UserInfo"
>
<
endpoint
address
=""
binding
="basicHttpBinding"
contract
="Lee.Contract.IUserInfo"
>
<
identity
>
<
dns
value
="localhost"
/>
</
identity
>
</
endpoint
>
<
endpoint
address
="webhttp"
behaviorConfiguration
="webHttp"
binding
="webHttpBinding"
contract
="Lee.Contract.IUserInfo"
>
<
identity
>
<
dns
value
="localhost"
/>
</
identity
>
</
endpoint
>
</
service
>
</
services
>
<
behaviors
>
<
endpointBehaviors
>
<
behavior
name
="webHttp"
>
<
webHttp
/>
</
behavior
>
</
endpointBehaviors
>
<
serviceBehaviors
>
<
behavior
name
="Lee.Hosting.UserInfoBehavior"
>
<
serviceMetadata
httpGetEnabled
="true"
/>
<
serviceDebug
includeExceptionDetailInFaults
="true"
/>
</
behavior
>
</
serviceBehaviors
>
</
behaviors
>
</
system.serviceModel
>
<
system.web
>
<
compilation
debug
="true"
/>
</
system.web
>
</
configuration
>



5)创建NHibernate配置文件hibernate.cfg.xml并设置为始终复制,添加对NHibernate和NHibernate.ByteCode.Castle的引用。
6)效果查看
浏览UserInfo.svc

对应的WSDL

查看Schema格式

到现在为止,我们已经用WCF成功的对外发布了接口。下面我们对Webservices进行单元测试!
单元测试
单元测试的相关设置在上一篇已经讲过了,这里不再介绍。
测试步骤
1)using
添加对Lee. Contract项目的引用。
2)添加服务引用,直接点“发现“,可以找到该解决方案下的服务。

成功添加后,会自动在App.Config中创建client端EndPoint。
3)创建服务测试类TestUserInfoSVC.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;

using
Lee.Model;
using
Lee.DAL;
using
NUnit.Framework;

namespace
Lee.Test

{
[TestFixture]
public class TestUserInfoSVC

{
[Test]
public void AddUserInfo()

{
UserInfoSVC.UserInfoClient client = new Lee.Test.UserInfoSVC.UserInfoClient();
bool result = client.AddUserInfo("testname6", "testdesc", "teststate");
Assert.AreEqual(true, result);
}
[Test]
public void ExistUserInfo()

{
UserInfoSVC.UserInfoClient client = new Lee.Test.UserInfoSVC.UserInfoClient();
bool result = client.ExistUserInfo("testname");
Assert.AreEqual(true, result);
}
[Test]
public void UpdateUserInfo()

{
UserInfoSVC.UserInfoClient client = new Lee.Test.UserInfoSVC.UserInfoClient();
bool result = client.UpdateUserInfo("testname5", "hello,testname!", "activation");
Assert.AreEqual(true, result);
}
}
}
4)可以在方法中设置断点单步调试。