質問
デスクトップ アプリケーションによって動的に接続された一連の WCF Web サービスがあります。
私の問題は、WCF が動作するために必要な非常に詳細な構成設定です。SSL を機能させるにはカスタム設定が必要です。MTOM やその他のものを機能させるには、さらに多くのことが必要です。圧縮したいですか?ああ、またか...
WCF は非常に強力です。さまざまな接続方法を使用できますが、どれも多くの詳細な構成が必要になるようです。ホストとクライアントが完全に一致しない場合、解読が困難なエラーが発生します。
デスクトップ アプリの設定をはるかに簡単にしたいと考えています。理想的には、ある種の自動検出機能です。デスクトップ アプリのユーザーは URL を入力するだけで、残りの作業はデスクトップ アプリが行います。
誰かこれを行う良い方法を知っていますか?
Visual Studio で構成を設定できることはわかっていますが、デスクトップ アプリでもさまざまなサーバー設定に基づいて構成できるようにしたいと考えています。
VS のツールが外部から使用できることは知っていますが、WCF の専門家でなくてもデスクトップ アプリのユーザーを探しています。MS がこれを意図的に複雑にしすぎていることは知っています。
WCF 設定の自動検出を可能にする方法、メカニズム、サードパーティのライブラリなどはありますか?
解決
エンドポイントに関するすべての情報はサービスのメタデータで入手でき、サービスのメタデータを探索してクライアントを構成するクライアントを作成できます。コード例については、この優れたものを調べることができます メキシコ探検家 ジュヴァル・ローウィより。
他のヒント
ありがとう、それは役に立つコードでした (+1)。
ただし、少々面倒で、いくつかのバグがあり (たとえば、大文字と小文字を区別する必要はないチェックなど)、必要のない UI 機能がたくさんあり、多くのコードが繰り返されています。
そこから実際の検出メカニズムを取り出して書き直し、ほぼ動作するようにしました (接続はできますが、多少の調整が必要です)。
まず、main メソッドで使用されるいくつかの util 関数:
/// <summary>If the url doesn't end with a WSDL query string append it</summary>
static string AddWsdlQueryStringIfMissing( string input )
{
return input.EndsWith( "?wsdl", StringComparison.OrdinalIgnoreCase ) ?
input : input + "?wsdl";
}
/// <summary>Imports the meta data from the specified location</summary>
static ServiceEndpointCollection GetEndpoints( BindingElement bindingElement, Uri address, MetadataExchangeClientMode mode )
{
CustomBinding binding = new CustomBinding( bindingElement );
MetadataSet metadata = new MetadataExchangeClient( binding ).GetMetadata( address, mode );
return new WsdlImporter( metadata ).ImportAllEndpoints();
}
次に、別の方法で接続を試み、エンドポイントを返すメソッド:
public static ServiceEndpointCollection Discover( string url )
{
Uri address = new Uri( url );
ServiceEndpointCollection endpoints = null;
if ( string.Equals( address.Scheme, "http", StringComparison.OrdinalIgnoreCase ) )
{
var httpBindingElement = new HttpTransportBindingElement();
//Try the HTTP MEX Endpoint
try { endpoints = GetEndpoints( httpBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
catch { }
//Try over HTTP-GET
if ( endpoints == null )
endpoints = GetEndpoints( httpBindingElement,
new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
}
else if ( string.Equals( address.Scheme, "https", StringComparison.OrdinalIgnoreCase ) )
{
var httpsBindingElement = new HttpsTransportBindingElement();
//Try the HTTPS MEX Endpoint
try { endpoints = GetEndpoints( httpsBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
catch { }
//Try over HTTP-GET
if ( endpoints == null )
endpoints = GetEndpoints( httpsBindingElement,
new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
}
else if ( string.Equals( address.Scheme, "net.tcp", StringComparison.OrdinalIgnoreCase ) )
endpoints = GetEndpoints( new TcpTransportBindingElement(),
address, MetadataExchangeClientMode.MetadataExchange );
else if ( string.Equals( address.Scheme, "net.pipe", StringComparison.OrdinalIgnoreCase ) )
endpoints = GetEndpoints( new NamedPipeTransportBindingElement(),
address, MetadataExchangeClientMode.MetadataExchange );
return endpoints;
}
私が最初の質問をしたときには利用できなかった、これを行う別の方法が現在あります。Microsoft は、WCF サービスの REST をサポートするようになりました。
- REST を使用する場合の欠点は、WSDL が失われることです。
- 利点は、構成が最小限で済み、WCF コントラクト インターフェイスが引き続き機能することです。
新しい参照が必要になります System.ServiceModel.Web
操作に次のいずれかのマークを付けます WebInvoke
または WebGet
//get a user - note that this can be cached by IIS and proxies
[WebGet]
User GetUser(string id )
//post changes to a user
[WebInvoke]
void SaveUser(string id, User changes )
これらをサイトに追加するのは簡単です。 .svc
ファイル:
<%@ServiceHost
Service="MyNamespace.MyServiceImplementationClass"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
ファクトリ ラインは、ASP.net にエンドポイントをアクティブ化する方法を指示します。サーバー側の構成はまったく必要ありません。
次に、 ChannelFactory
エンドポイントを指定する必要がなくなったことを除いて、ほとんど変更されていません(または、他の回答のようにエンドポイントを自動検出します)。
var cf = new WebChannelFactory<IMyContractInterface>();
var binding = new WebHttpBinding();
cf.Endpoint.Binding = binding;
cf.Endpoint.Address = new EndpointAddress(new Uri("mywebsite.com/myservice.svc"));
cf.Endpoint.Behaviors.Add(new WebHttpBehavior());
IMyContractInterface wcfClient = cf.CreateChannel();
var usr = wcfClient.GetUser("demouser");
// and so on...
クライアント構成を指定または検出していないことに注意してください。ローカル構成は必要ありません。
もう 1 つの大きな利点は、JSON シリアル化に簡単に切り替えることができることです。これにより、同じ WCF サービスを、Java、ActionScript、JavaScript、Silverlight、または JSON と REST を簡単に処理できるその他のもので利用できるようになります。