web-dev-qa-db-ja.com

app.configに依存せずにSOAP Webサービスを使用する

外部Webサービスを呼び出す.NETコンポーネントを構築しています。 「サービス参照の追加」ダイアログを使用してWebサービスをコンポーネントに追加しました。これにより、サービスを使用するために必要なコードが生成され、設定がapp.configファイルに追加されます。

コンソールアプリケーションからDLLへの参照を追加し、Webサービスの新しいインスタンスを作成する適切なメソッド... = new MyServiceSoapClient()を参照して、コンポーネントをテストしています。ただし、 、これを行うと、次の例外が発生します。

InvalidOperationException

ServiceModelクライアント構成セクションでコントラクト「MyServicesSoap」を参照するデフォルトのエンドポイント要素が見つかりませんでした。これは、アプリケーションの構成ファイルが見つからなかったため、またはこのコントラクトに一致するエンドポイント要素がクライアント要素で見つからなかったためです。

App.configはコンポーネントのDLLに引き継がれないため、これは理にかなっています。 App.Configの設定に依存せずにWebサービスを呼び出すにはどうすればよいですか?

32
Ben McCormack

App.configファイルの_<system.ServiceModel>_の設定は、外部Webサービスへの接続方法をコンポーネントに指示します。 xmlは、Webサービスへのデフォルト接続を確立するために必要なクラスと列挙の単なるテキスト表現です。

たとえば、これは、追加したWebサービス用に生成されたコードです。

_<system.serviceModel>
 <bindings>
  <basicHttpBinding>
   <binding name="MyServicesSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
     receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
     bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
     maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
     messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
     useDefaultWebProxy="true">
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
       maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     <security mode="None">
      <transport clientCredentialType="None" proxyCredentialType="None"
        realm="" />
      <message clientCredentialType="UserName" algorithmSuite="Default" />
     </security>
    </binding>
   </basicHttpBinding>
  </bindings>
 <client>
  <endpoint address="http://services.mycompany.com/WebServices/MyServices.asmx"
    binding="basicHttpBinding" bindingConfiguration="MyServicesSoap"
    contract="MyServices.MyServicesSoap" name="MyServicesSoap" />
 </client>
</system.serviceModel>
_

これは次のようなコードに変換できます。

_    'Set up the binding element to match the app.config settings '
    Dim binding = New BasicHttpBinding()
    binding.Name = "MyServicesSoap"
    binding.CloseTimeout = TimeSpan.FromMinutes(1)
    binding.OpenTimeout = TimeSpan.FromMinutes(1)
    binding.ReceiveTimeout = TimeSpan.FromMinutes(10)
    binding.SendTimeout = TimeSpan.FromMinutes(1)
    binding.AllowCookies = False
    binding.BypassProxyOnLocal = False
    binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
    binding.MaxBufferSize = 65536
    binding.MaxBufferPoolSize = 524288
    binding.MessageEncoding = WSMessageEncoding.Text
    binding.TextEncoding = System.Text.Encoding.UTF8
    binding.TransferMode = TransferMode.Buffered
    binding.UseDefaultWebProxy = True

    binding.ReaderQuotas.MaxDepth = 32
    binding.ReaderQuotas.MaxStringContentLength = 8192
    binding.ReaderQuotas.MaxArrayLength = 16384
    binding.ReaderQuotas.MaxBytesPerRead = 4096
    binding.ReaderQuotas.MaxNameTableCharCount = 16384

    binding.Security.Mode = BasicHttpSecurityMode.None
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None
    binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None
    binding.Security.Transport.Realm = ""
    binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName
    binding.Security.Message.AlgorithmSuite = Security.SecurityAlgorithmSuite.Default

    'Define the endpoint address'
    Dim endpointStr = "http://services.mycompany.com/WebServices/MyServices.asmx"
    Dim endpoint = New EndpointAddress(endpointStr)
    'Instantiate the SOAP client using the binding and endpoint'
    'that were defined above'
    Dim client = New MyServicesSoapClient(binding, endpoint)
_

通常、パラメーターなしのコンストラクター(つまり、new MyServicesSoapClient())を使用すると、app.configファイルの設定が使用されます。ただし、コードでbindingおよびendpointの値を明示的に設定し、それらのインスタンスをコンストラクターに渡すことにより、app.configファイルをバイパスできます。

69
Ben McCormack

コードでのBindingおよびEndpoint構成の設定は1つの方法ですが、コンシューマDLLを使用し、既存のApp.configファイルに構成を保持する別の方法。

前述のInvalidOperationExceptionが発生する理由は、DLLに構成設定が含まれていないためです。常に提供するのはApp.configに依存していますが、別のコンソールアプリケーションでDLLを使用している場合、構成設定が見つかりません。

[サービス参照の追加]ダイアログを使用してWebサービスをクライアントコンポーネントに追加し、Webサービスのインスタンスを作成すると、Visual Studioで通信チャネルの作成を処理し、構成設定を読み込むことができます。そのようなチャネルを明示的に作成すると、構成設定を管理できます。

Microsoftは、この目的のクラスを提供します。ConfigurationChannelFactory<TChannel>クラスは1です。 MSDNの状態:

特定のタイプのチャネル構成要素を作成するための汎用機能を提供します。

ConfigurationChannelFactoryを使用すると、WCFクライアント構成を集中管理できます。

[サービス参照の追加]ダイアログを使用して、サービスチャネルインターフェイスインスタンスが必要なため、Webサービスをクライアントコンポーネントに追加します。

まず、生成されたApp.configファイルの名前をApp.dll.configに変更し、そのFileプロパティ出力ディレクトリにコピープロパティを常にコピーに変更

次のようなWebサービスにアクセスするためのChannelオブジェクトを返すメソッドを持つクラスを作成します。

public class ManageService
{
    public static T CreateServiceClient<T>(string configName)
    {
        string _assemblyLocation = Assembly.GetExecutingAssembly().Location;
        var PluginConfig = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
        ConfigurationChannelFactory<T> channelFactory = new ConfigurationChannelFactory<T>(configName, PluginConfig, null);
        var client = channelFactory.CreateChannel();
        return client;
    }
}

プロパティCopy Always VSを設定したため、VSはProject DLLとApp.dll.configをbinフォルダーにコピーします。Assembly.GetExecutingAssembly().Location returnアセンブリの場所とConfigurationManager.OpenExeConfiguration

指定されたクライアント構成ファイルを構成オブジェクトとして開きます。

PluginConfigはApp.Config構成ファイルオブジェクトを保持し、ConfigurationChannelFactory<T>はそれを使用してサービスと通信します。

このメソッドは、次のようにサービスチャネルインターフェイスオブジェクトを渡すことで呼び出すことができます。

Client = ManageService.CreateServiceClient<SampleService.IKeyServiceChannel>("MetadataExchangeTcpBinding_IKeyService"); 

SampleServiceは私のWebサービスの名前空間です。 Clientは、Webサービスのインスタンスを保持します。

二重通信およびコールバックを処理する必要がある場合は、ConfigurationDuplexChannelFactory<TChannel>クラスを確認できます。

0