web-dev-qa-db-fra.com

Consommer un SOAP service Web sans s'appuyer sur app.config

Je construis un composant .NET qui appellera un service Web externe. J'ai utilisé la boîte de dialogue "Ajouter une référence de service" pour ajouter le service Web à mon composant, ce qui génère le code nécessaire à l'utilisation du service et ajoute les paramètres au fichier app.config.

Je teste le composant en ajoutant une référence à sa DLL à partir d'une application console et en appelant la méthode appropriée qui crée une nouvelle instance du service Web: ... = new MyServiceSoapClient(). Cependant, lorsque je le fais, j'obtiens l'exception suivante:

InvalidOperationException 

Impossible de trouver l'élément de noeud final par défaut faisant référence au contrat 'MyServicesSoap' dans la section de configuration du client ServiceModel. Cela peut être dû au fait qu'aucun fichier de configuration n'a été trouvé pour votre application ou qu'aucun élément de noeud final correspondant à ce contrat n'a été trouvé dans l'élément client.

Cela a du sens puisque le fichier app.config n’est pas transféré avec la DLL du composant. Comment puis-je appeler le service Web sans avoir à compter sur les paramètres de App.Config?

31
Ben McCormack

Les paramètres définis dans <system.ServiceModel> dans le fichier app.config indiqueront au composant comment se connecter au service Web externe. Le XML est simplement une représentation textuelle des classes et des énumérations nécessaires pour établir la connexion par défaut au service Web.

Par exemple, il s'agit du code généré pour le service Web que j'ai ajouté:

<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>

Cela peut être traduit en code comme suit:

    '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)

Habituellement, lorsque vous utilisez le constructeur sans paramètre (c'est-à-dire new MyServicesSoapClient()), les paramètres du fichier app.config sont utilisés. Toutefois, vous pouvez contourner le fichier app.config en définissant explicitement les valeurs binding et endpoint dans le code et en transmettant ces instances au constructeur.

68
Ben McCormack

Définir la configuration Binding et Endpoint dans le code est un moyen, mais il existe un autre moyen d'utiliser le consommateur DLL et de laisser la configuration dans le fichier App.config existant.

La raison pour laquelle InvalidOperationException mentionné se produit est due au fait que la DLL ne contient pas les paramètres de configuration. Il se fie toujours à App.config pour le fournir, mais comme vous utilisez le DLL dans une autre application de la console, il ne trouve pas les paramètres de configuration.

Lorsque nous utilisons la boîte de dialogue "Ajouter une référence de service" pour ajouter le service Web au composant client et créer une instance du service Web, Visual Studio se charge de la création du canal de communication et charge le paramètre de configuration.Alors, si nous pouvons créer ce canal nous-mêmes explicitement, nous pouvons alors gérer les paramètres de configuration.

Microsoft fournit des classes à cet effet, ConfigurationChannelFactory<TChannel> Class en est une. Les états MSDN:

Fournit la fonctionnalité générique pour créer un élément de configuration de canal pour un type spécifique.

Le ConfigurationChannelFactory permet la gestion centralisée de la configuration du client WCF.

Utilisez la boîte de dialogue "Ajouter une référence de service" pour ajouter le service Web au composant client car nous avons besoin de l'instance de l'interface de canal de service.

Commencez par renommer le fichier App.config fichier en App.dll.config et dans ses propriétés File modifiez leCopier dans le répertoire de sortieproperty en Copier Toujours

Créez une classe qui a une méthode qui renvoie l'objet Channel pour accéder au service Web tel que:

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;
    }
}

Depuis que nous avons défini la propriété Copier toujours, VS copie le projet DLL ainsi que le fichier App.dll.config dans le dossier bin . Assembly.GetExecutingAssembly().Location renvoie l'emplacement et le ConfigurationManager.OpenExeConfiguration de l'Assemblée

Ouvre le fichier de configuration du client spécifié en tant qu’objet de configuration.

PluginConfig contient le fichier de configuration App.Config et ConfigurationChannelFactory<T> l'utilise pour communiquer avec le service.

Cette méthode peut être appelée en passant votre objet d'interface Service Channel comme suit:

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

SampleService est l'espace de noms de mon service Web. Client contient l'instance du service Web.

Si vous devez gérer Communication duplex et rappels, vous pouvez consulter ConfigurationDuplexChannelFactory<TChannel> Classe. 

0
Shrikant Mahapatra