5

この質問は、時間の経過とともに進化しやすいように WCF サービスを設計する方法に関するものです。問題を説明せずに、これに対する反応の深さを理解することは困難です。

バックグラウンド

私は、WCF サービスとクライアントの大規模なシステムを開発しています。このコードを実行している問題のサーバーは 10 台しかないため、サーバー側は「簡単に」更新できます。

高度な自動化にもかかわらず、クライアントの更新は非常に難しく、300,000 以上の WCF クライアントでは、更新には常に時間がかかり、2 ~ 3 週間で高い更新成功率しか達成できません。

データ契約

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

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

    // More members
}

DataContract初期化が難しくMyContractFactory、マシンに適切なインスタンスを取得するための標準クラスがあります。

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

サービス契約

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);
    }
}

クライアント

私のクライアントは、プラグインの信頼レベルに応じて、個別のプロセスまたはアプリ ドメインで実行されるプラグイン ベースのプラグインです。

実装 1

これ (デフォルトの WCF) の私の最初の実装は、最終的DataContractに 1 つのアセンブリServiceContract内にあり、独自のアセンブリ内に実装されました。

クライアントは非常に醜いものになってしまいました。

MyWebService1.MyContract
MyWebService2.MyContract

MyContractFactoryほぼすべてのプラグインで をコピーして貼り付けます。は同じでしDataContractたが、クライアントにアセンブリが含まれていなかったという事実は、DataContractアセンブリが異なるオブジェクトとして異なる名前空間に表示されることを意味していました。

実装 2

クライアントにはDataContractアセンブリが含まServiceContractsれるようになり、サービス実装とは別のアセンブリになります。クライアントは、ServiceContractコードの再利用に役立つ場合はアセンブリの一部を含めることができます (コピー アンド ペーストは不要です)。

質問

2 番目の実装では、現在困難に直面しています。どのように更新すればよいのDataContractでしょServiceContractsうか。

  1. 同じアセンブリを更新して、バージョン番号を増やしますか? すべてのクライアントをアップグレードする間、下位互換性を維持するにはどうすればよいですか? 更新するまでクライアントを中断することは受け入れられません。

  2. MyDataContractnew の下で新しい型を受け入れる新しいメソッドを拡張するクラスで新しいアセンブリを作成しServiceContractますか? これは、契約に小さな変更を加えるたびに、新しいアセンブリが必要になるということですか? 数年で文字通り数百人にならないようにするにはどうすればよいでしょうか。

  3. 他の解決策はありますか?

私が考え抜いた解決策に関係なく、それらにはすべて大きな欠点があるようです.

(少なくとも私には)ないようです。

  • クライアントが更新されるまで下位互換性を維持する
  • ソフトウェアが時間の経過とともに進化するにつれて、クライアントを肥大化させずにトリムし続ける
  • 私を著しく汚染していません(新しい「名前」が必要なServiceContract過負荷)。OperationContract私はすでに以下のようなものを持っていますが、時間をかけて維持するのは悪夢です。

運用契約の複雑さ

[OperationContract]
public void DoSomethingWithMyContract(MyContract data);

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

大規模な環境で一定期間にわたって機能するソリューションを探しています。ブログ等も大歓迎です。

更新 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
}

以下のサービスで

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>

その結果、2 つの異なる名前を持つ 2 つの契約が作成されました。

古いバージョンの場合http://myurl.com/MyService.svc/2012/05、http://myurl.com/MyService.svc/2012/06

、しかし、ServiceContract名を保持したい場合、同じサービスの別々のエンドポイントアドレスではなく、2つの別々のサービスでなければならないようです?

更新 2

update 1で説明した方法を使用することになりました。WSDL は間違っているように見えますが、私がこれをテストしたところ、サービスは確かに古いクライアントの下で下位互換性があります。

4

1 に答える 1

5

Microsoftとそこにある尊敬されているWCFの達人のほとんどは、おそらく同じことを言うでしょう。バージョン管理は、コントラクト名前空間を使用して処理する必要があります。

アセンブリの.NET名前空間を意味するのではなく、実際のWCFサービス(およびデータコントラクト)の名前空間を意味するので、次のようにする必要があります。

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

または同様のもの-一部の人々は年/月ごとにバージョン管理するのが好きです:

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

これにより、同じサービスの複数のバージョンを持つことができ、クライアントが古いバージョン(サービスの名前空間で示される)で呼び出しを行う限り、クライアントは古いバージョンを取得します(それを公開している限り)。

見る:

于 2012-05-29T10:18:38.673 に答える