开发者社区> 一线码农> 正文

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

简介:
+关注继续查看

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

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

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
DataFountain训练赛汇总,成长在于不断学习(上)
DataFountain训练赛汇总,成长在于不断学习(上)
4 0
JavaScript 对象入门使用JSON
JavaScript对象表示法(JSON)是用于将结构化数据表示为JavaScript对象的标准格式,通常用于在网站上表示和传输数据
4 0
js的严格模式(strict mode)
JavaScript 严格模式(strict mode)即在严格的条件下运行。 "use strict" 指令只允许出现在脚本或函数的开头。 为什么使用严格模式: 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为; 消除代码运行的一些不安全之处,保证代码运行的安全; 提高编译器效率,增加运行速度; 为未来新版本的Javascript做好铺垫。
4 0
如何实现多账号共享VPC
多账号共享VPC架构具备上下通吃的特点,今天就给大家介绍一下这个架构要如何落地实施。
7 0
比赛背景 Background
比赛背景 Background
3 0
【Jenkins+Blue Ocean】docker部署Jenkins,编写Jenkinsfile创建流水线,一篇解决“贼带劲”
Jenkins 是一个持续集成工具,可用于自动化与构建、测试、交付或部署软件相关的各种任务。 Jenkins 可以通过本机系统包、Docker 安装,甚至可以由任何安装了 Java 运行时环境 (JRE) 的机器独立运行。 持续集成工具还有Drone、Gitlab-CICD(gitlab内置cicd)还要kubesphere容器云平台也能做持续集成(CICD)kubesphere是借助于Jenkins来实现CICD,本身没有该功能。 本章就带各位简单搭建Jenkins和使用Jenkins+Blue Ocean及编写Jenkinsfile流程。
5 0
spring security技术分享(二)
用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。 认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也可以是接入的设备或者其他系统。
4 0
牛逼!TCP 粘拆包问题及 Netty 中的解决方案
本文选自 Doocs 开源社区旗下“源码猎人”项目,作者 AmyliaY。
4 0
ESC阿里云服务器学习使用心得
在大一学习微信小程序时,以ESC阿里云服务器为后台进行学习时的心得分享。
4 0
【DataFountain-CV训练赛】
【DataFountain-CV训练赛】
3 0
+关注
194
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载