【问题标题】:WCF Versioning : Update Attribute Namespaces and Support Previous NamespacesWCF 版本控制:更新属性命名空间并支持以前的命名空间
【发布时间】:2010-08-19 05:38:19
【问题描述】:

我有三个 WCF 服务 (.svc),它们为 SOAP 消息生成 .wsdl 引用。

假设命名空间的一部分需要针对所有 ServiceContract、OperationContract、DataContract 属性进行更改,例如

[DataContract(Namespace = "http://old.com.au/types/")]

[DataContract(Namespace = "http://new.com.au/types/")]

为什么我仍然可以支持具有旧服务引用的客户(无需他们更新,因为他们可能没有时间立即更新)并允许客户获取新服务引用以获取新服务引用命名空间? 没有任何服务在改变,只是命名空间。

到目前为止,我已经阅读了很多内容,但以下文章建议可以从 ServiceHostFactory 更改服务类型:http://blog.ranamauro.com/2008/07/hosting-wcf-service-on-iis-site-with_25.html

这意味着创建每个合约中的两个(将尽可能多的实现放在一个地方),并在运行时确定要使用的服务类型。这会在我的场景中造成一些混乱。

问。是否有替代的好方法来完成此操作,或者是否期望不应执行此类操作,并且客户端会更新到新的命名空间。

(如果客户端的命名空间不匹配,我会收到错误消息:由于 ContractFilter 不匹配,接收方无法处理带有操作“...”的消息)

【问题讨论】:

    标签: wcf versioning xml-namespaces


    【解决方案1】:

    IMO,您需要在(最好)旧端点为您以前的客户托管旧服务,并在新端点提供新服务。当您的所有旧客户端迁移到新版本时,您可以取出旧服务。 也许,您可以使用继承来减少工作量,例如

    [DataContract(OldNameSpace)]
    ClassA {
     ...
    }
    
    [DataContract(NewNameSpace)]
    ClassB : ClassA {
    }
    

    同样,通过继承新的服务合同来创建新的服务合同。服务实现不需要改变,但它需要实现新的合同。现在您必须配置两个端点 - 一个用于旧合同,另一个用于新合同。

    编辑:放置示例接口和实现

    假设您的旧合同类似于

    public interface IOldContract
    {
        ClassA GetFoo();
        void DoBar(ClassA a);
    }
    

    现在您可以选择新合同为

    public interface INewContract
    {
        ClassB GetFoo();
        void DoBar(ClassB b);
        ClassB GetMix(ClassB a);
    }
    

    或作为

    public interface INewContract2 : IOldContract
    {
        ClassB GetFoo2();
        void DoBar2(ClassB b);
        ClassB GetMix2(ClassB b);
    }
    

    我倾向于采用后来的变化(因为新合同与旧合同保持兼容)。但是在您的情况下,您可以选择前者,因为无论如何您都会暴露两个端点。 现在你需要修改服务实现如下:

        public class ServiceImplementation : INewContract2
    {
        #region INewContract2 Members
    
        public ClassB GetFoo2()
        {
            // Your old implementation goes here 
        }
    
        public void DoBar2(ClassB b)
        {
            DoBar(b);
        }
    
        public ClassB GetMix2(ClassB b)
        {
            return GetMixHelper(b);
        }
    
        #endregion
    
        #region IOldContract Members
    
        public ClassA GetFoo()
        {
            return GetFoo2();
        }
    
        public void DoBar(ClassA a)
        {
            // You old implementation goes here
        }
    
    
        public ClassA GetMix(ClassA a)
        {
            return GetMixHelper(a);
        }
    
        #endregion
    
        private ClassB GetMixHelper(ClassA a)
        {
            // Your old implementation goes here
        }
    
    }
    

    我希望你能明白。即使在这里,您也有多种代码组织选择。您可以有两个框架服务实现类 - 一个用于旧合同,另一个用于新合同。两者都将实际功能委托给帮助程序类(这是您当前的实现)。

    【讨论】:

    • 如果我每个数据合约有 2 个,就会出现问题,而我需要在很多实现上加倍......旧服务返回 ClassA 我现在需要一个新的服务和返回的方法一个 ClassB,但它是相同的实现,如果我想共享现有功能的一部分,我必须从将 ClassA 作为 ClassB 返回的内部方法映射返回类型。
    • 正如您所说,您需要创建内部方法,其中返回类型应该是子类(新数据协定类),参数将是超类(旧数据协定类)。检查我编辑的回复以获取想法。
    • 感谢您的建议,您的示例存在一些小问题,但我明白您在指出什么。原始解决方案的返回类型需要映射为新解决方案的返回类型,因此可以使用大部分实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多