uldはサービス契約のバージョン管理を実装する必要があります。その時点で、このVersioning Strategiesページに記載されているように、WCF自身の機能を利用してクライアントを壊さない小さな変更を無視することができます。
図1では、操作シグネチャに新しいパラメータを追加したり、操作シグネチャからパラメータを削除したり、新しい操作を追加したりすると、クライアントは影響を受けません。
まだ突然の変更がある場合や、お客様のクライアントが両方のバージョンをサポートする必要がある場合(私はあなたの導入戦略がわからないので間違っている場合は修正してください)、異なるバージョンのサービスを別々のエンドポイントクライアントコードにWCFクライアントファクトリがあり、適切なエンドポイントのクライアントを返すように構成できます。
この時点で、さまざまなクライアントでさまざまな実装が分離されています。これはおそらく、現在よりもクリーンでメンテナンスの悪いことではありません。私たちは私たちのサービスのための2つの異なる契約、古いものと新しいものを持っていることとします物事をクリアする
非常に基本的なサンプル実装。両方のサービスが同じ名前で異なる名前空間を持っているか
[ServiceContract(Name = "Service", Namespace = "http://stackoverflow.com/2012/03")]
public interface IServiceOld
{
[OperationContract]
void DoWork();
}
[ServiceContract(Name = "Service", Namespace = "http://stackoverflow.com/2012/04")]
public interface IServiceNew
{
[OperationContract]
void DoWork();
[OperationContract]
void DoAdditionalWork();
}
注意。
拡張サービスと新しいサービスの両方をサポートする必要があるクライアントと、古いサービスの両方をサポートする必要があるという問題を解決しましょう。以前はDoWorkを呼び出したばかりのときにDoAdditionalWorkメソッドを呼び出したいとし、DoAdditionalWorkがクライアントから余分な引数を必要とする可能性があるため、クライアントサイドの状況を処理したいとします。そして、サービスの構成は次のようなものが考えられます。
<service name="ConsoleApplication1.Service">
<endpoint address="http://localhost:8732/test/new" binding="wsHttpBinding" contract="ConsoleApplication1.IServiceNew" />
<endpoint address="http://localhost:8732/test/old" binding="wsHttpBinding" contract="ConsoleApplication1.IServiceOld" />
...
</service>
ファイン、我々は今、興味深い部分に、サービス側を持っている:我々は、同じインターフェイスを使用してサービスと通信したいと思います。この場合は古いものを使用しますが、その間にアダプタを置く必要があります。
internal class ClientFactory
{
public IServiceOld GetClient()
{
string service = ConfigurationManager.AppSettings["Service"];
if(service == "Old")
return new ClientOld();
else if(service == "New")
return new ClientNew();
throw new NotImplementedException();
}
}
私がするために使用するクライアントの決定を委任:
IServiceOld client = *Magic*
client.DoWork();
この場合、魔法は、このような単純な工場がある:理想的には、私たちのクライアントコードでは、我々はこのような何かをするだろうapp.configは、あなたのバージョンチェックを挿入することができます。 ClientOldの実装はIServiceOldのためだけに通常のWCFクライアントです:
public class ClientOld : IServiceOld
{
private IServiceOld m_Client;
public ClientOld()
{
var factory = new ChannelFactory<IServiceOld>(new WSHttpBinding(), "http://localhost:8732/test/old");
m_Client = factory.CreateChannel();
}
public void DoWork()
{
m_Client.DoWork();
}
...
}
ClientNewではなく、すなわちDoAdditionalWork操作を呼び出し、我々が希望された動作を実装:
public class ClientNew : IServiceOld
{
private IServiceNew m_Client;
public ClientNew()
{
var factory = new ChannelFactory<IServiceNew>(new WSHttpBinding(), "http://localhost:8732/test/new");
m_Client = factory.CreateChannel();
}
public void DoWork()
{
m_Client.DoWork();
m_Client.DoAdditionalWork();
}
...
}
ことだ。つまり、今、私たちのクライアントができます次の例のように使用してください:
var client = new ClientFactory().GetClient();
client.DoWork();
私たちは何を達成しましたか?クライアントを使用するコードは、実際のWCFクライアントがどのような追加作業をしなければならないか、どのクライアントを使用するかの決定が工場に委任されたものから抽象化されます。私はこのサンプルのいくつかのバリエーション/拡張があなたのニーズに合うことを願っています。
クイックレスポンスありがとう!最低限、私はIsValidToRunのようなメソッドでこのロジックを集中させるべきだと思います。私はServerFeaturesクラスは素晴らしいアイデアだと思うし、新しいビルドが出されたときにどのチェックを排除できるかを追跡するのに役立つかもしれない。 –
@JohnRussell、それはまたあなたの目的を達成するための良い方法をビルドすることができます。チェックが不要になったときに 'ServerFeatures'バージョンを削除し、コンパイルして、それに依存する壊れた場所をすべて修正します。 –
まさに!私はそれが好きです!私は実際にServerFeatureを列挙して、ServerFeatureへのバージョンマッピングをヘルパーメソッドで実行すると思います。大きなswitch文。これにより、同じバージョンを複数の機能に再利用し、すべてのロジックを1つの場所に持たせることができます。 IsValidToRunはServerFeatureをパラメータとして受け取り、うまくいけば、消費者がフライバージョンのオブジェクトで使用するのを防ぎます。助けてくれてありがとう! –