この質問は、時間の経過とともに進化しやすいように 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
うか。
同じアセンブリを更新して、バージョン番号を増やしますか? すべてのクライアントをアップグレードする間、下位互換性を維持するにはどうすればよいですか? 更新するまでクライアントを中断することは受け入れられません。
MyDataContract
new の下で新しい型を受け入れる新しいメソッドを拡張するクラスで新しいアセンブリを作成しServiceContract
ますか? これは、契約に小さな変更を加えるたびに、新しいアセンブリが必要になるということですか? 数年で文字通り数百人にならないようにするにはどうすればよいでしょうか。他の解決策はありますか?
私が考え抜いた解決策に関係なく、それらにはすべて大きな欠点があるようです.
(少なくとも私には)ないようです。
- クライアントが更新されるまで下位互換性を維持する
- ソフトウェアが時間の経過とともに進化するにつれて、クライアントを肥大化させずにトリムし続ける
- 私を著しく汚染していません(新しい「名前」が必要な
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 は間違っているように見えますが、私がこれをテストしたところ、サービスは確かに古いクライアントの下で下位互換性があります。