zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

WCFWCF事务 速成 第三天 使用 系列学习
2023-09-14 08:57:29 时间

 

在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())

 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())

 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起到效果了,再来看一下数据库。大家都知道会发生什么了,对的,异常不再产生数据了,

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

 


三歪吐血总结了各个中间件是如何实现持久化的 到目前为止,三歪也已经接触到了不少的中间件了,比如说「Elasticsearch」「Redis」「HDFS」「Kafka」「HBase」等等。 可以发现的是,它们的持久化机制都差不得太多。今天想来总结一下,一方面想来回顾一下这些组件,一方面给还没入门过这些中间件的同学总结一下持久化的”套路“,后面再去学习的时候就会轻松很多。