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

来源:岁月联盟 编辑:exp 时间:2011-11-10

 

今天是速成的第三天,再分享一下WCF中比较常用的一种技术,也就是”事务“。

 

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

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

 

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

/

 

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

            这一块不懂可以留言。

/

 

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

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

 

 

 

   Shop.cs

 

 1 namespace Model

 2 {

 3     [DataContract]

 4     public class Shop

 5     {

 6         [DataMember]

 7         public int ShopID { get; set; }

 8

 9         [DataMember]

10         public int UserID { get; set; }

11

12         [DataMember]

13         public string ShopName { get; set; }

14

15         [DataMember]

16         public string ShopUrl { get; set; }

17

18     }

19 }

  User.cs

 

 1 namespace Model

 2 {

 3     [DataContract]

 4     public class User

 5     {

 6         [DataMember]

 7         public int UserID { get; set; }

 8

 9         [DataMember]

10         public string UserName { get; set; }

11

12         [DataMember]

13         public string Password { get; set; }

14     }

15 }

 

 

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

 

        ISeller.cs:

 

 1 using System;

 2 using System.Collections.Generic;

 3 using System.Linq;

 4 using System.Runtime.Serialization;

 5 using System.ServiceModel;

 6 using System.Text;

 7

 8 namespace ServiceWCF

 9 {

10     [ServiceContract]

11     public interface ISeller

12     {

13         [OperationContract(Name = "AddUser")]

14         bool Add(Model.User user, out int userID);

15

16         [OperationContract(Name = "AddShop")]

17         bool Add(Model.Shop shop, out int shopID);

18

19         [OperationContract]

20         bool Add(Model.User user, Model.Shop shop);

21     }

22 }

     Seller.cs

 

 1 namespace ServiceWCF

 2 {

 3     public class Seller : ISeller

 4     {

 5         ///<summary>

 6 /// User的插入操作

 7 ///</summary>

 8 ///<param name="user"></param>

 9 ///<param name="userID"></param>

10 ///<returns></returns>

11         public bool Add(Model.User user, out int userID)

12         {

13             using (CommerceEntities db = new CommerceEntities())

14             {

15                 try

16                 {

17                     User userModel = new User()

18                     {

19                         UserName = user.UserName,

20                         Passwrod = user.Password

21                     };

22

23                     db.User.AddObject(userModel);

24

25                     db.SaveChanges();

26

27                     userID = userModel.UserID;

28

29                     return true;

30                 }

31                 catch (Exception)

32                 {

33                     userID = 0;

34                     throw;

35                 }

36             }

37         }

38

39         ///<summary>

40 /// Shop的插入操作

41 ///</summary>

42 ///<param name="shop"></param>

43 ///<param name="shopID"></param>

44 ///<returns></returns>

45         public bool Add(Model.Shop shop, out int shopID)

46         {

47             using (CommerceEntities db = new CommerceEntities())

48             {

49                 try

50                 {

51

52                     Shop shopModel = new Shop()

53                           {

54                               ShopName = shop.ShopName,

55                               ShopUrl = shop.ShopUrl,

56                               UserID = shop.UserID

57                           };

58

59                     db.Shop.AddObject(shopModel);

60

61                     db.SaveChanges();

62

63                     shopID = shopModel.ShopID;

64

65                     return true;

66                 }

67                 catch (Exception)

68                 {

69                     shopID = 0;

70                     throw;

71                 }

72             }

73         }

74

75 ///<summary>

76 /// User,Shop的插入的操作

77 ///</summary>

78 ///<param name="user"></param>

79 ///<param name="shop"></param>

80 ///<returns></returns>

81         [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

82         public bool Add(Model.User user, Model.Shop shop)

83         {

84             int shopID;

85             int UserID;

86

87             //注意,这个方法操作了两个数据库实例,为AddUser和AddShop。所以晋升为分布式事务

88             if (Add(user, out  UserID))

89             {

90                 shop.UserID = UserID;

91

92                 return Add(shop, out shopID);

93             }

94

95             return false;

96         }

97     }

98 }

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

 

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

 

 

 

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

 

 1 using System;

 2 using System.Collections.Generic;

 3 using System.Linq;

 4 using System.Text;

 5

 6 namespace ServiceHost

 7 {

 8     class Program

 9     {

10         static void Main(string[] args)

11         {

12             System.ServiceModel.ServiceHost host = new System.ServiceModel.ServiceHost(typeof(ServiceWCF.Seller));

13

14             host.Open();

15

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

17

18             Console.Read();

19         }

20     }

21 }

 

 

 1 <?xml version="1.0" encoding="utf-8"?>

 2 <configuration>

 3   <system.web>

 4     <compilation debug="true" />

 5   </system.web>

 6   <!-- 部署服务库项目时,必须将配置文件的内容添加到

 7   主机的app.config 文件中。System.Configuration 不支持库的配置文件。-->

 8   <system.serviceModel>

 9     <services>

10       <service name="ServiceWCF.Seller">

11         <endpoint address="" binding="wsHttpBinding" contract="ServiceWCF.ISeller">

12           <identity>

13             <dns value="localhost" />

14           </identity>

15         </endpoint>

16         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

17         <host>

18           <baseAddresses>

19             <add baseAddress="http://localhost:8732/Seller/" />

20           </baseAddresses>

21         </host>

22       </service>

23     </services>

24     <behaviors>

25       <serviceBehaviors>

26         <behavior>

27           <!-- 为避免泄漏元数据信息,

28           请在部署前将以下值设置为false 并删除上面的元数据终结点  -->

29           <serviceMetadata httpGetEnabled="True" />

30           <!-- 要接收故障异常详细信息以进行调试,

31           请将以下值设置为true。在部署前设置为false

32             以避免泄漏异常信息-->

33           <serviceDebug includeExceptionDetailInFaults="False" />

34         </behavior>

35       </serviceBehaviors>

36     </behaviors>

37   </system.serviceModel>

38   <connectionStrings>

39     <add name="CommerceEntities" connectionString="metadata=res://*/Commerce.csdl|res://*/Commerce.ssdl|res://*/Commerce.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=VONXCEVF0IT7JDJ;Initial Catalog=Commerce;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

40   </connectionStrings>

41 </configuration>

 

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

 

 

 

 1 using System;

 2 using System.Collections.Generic;

 3 using System.Linq;

 4 using System.Text;

 5 using System.ServiceModel;

 6 using ServiceWCF;

 7

 8 namespace ServiceClient

 9 {

10     class Program

11     {

12         static void Main(string[] args)

13         {

14             var user = new Model.User()

15             {

16                 UserName = "huangxincheng520",

17                 Password = "i can fly"

18             };

19

20             var shop = new Model.Shop()

21             {

22                 ShopName = "shopex",

23                 ShopUrl = "http://www.shopex.cn"

24             };

25

26             var factory = new ChannelFactory<ISeller>();

27

28             var client = factory.CreateChannel();

29

30             if (client.Add(user, shop))

31                 Console.WriteLine("huangxincheng520, 恭喜你,数据插入成功。");

32             else

33                 Console.WriteLine("huangxincheng520, 呜呜,数据插入失败。");

34

35             Console.Read();

36         }

37     }

38 }


最后就是测试了:

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

  

/

 

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

  

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

 

 1   ///<summary>

 2 /// User,Shop的插入的操作

 3 ///</summary>

 4 ///<param name="user"></param>

 5 ///<param name="shop"></param>

 6 ///<returns></returns>

 7         [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

 8         public bool Add(Model.User user, Model.Shop shop)

 9         {

10             int shopID;

11             int UserID;

12            

13             if (Add(user, out  UserID))

14             {

15                 //注意注意,我在Adduser成功的情况下,抛出异常,看是否回滚。

16                 throw new Exception();

17

18                 shop.UserID = UserID;

19

20                 return Add(shop, out shopID);

21             }

22

23             return false;

24         }

 

 

 

截图如下:

/

 

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

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

 

/

 

 

作者 huangxincheng520