WCFサービスからインターフェイスを返すにはどうすればよいですか?
-
22-07-2019 - |
質問
いくつかのインターフェイスがあるとしましょう:
public interface IFoo {
IBar DoesStuff();
}
public interface IBar {
string Thingo { get; }
}
コードベース全体でこのコードを使用しています。 IFooプロセスを別のシステムに移動する必要があります(x64とx32の違い)。これがWFCを使用する理由です。私のWCFサービスはこのインターフェイスを実装しています。 「サービス参照」を作成すると、プロキシスタブは作成されますが、インターフェイスは変更されます。
public interface IFoo {
object DoesStuff();
}
IBar / BarをDataServiceとDataContractの両方として定義しようとしましたが、違いはありませんでした。インターフェイスを使用してプロキシコードを生成する方法はありますか?
モックオブジェクトがテスト用のインターフェイスのオブジェクトを生成できるかどうかを考えていますが、サービスにそれを尊重させることはできませんか?それともばかげたことや間違ったことをしましたか?
解決
IBarは具体的かつDataContractである必要があります。 WCFは分散オブジェクトに関するものではなく、データを転送し、そのデータに対してサービスを機能させる方法です。 WCFで動作するオブジェクトを返すことはできません。
他のヒント
まだ解決策が必要かどうかわかりません。以下は私がやることです。ここでのコツは、標準の「サービス参照の追加」を使用しないことです。多くのブログが示唆しているように、Channel Factoryを使用して独自のクライアントプロキシを作成しています。この場合、インターフェイスを再利用し、必要に応じて具象クラスを再定義することを選択できます。必要に応じてさらに詳しく説明します。
// Service Contract
[ServiceContract(name="a", namespace="b")]
public interface IFoo {
Bar DoesStuff();
}
// Interface to share
public interface IBar {
string Thingo { get; }
}
// Server Implementation
public class Bar : IBar
{
string Thingo { get; set; }
}
// Client Proxy reference IBar interface only but redefine concrete class Bar.
public class Bar : IBar
{
public string Thingo
{
get { return _thingo; }
set { _thingo = value; }
}
string _thingo;
}
/// Sample channel factory implementation
using System;
using System.Configuration;
using System.ServiceModel;
using System.ServiceModel.Channels;
public abstract partial class ServiceProxyBase<TServiceContract> : IServiceProxy
where TServiceContract : class
{
protected ServiceProxyBase()
: this(null, null)
{
}
protected ServiceProxyBase(string url, Binding binding)
{
var contractName = typeof(TServiceContract).Name;
var urlConfiguration = string.Format("{0}_Url", contractName);
var serviceUrl = url ?? ConfigurationManager.AppSettings.ValueOrDefault (urlConfiguration, string.Empty, true);
if (serviceUrl.IsNullOrEmptỵ̣())
{
throw new Exception(string.Format("Unable to read configuration '{0}'", urlConfiguration));
}
var serviceBinding = binding ?? new BasicHttpBinding();
Factory = new ChannelFactory<TServiceContract>(serviceBinding);
var serviceUri = new Uri(serviceUrl);
var endPoint = new EndpointAddress(serviceUri);
Channel = Factory.CreateChannel(endPoint);
}
public virtual void Abort()
{
isAborted = true;
}
public virtual void Close()
{
if (Channel != null)
{
((IClientChannel)Channel).Close();
}
if (Factory != null)
{
Factory.Close();
}
}
private ChannelFactory<TServiceContract> Factory { get; set; }
protected TServiceContract Channel { get; set; }
private bool isAborted = false;
}
public class FooServiceProxy : ServiceProxyBase<IFooServiceProxy>, IFooServiceProxy
{
public Task<Bar> DoesStuffAsync()
{
return Channel.DoesStuffAsync();
}
}
[ServiceContract(name="a", namespace="b")] // The trick when redefine service contract
public interface IFooServiceProxy
{
[OperationContract]
Task<Bar> DoesStuffAsync();
}
Webサービスはクロスプラットフォームであると考えてください。返された場合、Javaクライアントはインターフェースで何をしますか?
はい。サービス参照を追加する前に、インターフェースを含むプロジェクトを参照する必要があります。その後、インターフェースは再利用されます。使用されるカスタムクラスについても同様です。サービス参照が追加される前に定義を含むプロジェクトがクライアントプロジェクトによって参照される場合、WCFはそれらの定義を再利用できます。
また、[サービス参照の追加]ダイアログの[詳細設定]タブに移動し、[参照アセンブリのタイプを再利用する]にチェックマークを付ける必要があります。これを機能させるために。
猫の皮を剥ぐ別の方法。 DominicはKnownType属性を使用してそれを実行しました。以下の彼のブログをご覧ください。
http://blogs.msdn.com/b/domgreen/archive/2009/04/13/wcf-using-interfaces-in-method-signatures.aspx