您的位置:首页 > 其它

wcf系列学习5天速成——第三天 事务的使用

2013-12-06 16:50 411 查看
今天是速成的第三天,再分享一下WCF中比较常用的一种技术,也就是”事务“。

在B2B的项目中,一般用户注册后,就有一个属于自己的店铺,此时,我们就要插入两张表, User和Shop表。

当然,要么插入成功,要么全失败。

第一步: 首先看一下项目的结构图:



第二步: 准备工作,我们新建Commerce数据库,用EF去映射,然后新建ServiceWCF类库,具体步骤就省略,

这一块不懂可以留言。



第三步:新建一个Model类库。建立两个实体类Shop和User,当然自定义类型在WCF中传输,

必须在类上加上【DataContract】,属性上加【DataMember】。

Shop.cs



namespace Model
{
[DataContract]
public class Shop
{
[DataMember]
public int ShopID { get; set; }

[DataMember]
public int UserID { get; set; }

[DataMember]
public string ShopName { get; set; }

[DataMember]
public string ShopUrl { get; set; }

}
}




User.cs



namespace Model
{
[DataContract]
public class User
{
[DataMember]
public int UserID { get; set; }

[DataMember]
public string UserName { get; set; }

[DataMember]
public string Password { get; set; }
}
}




第四步:然后在ServiceWCF类库中新建两个文件Seller.cs 和 ISeller.cs.

ISeller.cs:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace ServiceWCF
{
[ServiceContract]
public interface ISeller
{
[OperationContract(Name = "AddUser")]
bool Add(Model.User user, out int userID);

[OperationContract(Name = "AddShop")]
bool Add(Model.Shop shop, out int shopID);

[OperationContract]
bool Add(Model.User user, Model.Shop shop);
}
}




Seller.cs



namespace ServiceWCF
{
public class Seller : ISeller
{
///<summary>
/// User的插入操作
///</summary>
///<param name="user"></param>
///<param name="userID"></param>
///<returns></returns>
public bool Add(Model.User user, out int userID)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
User userModel = new User()
{
UserName = user.UserName,
Passwrod = user.Password
};

db.User.AddObject(userModel);

db.SaveChanges();

userID = userModel.UserID;

return true;
}
catch (Exception)
{
userID = 0;
throw;
}
}
}

///<summary>
/// Shop的插入操作
///</summary>
///<param name="shop"></param>
///<param name="shopID"></param>
///<returns></returns>
public bool Add(Model.Shop shop, out int shopID)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{

Shop shopModel = new Shop()
{
ShopName = shop.ShopName,
ShopUrl = shop.ShopUrl,
UserID = shop.UserID
};

db.Shop.AddObject(shopModel);

db.SaveChanges();

shopID = shopModel.ShopID;

return true;
}
catch (Exception)
{
shopID = 0;
throw;
}
}
}

///<summary>
/// User,Shop的插入的操作
///</summary>
///<param name="user"></param>
///<param name="shop"></param>
///<returns></returns>

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool Add(Model.User user, Model.Shop shop)
{
int shopID;
int UserID;

//注意,这个方法操作了两个数据库实例,为AddUser和AddShop。所以晋升为分布式事务
if (Add(user, out  UserID))
{
shop.UserID = UserID;

return Add(shop, out shopID);
}

return false;
}
}
}




TransactionScopeRequired: 告诉ServiceHost自托管服务,进入我的方法,必须给我加上事务。

TransactionAutoComplete: 方法执行中,如果没有抛出异常,则自动提交。

第五步: 新建Host来承载了,配置AppConfig,这些细节就不再说了。



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ServiceHost
{
class Program
{
static void Main(string[] args)
{
System.ServiceModel.ServiceHost host = new System.ServiceModel.ServiceHost(typeof(ServiceWCF.Seller));

host.Open();

Console.WriteLine("WCF 服务已经开启!");

Console.Read();
}
}
}






<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- 部署服务库项目时,必须将配置文件的内容添加到
主机的 app.config 文件中。System.Configuration 不支持库的配置文件。-->
<system.serviceModel>
<services>
<service name="ServiceWCF.Seller">
<endpoint address="" binding="wsHttpBinding" contract="ServiceWCF.ISeller">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Seller/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false 并删除上面的元数据终结点  -->
<serviceMetadata httpGetEnabled="True" />
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<connectionStrings>
<add name="CommerceEntities" connectionString="metadata=res://*/Commerce.csdl|res://*/Commerce.ssdl|res://*/Commerce.msl;provider=System.Data.SqlClient;provider connection string="Data Source=VONXCEVF0IT7JDJ;Initial Catalog=Commerce;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>




第六步:开启WCF服务,新建ServiceClient类库,然后用信道生成实例。



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ServiceWCF;

namespace ServiceClient
{
class Program
{
static void Main(string[] args)
{
var user = new Model.User()
{
UserName = "huangxincheng520",
Password = "i can fly"
};

var shop = new Model.Shop()
{
ShopName = "shopex",
ShopUrl = "http://www.shopex.cn"
};

var factory = new ChannelFactory<ISeller>(new WSHttpBinding(),

new EndpointAddress("http://localhost:8732/Seller/"));

var client = factory.CreateChannel();

if (client.Add(user, shop))
Console.WriteLine("huangxincheng520, 恭喜你,数据插入成功。");
else
Console.WriteLine("huangxincheng520, 呜呜,数据插入失败。");

Console.Read();
}
}
}




最后就是测试了:

首先:走正常流程。client.Add方法调用服务器端,运行效果如图所示:



是的,数据已经正常插入成功,对Client端而言,这个操作是透明的。

然后: 我们在Seller类中的Add方法中故意加入异常。看效果咋样。



///<summary>
/// User,Shop的插入的操作
///</summary>
///<param name="user"></param>
///<param name="shop"></param>
///<returns></returns>
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool Add(Model.User user, Model.Shop shop)
{
int shopID;
int UserID;

if (Add(user, out  UserID))
{
//注意注意,我在Adduser成功的情况下,抛出异常,看是否回滚。
throw new Exception();

shop.UserID = UserID;

return Add(shop, out shopID);
}

return false;
}




截图如下:



哈哈,抛出异常了,我的Exception起到效果了,再来看一下数据库。大家都知道会发生什么了,对的,异常不再产生数据了,

还是先前产生了那条数据,说明起到效果了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: