9 votes

Comment utiliser un proxy WCF personnalisé dans un script Powershell avec un fichier de configuration ?

J'ai un proxy WCF écrit à la main dans sa propre assemblée, c'est très simple :

public class MyServiceClient : ClientBase<IMyService>, IMyService
{
    public MyServiceClient()
    {
    }

    public MyServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }
}

Je charge ceci dans un script Powershell :

Add-Type -Path "$LocalPath\MyService.Client.dll"
Add-Type -Path "$LocalPath\MyService.Contracts.dll"

J'essaie ensuite de définir l'App.config (conformément à l'article 2.2.1). autres postes sur SO) afin que le client puisse être instancié avec un Endpoint défini dans config, plutôt que dans le script lui-même :

[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "$LocalPath\MyService.Client.dll.config")

J'ai vérifié l'AppDomain et le fichier de configuration est défini comme suit ConfigurationFile propriété.

Lorsque je crée une instance du client :

$endpointName = "MyServiceHttpEndpoint" # defined in the app.config file
$myclient = New-Object MyService.Client.MyServiceClient($endpointName)

Il tombe en disant :

Exception calling ".ctor" with "1" argument(s): "Could not find endpoint element with name 'MyServiceHttpEndpoint' and contract 'MyService.Contracts.IMyService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element."

Des idées ? Je ne veux pas créer manuellement le point de terminaison dans le fichier script - il doit être lu depuis la configuration.

1voto

Steve L Points 11

Il semble qu'il y ait une différence dans la manière dont Powershell et Powershell ISE traitent cette question.

Avec ISE (du moins la version que j'utilise), vous devez effacer la configuration pour le forcer à se recharger. Cependant, je suppose que vous pourriez aussi mettre le contenu de votre fichier .dll.config dans la configuration powershell ISE. Cependant, cela semble désagréable. Le code posté ci-dessous fonctionne. J'en ai trouvé des parties en googlant ce problème.

# $dllPath is the path to the dll we want to load
# first point to the correct config file
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "$dllPath.config")

# PowerShell ISE is a PITA we have to override the config
if ($psISE -ne $null) {
    Add-Type -AssemblyName System.Configuration
    [Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null,0)
    [Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null,$null)
    ([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"})[0].GetField("s_current", "NonPublic, Static").SetValue($null, $null)
}

#Now load the DLL
$null = [Reflection.Assembly]::LoadFrom($dllPath)

# DLL and Config should be loaded - test

0voto

JPBlanc Points 26156

Vos assemblages sont-ils construits en tant que cible 32 bits ou 64 bits ?

J'ai rencontré le problème des 32/64 dans plusieurs cas.

Attention, si vous utilisez un système d'exploitation 64 bits, vous avez deux PowerShells, un 64 bits (habituel) et un 32 bits (intéressant lorsque vous avez besoin de 32 assemblages externes).

0voto

David McLean Points 831

Ce serait plus facile si vous postiez votre configuration complète, mais il semble qu'il vous manque la section suivante.

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="ServiceAddress"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding"
        contract="MyService.Contracts.IMyService" name="MyServiceHttpEndpoint" />
    </client>
</system.serviceModel>

Bien que vous ayez l'air sûr que ce n'est pas le cas.

Essayons donc de nous assurer que votre application powershell récupère correctement la configuration...

Pour être sûr que l'application powershell récupère la configuration comme prévu, ajoutez quelque chose comme ceci à votre fichier powershell :

Get-Content $LocalPath\MyService.Client.dll.config | foreach {Write-Output $_}

Si c'est le cas, ce n'est pas un problème de configuration, je pense que nous sommes d'accord sur ce point.

La dll peut-elle voir les paramètres de la configuration ? Nous savons maintenant que powershell peut voir la configuration et appeler votre dll.

La configuration se trouve-t-elle au même endroit que la dll ?

Le type de dépendance fait-il quelque chose que nous n'attendons pas ? En regardant la documentation msdn, on dirait que add-type

Ajoute un Microsoft .NET Framework Windows PowerShell.

Si la classe est maintenant dans une session powershell, a-t-elle accès à la configuration comme elle le ferait normalement ? Je ne sais pas.

Essayez peut-être [Reflection.Assembly]::LoadFrom plutôt et add-type pour voir si cela fait une différence ?

J'ai bien peur de ne pas avoir de réponse précise, mais j'espère que mes divagations vous seront utiles.

0voto

Nirav Points 187

Il semble qu'il vous manque le type de liaison, qui devrait être basicHttpBinding lorsque vous êtes dans powershell.

Faites en sorte que votre code ressemble à :

$endpointName = "MyServiceHttpEndpoint" 
$httpBinding = new-object System.ServiceModel.WSHttpBinding
$myclient = New-Object MyService.Client.MyServiceClient($httpBinding, $endpointName)

0voto

Alex Sarafian Points 324

Je suggère de ne pas utiliser le fichier de configuration si possible. Si votre api fournit un endpoint MEX ou WSDL, essayez de créer vos proxies en les interrogeant et utilisez WsdlImporter pour constituer la configuration de la liaison en mémoire. À partir de ce moment, vous pouvez la modifier en mémoire si nécessaire.

C'est ce que je fais pour le projet sur lequel je travaille qui a un service WCF très lourd en termes de configuration car il est intégré à un service de jeton de sécurité utilisant WS-Trust .

Pour une question J'ai suggéré d'essayer d'utiliser le WcfPS module disponible sur la galerie. Comme il y a un chevauchement avec l'autre question, je vais en citer une partie.

En code pour le module est open source et, bien qu'il soit en script, il dépend fortement des classes et des assemblages .net framework de l'initiative System.ServiceModel y System.IdentityModel assemblages. Je le mentionne parce que la plupart des apis contenues dans ces assemblages ne sont pas disponibles à partir de .NET standard 2, donc le module ne fonctionnera malheureusement pas sur les systèmes d'exploitation non Windows. Vous pouvez également en savoir plus à ce sujet dans mon post WCFPS - Module PowerShell pour travailler avec des points de terminaison SOAP .

Voici l'exemple de la README

#region Initialize the channel/client
$svcEndpoint="http://myserviceprovider/Service1.svc"

$wsImporter=New-WcfWsdlImporter -Endpoint $svcEndpoint -HttpGet
$proxyType=$wsImporter | New-WcfProxyType

# select the endpoint and implicitly the binding from the imported configuration
$endpoint=$wsImporter | New-WcfServiceEndpoint -Endpoint $svcEndpoint
$channel=New-WcfChannel -Endpoint $endpoint -ProxyType $proxyType
#endregion

#region Use the channel/client
$channel.Method1()
$channel.Method2()
#endregion

Avec cette méthode, vous n'avez pas besoin d'importer les types .net en ligne, ni les proxies que vous utilisez sur Visual Studio et aucune configuration. Vous devrez probablement l'adapter à votre cas d'utilisation. Si vous pouvez améliorer la fonctionnalité du module, veuillez soumettre une demande de téléchargement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X