.NETアーキテクチャの問題:2つのWebサービス、実行時に使用するWebサービスを変更するにはどうすればよいですか?
-
02-07-2019 - |
質問
Reporting ServicesとSharepointを使用していますが、Reporting Servicesを活用するアプリケーションがありますが、クライアントはアプリケーションをsharepointに統合したいと考えています。現在、操作を実行するためのさまざまなメソッドを公開するReportService.asmx Webサービスと密結合しています。 Reporting Servicesには、「Sharepoint Integration mode」と呼ばれるものがあります。有効にすると、レポートサーバーの動作が異なり、Sharepointを使用してレポートが管理されます。 Sharepointは、ほぼ同じReportService2006.asmxという新しいWebサービスを追加します。
現在、アプリケーションはReportServiceへのWeb参照を使用し、サービスによって公開されているさまざまなオブジェクトを使用しています。 ReportService2006にはまったく同じオブジェクトがありますが、明らかに異なる名前空間にあります。たとえば、各サービスへの2つのWeb参照があるため、オブジェクトMyApplication.ReportService.CatalogItemと別のMyApplication.ReportService2006.CatalogItemがあります。
依存関係注入を使用して、ファクトリパターンと組み合わせたアプリケーションからサービスを除外して、インスタンス化するインターフェイスの実装を決定しようとしました。インターフェースはここにあります。このアプリケーションに必要な呼び出しのみを含めるように簡略化しました。
using System;
using NetworkUserEncrypt.ReportService;
namespace MyApplication.Service
{
public interface IReportingService
{
CatalogItem CreateDataSource(string DataSource, string Parent, bool Overwrite, DataSourceDefinition Definition, Property[] Properties);
void DeleteItem(string Item);
DataSourceDefinition GetDataSourceContents(string DataSource);
byte[] GetReportDefinition(string Report);
CatalogItem[] ListChildren(string Item);
}
}
そのため、それぞれ異なるWebサービスをインスタンス化する2つの実装があります。例:
namespace MyApp.Service.Implementation
{
class ReportingServiceImpl : IReportingService
{
ReportingService _service = null;
public ReportingServiceImpl()
{
ReportingService _service = new ReportingService();
}
/* SNIP */
}
}
and
namespace MyApp.Service.Implementation
{
class ReportingService2006Impl : IReportingService
{
ReportingService2006 _service = null;
public ReportingService2006Impl()
{
ReportingService2006 _service = new ReportingService2006();
}
/* SNIP */
}
}
そのため、実行時にこれらをServiceWrapperに注入できるようにする計画です。ただし、インターフェイスがReportServiceに関連付けられており、一部のメソッドがWeb参照(たとえばCatalogItem。したがって、ReportService2006の実装が別のネームスペースからCatalogItemを参照しているため、プロジェクトはビルドされません。
アイデアはありますか?私はこれでまったく間違った方向に進んでいますか?
解決
最も堅牢なソリューションは、CatalogItemインターフェイスを作成し、各Webサービスのラッパーを作成して、ファクトリーの背後にあるものをすべて隠すことです。ファクトリには" correct"を呼び出すためのロジックが含まれます。インターフェイスを使用するには、Webサービスとクライアントコードを変更する必要がありますが、それは改善のためです。
WCFはこれらの問題のほとんどをサービスコントラクトで解決します。私の以前のアドバイスが扱いにくいと判明した場合は、WCFソリューションへの移行を検討できます。
他のヒント
あなたはこの状況に向かって正しい方向に向かっていると思います。それを家に追いやるにはかなりの労力を費やすだけです。リフレクションまたは動的メソッドを使用して、両方のバージョンのクラスをラップできるプロキシクラスをいくつか作成します。また、リモートネームスペースのプロキシクラスを使用して、実行時にメソッド呼び出しをインターセプトし、それらを適切な場所に転送します。そうすれば、手動でコーディングするのではなく、オンデマンドで動的メソッドを作成できます。オブジェクトのインターフェースと一致するインターフェースです。
必要な参照を追加するか、CatalogItemおよびその他の特定のクラスのラッパーを構築します。ラッパーを作成すると、インターフェイスは特定の実装を参照せずに単独で立つことができるはずです。
Webサービスが異なる名前空間に存在する場合、簡単な解決策はありません(たとえば、URLを変更するような単純なもの)。ただし、抽象化によって正しい軌道に乗っているようです。
ただし、冒険心がある場合は、生成されたWebサービスクラス(" reference.cs"ファイル)を自分で変更し、プロジェクトに手動で追加できます。最初に共通のインターフェイスを作成してから、ファイルの最初の行を次のように変更します。
public partial class MyWebService : SoapHttpClientProtocol, IMyWebService
次に、これを使用してコードを呼び出します:
IMyWebService webService = new MyWebService(); // Or you can use a Factory
VS2008では、Webサービスにサービス参照を追加しようとすると、詳細ボタンが表示されます。クリックすると、"タイプを再利用"するオプションがあります。