WCF架构和Evolution,版本

M A*_*ifi 5 c# wcf

这个问题围绕如何构建WCF服务以使其随着时间的推移变得容易.在没有描述问题的情况下很难得到对此的响应深度.

背景

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

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

数据合同

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

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

    // More members
}
Run Code Online (Sandbox Code Playgroud)

DataContract难以初始化并有一个标准的MyContractFactory类初始化获得相应的实例为您的机器.

public class static MyContractFactory
{
    public static MyContract GetMyContract()
    {
        // Complex implementation
    }
}
Run Code Online (Sandbox Code Playgroud)

ServiceContracts

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

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

    [ServiceContract]
    public class IMyInterface2
    {
        [OperationContract]
        public void DoSomethingDifferentWithMyContract(MyContract data);
    }
}
Run Code Online (Sandbox Code Playgroud)

客户

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

实施1

我对此(默认WCF)的初始实现最终得到了DataContract一个程序集ServiceContract,并在其自己的程序集中实现.

客户最终非常难看,

MyWebService1.MyContract
MyWebService2.MyContract
Run Code Online (Sandbox Code Playgroud)

随着MyContractFactory几乎每个插件的复制和粘贴.虽然它们DataContract是相同的,但客户端不包含DataContract程序集的事实意味着它在不同的名称空间中显示为不同的对象.

实施2

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

随着第二次实现我现在面临的困难,我如何更新我DataContractServiceContracts

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

  2. 我是否创建了一个扩展类的新程序集MyDataContract,接受新类型的新方法ServiceContract?这是否意味着我的合同每次微小的改变都需要新的装配?我怎么能阻止它在几年内达到几百个呢?

  3. 其他解决方案?

无论我想到什么解决方案,它们似乎都有一个重大的缺点.

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

  • 在客户端更新之前保留向后兼容性
  • 随着软件的发展,随着软件的发展,保持客户不受任何膨胀
  • 没有明显污染我的ServiceContract(重载OperationContract需要一个新的"名称").我已经有了类似下面的内容,随着时间的推移,这让我感到噩梦.

操作合同复杂性

[OperationContract]
public void DoSomethingWithMyContract(MyContract data);

[OperationContract(Name = "DoSomethingWithMyDataByAdditionalData"]
public void DoSomethingWithMyContract(MyContract data, MyContract2 additionalData);
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个在大规模环境中工作了一段时间的解决方案.博客条目等非常受欢迎.

更新1

纵观使用"无模式"更改的局限性,不同的命名空间似乎是唯一可靠的方法.但是,它没有按预期工作,例如下面

[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
}
Run Code Online (Sandbox Code Playgroud)

有以下服务

public class MyService : IServiceContract1, IServiceContract2
{
    // Implement both operations
}
Run Code Online (Sandbox Code Playgroud)

和以下配置

  <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>
Run Code Online (Sandbox Code Playgroud)

结果有两个不同名称的合同,我希望我能指出我的客户,

http://myurl.com/MyService.svc/2012/05 旧版本和http://myurl.com/MyService.svc/2012/06

,但似乎我想保留ServiceContract名称,他们必须是两个单独的服务,而不是相同服务的单独端点地址?

更新2

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

mar*_*c_s 5

微软和大多数受人尊敬的WCF大师都可能会说同样的事情:应该使用合同命名空间来处理版本控制.

我不是指程序集的.NET命名空间 - 我的意思是实际的WCF服务(和数据协定)命名空间 - 所以你应该:

[ServiceContract(Namespace="http://services.yourcompany.com/Service1/V01"]
Run Code Online (Sandbox Code Playgroud)

或类似的东西 - 一些人喜欢按年/月的版本:

[ServiceContract(Namespace="http://services.yourcompany.com/Service1/2012/05"]
Run Code Online (Sandbox Code Playgroud)

这允许您拥有相同服务的多个版本,并且只要客户端使用旧版本(由服务命名空间指示)调用,它们就会获得旧版本(只要您仍然公开它).

看到: