WCF体系结构和演进,版本 [英] WCF Architecture, and Evolution, Version

查看:53
本文介绍了WCF体系结构和演进,版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是关于如何构造WCF服务以使其易于随时间演变的.不描述问题就很难获得对此的深度答复.

This question is around how to architect WCF services to make it easy to evolve over time. Its difficult to get the depth of response to this without describing the problem.

背景

我正在开发WCF服务和客户端的大型系统.服务器端很容易更新,因为只有10台服务器正在运行此代码.

I am developing a large system of WCF services and clients. The server side is "easy" to update as there are only 10 servers in question running this code.

尽管自动化程度很高,但在300,000多个WCF客户端上,客户端仍然很难更新,更新总是需要时间,并且在两到三周的时间内只能获得很高的更新成功率.

The clients are very difficult to update, despite the high degree of automation, at 300,000+ WCF clients, updates are something that will always take time, and only achieves a high update success rate over a period of two to three weeks.

数据合同

[DataContract]
public class MyContract
{
    [DataMember]
    public int Identity {get; set;}

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

    // More members
}

DataContract 很难初始化,并且具有标准的 MyContractFactory 类来初始化以获得适用于您计算机的实例.

The DataContract is difficult to initialise and has a standard MyContractFactory class to initialise obtain the appropriate instance for your machine.

public class static MyContractFactory
{
    public static MyContract GetMyContract()
    {
        // Complex implementation
    }
}

服务合同

DataContract 在一系列Web服务中非常常见.

The DataContract is very common across a range of web services.

namespace MyPrefix.WebServicve1
{
    [ServiceContract]
    public class IMyInterface1
    {
        [OperationContract]
        public void DoSomethingWithMyContract(MyContract data);
    }

    [ServiceContract]
    public class IMyInterface2
    {
        [OperationContract]
        public void DoSomethingDifferentWithMyContract(MyContract data);
    }
}

客户

我的客户端是基于插件的,其插件在单独的进程或应用程序域中运行,具体取决于我们对该插件的信任程度.

My client is plugin based with plugins running in either separate processes or app domains depending on the level of trust we have in that plugin.

实施1

我对此的最初实现(默认WCF)以一个程序集 DataContract ServiceContract 和其自己的程序集中的最终结果结束.

My initial implementation of this (default WCF) ended up with the DataContract in one assembly, ServiceContract, and implementation in its own assembly.

客户最终变得非常丑陋

MyWebService1.MyContract
MyWebService2.MyContract

在几乎每个插件中复制并粘贴 MyContractFactory .尽管 DataContract 是相同的,但客户端不包含 DataContract 程序集的事实意味着它在不同的命名空间下作为不同的对象出现.

With a copy and paste of the MyContractFactory in nearly every plugin. Whilst the DataContract was the same, the fact that the clients did not include the DataContract assembly meant that it appeared under different namespaces as different objects.

实施2

客户端现在包括 DataContract 程序集, ServiceContracts 与服务实现位于单独的程序集中,客户端可能包括某些 ServiceContract 程序集,如果它有助于代码重用(不再复制和粘贴).

The clients now include the DataContract assembly, ServiceContracts are in a separate assembly to the service implementation, clients may include some of the ServiceContract assemblies if it will aid with code reuse (no more copy and paste).

问题

在第二个实现中,我现在面临的困难是,如何更新我的 DataContract ServiceContracts ?

With the second implementation I am now facing the difficulty of, how do I update my DataContract and ServiceContracts?

  1. 我是否更新相同的程序集并增加版本号?在所有客户端升级时,如何保持向后兼容性?破坏客户端直到他们更新是不可接受的.

  1. Do I update the same assembly and increment the version number? How do I preserve backwards compatibility whilst all the clients upgrade? Breaking the clients until they update is not acceptable.

我是否使用扩展了 MyDataContract 的类创建新的程序集,在新的 ServiceContract 下接受新类型的新方法?这是否意味着我对合同进行的每一次微小更改都需要一个新的装配体?我要如何阻止它在几年内达到几百个字呢?

Do I create a new assembly with a class that extends MyDataContract, new methods that accept the new type under a new ServiceContract? Does that mean for every minor change to my contracts I need a new assembly? How would I stop it from getting to literally hundreds in a couple of years time?

其他解决方案?

不管我想出了什么解决方案,它们似乎都有很大的缺点.

Regardless of the solutions I think through, they all seem to have a major downside.

(至少对我而言)似乎没有

There doesn't seem to be (at least to me) of,

  • 保持向后兼容性,直到客户端更新
  • 随着时间的推移,随着软件的发展,保持客户的需求不会膨胀
  • 不会严重污染我的 ServiceContract ( OperationContract 的重载需要一个新的名称").我已经有下面这样的事情了,随着时间的推移,这让我感到噩梦.
  • Preserving backwards compatibility until clients update
  • Keeping the clients trim with no bloat as the software evolves over time
  • Not significantly polluting my ServiceContract (overloads of the OperationContract need a new "name"). I already have things like the below, and it strikes me a nightmare to maintain over time.

运营合同复杂度

[OperationContract]
public void DoSomethingWithMyContract(MyContract data);

[OperationContract(Name = "DoSomethingWithMyDataByAdditionalData"]
public void DoSomethingWithMyContract(MyContract data, MyContract2 additionalData);

我正在寻找在大规模环境中已使用一段时间的解决方案.非常欢迎博客条目之类的内容.

I am looking for a solution that has worked over a period of time in a large scale environment. Blog entries and the like are very welcome.

更新1

通过使用无模式"更改的局限性,不同的名称空间似乎是唯一可以肯定的方法.但是,它不能按预期工作,例如下方

Looking through the limitations of using "schemaless" changes, different namespaces seems like the only sure method. However, its not quite working as expected, e.g. below

[ServiceContract(
    Name = "IServiceContract",
    Namespace = "http://myurl/2012/05")]
public interface IServiceContract1
{
    // Some operations
}

[ServiceContract(
    Name = "IServiceContract",
    Namespace = "http://myurl/2012/06")]
public interface IServiceContract2
{
    // Some different operations using new DataContracts
}

提供以下服务

public class MyService : IServiceContract1, IServiceContract2
{
    // Implement both operations
}

和以下配置

  <service behaviorConfiguration="WcfServiceTests.ServiceBehavior"
    name="Test.MyService">
    <endpoint
      address="2012/05"
      binding="wsHttpBinding"
      contract="Test.IServiceContract1">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint
      address="2012/06"
      binding="wsHttpBinding"
      contract="Test.IServiceContract2">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>

产生两个具有两个不同名称的合同,我希望我可以指向我的客户,

Results in two contracts with two different names, I expected that I can point my clients to,

http://myurl.com/MyService.svc/2012/05 旧版本,以及 http://myurl.com/MyService.svc/2012/06

,但是好像我想保留ServiceContract名称,它们必须是两个单独的服务,而不是同一服务的单独端点地址?

, but it seems like if I want to preserve the ServiceContract name they have to be two separate services rather than separate endpoint addresses for the same service?

更新2

我最终使用了更新1 中描述的方法.尽管WSDL看起来不对,但在我测试了该服务之后,该服务的确确实是在旧客户端下向后兼容的.

I ended up using the method I have described under update 1. Whilst the WSDL looks wrong, the service is indeed backwards compatible under older clients when I've tested this.

推荐答案

Microsoft和大多数受尊敬的WCF专家都可能会说同一件事:应该使用合同命名空间处理版本控制

Both Microsoft and most of the respected WCF gurus out there will probably say the same thing: versioning should be handled using the contract namespaces.

我的意思不是您程序集的.NET命名空间-我的意思是实际的WCF服务(和数据协定)命名空间-因此您应该具有:

I don't mean the .NET namespaces of your assemblies - I mean the actual WCF service (and data contract) namespaces - so you should have:

[ServiceContract(Namespace="http://services.yourcompany.com/Service1/V01"]

之类的东西-有些人喜欢按年份/月份进行版本:

or something the like - some folks like to version by year/month:

[ServiceContract(Namespace="http://services.yourcompany.com/Service1/2012/05"]

这允许您具有同一服务的多个版本,并且只要客户端使用较旧的版本(由服务名称空间指示)进行调用,它们就会获得较旧的版本(只要您仍然公开该版本)

This allows you to have multiple versions of the same service, and as long as clients come calling with an older version (indicated by the service namespace), they'll get the old version (as long as you still expose that).

请参阅:

这篇关于WCF体系结构和演进,版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆