zoukankan      html  css  js  c++  java
  • 关于已部署的WCF服务升级的问题

    在日常的开发过程中,我们会经常迭代发布不同的版本,所以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; }

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

  • 相关阅读:
    @PostConstruct和 @PreDestroy注解
    【JQuery】,ajax请求中,url出现[Object Object]
    筛法求素数
    母牛的故事
    将一个数拆分
    计算两个日期差
    用二分查找——查找比目标元素略大的索引
    反向输出字符串
    bootstrap table合并单元格(该版本是简单的应用)
    获取访问者IP
  • 原文地址:https://www.cnblogs.com/JustYong/p/5481440.html
Copyright © 2011-2022 走看看