关于已部署的服务升级的问题

在日常的开发过程中,我们会经常迭代发布不同的版本,所以WCF服务的接口也会经常处于变动的状态,比如在传递实体类中新加一个字段、修改参数名称等等关于服务升级的问题。但是我们不可能让已发布的版本重新引用新的服务,这是不现实的,所以我们在升级WCF服务时,一定要让服务兼容以前的版本。现在我们分别介绍关于服务升级的几个常用情况。

一、参数变动

我们来实现最初的版本1.0,新建一个服务接口,服务实现很简单,在Output窗口中简单输出服务接收到的参数值。

    [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(string id, string username, int age);
    }
    public class TestingService : ITestingService
    {
        public void AddUser(string id, string username, int age)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", username));

            System.Diagnostics.Debug.WriteLine(string.Format("age = {0}", age));
        }
    }

在客户端引用1.0版本的服务,调用服务接口

    class Program
    {
        static void Main(string[] args)
        {
            var testingServiceClient = new TestingServiceClient();

            testingServiceClient.AddUser("001", "James", 18);

            Console.ReadKey();
        }
    }

在服务端的Output输出结果如下

1.添加参数

考虑一种特别常用的情形,我需要添加一个新的字段,以便得到更多的信息,我们需要升级服务至2.0,所以我们需要修改接口和实现。最终的结果当然是不影响引用1.0服务的客户端的继续使用。

让我们修改接口和实现。

    [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(string id, string username, int age, string city);
    }
    public class TestingService : ITestingService
    {
        public void AddUser(string id, string username, int age, string city)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", username));

            System.Diagnostics.Debug.WriteLine(string.Format("age = {0}", age));

            System.Diagnostics.Debug.WriteLine(string.Format("city = {0}", city));
        }
    }

首先我们需要保证引用1.0服务的客户端的继续使用,所以我们先测试引用1.0服务的客户端。

从测试结果可以看到,在引用旧的服务的客户端在调用新的服务时,可以正常调用,只是新添加的字段是默认值。这是正确的结果,因为在旧的客户端传递过来的数据中不包含新添加的字段的信息,自然新添加的字段的值是默认的值。

2.删除不再需要的参数

紧接1.0版本,假设在新的2.0版本中不再需要age的值,所以需要在接口中删除这个参数,所以需要修改接口和实现。

   [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(string id, string username);
    }
    public class TestingService : ITestingService
    {
        public void AddUser(string id, string username)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", username));
        }
    }

首先我们需要保证引用1.0服务的客户端的继续使用,所以我们先测试引用1.0服务的客户端。

从测试结果可以看到,在引用旧的服务的客户端在调用新的服务时,可以正常调用。

3.修改参数名(重构)

紧接1.0版本,假设在新的2.0版本中需要修改username名为name,所以需要修改接口和实现。

   [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(string id, string name);
    }
    public class TestingService : ITestingService
    {
        public void AddUser(string id, string name)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", name));
        }
    }

在保证客户端不引用新的服务的前提下,我们测试客户端的服务调用情况。

从结果可以看到,如果修改了参数的名称则会影响到旧版本客户端的使用,难道没有别的什么方法可以解决这个问题么?答案是有的,如果想要重构但是不想改动客户端代码的话,那么可以给参数加上一个MessageParameter的属性,代码如下:

    [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(string id, [MessageParameter(Name = "username")]string name);
    }

重新测试旧版本的客户端,可以看到最终的结果又恢复正常。

二、实体的变动

在第一部分我们谈论的是参数的变动,在第二部分我们变化实体中属性的变动。先来定义最初的1.0服务版本。

    [DataContract]
    public class User
    {
        [DataMember]
        public string Id
        {
            get;
            set;
        }

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

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

    }
   [ServiceContract]
    public interface ITestingService
    {
        [OperationContract]
        void AddUser(User user);
    }
    public class TestingService : ITestingService
    {
        public void AddUser(User user)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", user.Id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", user.Name));

            System.Diagnostics.Debug.WriteLine(string.Format("age = {0}", user.Age));
        }
    }

客户端引用最初的服务

    class Program
    {
        static void Main(string[] args)
        {
            var testingServiceClient = new TestingServiceClient();

            var user = new User() { Id = "001", Name = "Tommy", Age = 25};

            testingServiceClient.AddUser(user);

            Console.ReadKey();
        }
    }

测试结果如下

1.在实体类中添加属性

在User类中添加City属性,以便在新的服务版本中获取更多的用户信息。服务接口不变,只需修改实体类和服务实现。

    [DataContract]
    public class User
    {
        [DataMember]
        public string Id { get; set; }

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

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

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

    }
        public void AddUser(User user)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", user.Id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", user.Name));

            System.Diagnostics.Debug.WriteLine(string.Format("age = {0}", user.Age));

            System.Diagnostics.Debug.WriteLine(string.Format("city = {0}", user.City));
        }

在保证客户端不引用新的服务的前提下,测试客户端的服务调用情况。从结果可以看出,旧的客户端可以正常调用新的服务,只是新添加的字段没有显式赋值。

2.在实体类中删除属性

在User类中删除Age属性。服务接口不变,只需修改实体类和服务实现。

    [DataContract]
    public class User
    {
        [DataMember]
        public string Id { get; set; }

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

    }
    public class TestingService : ITestingService
    {
        public void AddUser(User user)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", user.Id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", user.Name));

        }
    }

在保证客户端不引用新的服务的前提下,测试客户端的服务调用情况。从结果可以看出,旧的客户端可以正常调用新的服务。

3.在实体类中修改属性名

在User类中修改Name属性的名称为UserName。服务接口不变,只需修改实体类和服务实现。

    [DataContract]
    public class User
    {
        [DataMember]
        public string Id { get; set; }

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

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

    }
    public class TestingService : ITestingService
    {
        public void AddUser(User user)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("id = {0}", user.Id));

            System.Diagnostics.Debug.WriteLine(string.Format("username = {0}", user.UserName));

        }
    }

在保证客户端不引用新的服务的前提下,测试客户端的服务调用情况。

从结果可以看到,如果修改了实体属性的名称则会影响到旧版本客户端的使用,可以在DataMemeber中设定Name属性的值,代码如下

  [DataMember(Name = "Name")]
  public string UserName { get; set; }

重新测试客户端,发现可以继续正常使用。

时间: 2024-10-06 03:03:56

关于已部署的服务升级的问题的相关文章

CDH 5.16.1 离线部署 & CDH 部署 Hadoop服务

参考 Cloudera Enterprise 5.16.x Installing Cloudera Manager, CDH, and Managed Services Installation Path B - Manual Installation Using Cloudera Manager Packages 一. 环境 1.1 系统节点信息 Hostname IP CPU(cores) Memory(GB) OS Service Remark master 172.30.200.75 2

生产环境部署squid服务

网络拓扑 该实验使用虚拟机模拟搭建,准备开启2台虚拟机,客户端用本记代替. 1.Squid服务器使用2块网卡.如下图显示: 2.Web服务器与squid服务器配置在同一个网段即可.如下图显示: 3.客户端IP与squid服务器网卡1是在同一网段上即可.如下图显示: 4.查看squid服务器上的eth0和eth1网卡ip地址 5.查看web服务器的ip地址 6.先测试客户端能否ping通squid服务器的网卡1. 7.测试客户端能否ping通web服务器,ping不通正常. 8.安装squid软件

如何将phantomjs单独部署在服务端

如何将phantomjs单独部署在服务端 文章目录 一. 容我分析(lao dao)几句 二. 服务端 Look here 服务端phantomjs搭建 web端搭建及如何调用phantomjs 三. 效果展示啦 hey,every one ,很久没给大家分享技术型的文章啦,今天抽时间来一发吧 一. 容我分析(lao dao)几句 之前写了2篇 highcharts 结合 phantomjs 后端生成图片的文章,http://www.peng8.net/2014/07/21/render-cha

IIS Internal Server Error &IIS8中部署WCF服务出错:HTTP 错误 404.3 - Not Found

Http error      503. The service is unavailable. Due to appliction pool is stop and start it can resolve it Server Error Internet Information Services 7.5 Error Summary HTTP Error 500.19 - Internal Server Error The requested page cannot be accessed b

代码服务升级步骤整理

1.首先使用VNC Viewer登录到 代码服务器(192.168.12.167),然后更新项目MIS_Release 将代码更新. 2.将更新的项目 添加到压缩文件,压缩为.zip.将该.zip包复制到本地. 3.远程登录 172.16.4.2 服务器,将2步骤中的.zip包复制到该系统中D:/AUTOUPLOAD 文件夹下并解压,将项目名称改为mis. 4.找到C盘下运行说明文件,粘贴其中命令,并在cmd窗口中,C盘根下运行粘贴的命令. 5.会自动部署项目,进行服务升级 ----------

轻轻松松在centos上部署docker服务

首先,因为docker的运行需要linux本身某些组件和内核特性的支持,所以要确保centos的版本大于6,并且内核版本大于2.6.32-431.可以简单的升级centos6到最新版本. sudo yum upgrade 然后安装cgroup sudo yum install libcgroup service cgconfig start #启动croup服务 lssubsys -am 如果安装成功,最后一个命令lssubsys -am会显示所有子系统的挂载点 源码方式安装lxc sudo y

[自动化] 部署Ansible服务及其常用的命令模块

Ansible简介: Ansible基于Python开发,默认通过SSH协议进行远程命令执行或下发配置,无需部署任何客户端代理软件,可同时支持多台主机进行管理.ansible是基于模块工作的,本身没有批量部署的能力,真正具有批量部署的是ansible所运行的模块,能够实现批量运行命令.部署程序.配置系统等功能. Ansible的基本架构主要包括: (1)Ansible core核心引擎.(2)Host inventory 主机清单:用来定义Ansible管理的主机,默认是在Ansible配置文件

部署WDS服务

WDS的全称为Windows部署服务,主要应用于大中型网络中的计算机操作系统的批量化部署.通过使用WDS可以管理系统映像和无人参与安装脚本,并提供人工参与安装和无人参与安装的方式,大大提升我们安装操作系统的速度.当需要给一个两个PC安装系统时,可能没必要使用该服务,可是当需要给五十台,上百台PC安装呢?我们还要使用笨拙的方法实施么?计算机就是来给我们提供方便的,当你重复做一件事的时候,你就该考虑换一种方法了,WDS只是实现的方法之一.本文为个人的一些总结,使用VMware虚拟机部署,不足之处,还

docker微服务部署之:六、Rancher管理部署微服务

docker微服务部署之:五.利用DockerMaven插件自动构建镜像 一. 什么是Rancher Rancher是一个开源的企业级容器管理平台.通过Rancher,企业再也不必自己使用一系列的开源软件去从头搭建容器服务平台.Rancher提供了生产环境中使用的管理Docker和Kubernetes的全栈化容器部署与管理平台. Rancher官网:https://rancher.com 二.Docker中下载Rancher镜像并运行 #Rancher镜像下载 $ sudo docker pul