Question

Un ensemble de services Web WCF est connecté de manière dynamique par une application de bureau.

Mon problème est lié aux paramètres de configuration très détaillés nécessaires au fonctionnement de WCF. Faire fonctionner SSL implique des paramètres personnalisés. Obtenir MTOM ou toute autre chose au travail nécessite plus. Vous voulez une compression? Nous y revoilà ...

WCF est vraiment puissant - vous pouvez utiliser une multitude de façons de vous connecter, mais toutes semblent impliquer beaucoup de configurations détaillées. Si l'hôte et le client ne correspondent pas parfaitement, vous aurez du mal à déchiffrer les erreurs.

Je souhaite simplifier la configuration de l'application de bureau, idéalement une sorte de détection automatique. Les utilisateurs de l'application de bureau devraient juste pouvoir entrer l'URL et faire le reste.

Quelqu'un connaît-il un bon moyen de le faire?

Je sais que Visual Studio peut configurer la configuration pour vous, mais je souhaite que l'application de bureau puisse le faire en fonction d'une grande variété de configurations de serveurs.

Je sais que les outils de VS peuvent être utilisés à l'extérieur, mais je recherche des utilisateurs d'applications de bureau qui ne doivent pas nécessairement être des experts de la WCF. Je sais que MS a volontairement compliqué cela.

Existe-t-il un moyen, une bibliothèque tierce ou un mécanisme permettant la découverte automatique des paramètres WCF?

Était-ce utile?

La solution

Toutes les informations sur le noeud final sont disponibles dans les métadonnées d'un service. Vous pouvez écrire un client pour explorer les métadonnées du service et configurer le client. Vous trouverez un exemple de code dans cet excellent Mex Explorer de Juval Lowy.

Autres conseils

Merci, c'était un code utile (+1).

Cependant, il est plus qu'un peu désordonné, il a quelques bugs (des contrôles sensibles à la casse qui ne devraient pas être, par exemple), a une charge de fonctionnalités d'interface utilisateur dont je n'ai pas besoin et répète beaucoup de code.

J'y ai pris le mécanisme de découverte, je l'ai réécrit et je l'ai presque mis en marche (connecte, mais a besoin d'être peaufiné).

Quelques fonctions utilitaires utilisées par la méthode principale:

/// <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();
}

Ensuite, une méthode qui tente de se connecter de différentes manières et renvoie les points de terminaison:

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

Il existe maintenant un autre moyen de le faire qui n’était pas disponible lorsque j’ai posé la question initiale. Microsoft prend désormais en charge REST pour les services WCF.

  • L’inconvénient de l’utilisation de REST est que vous perdez le WSDL.
  • La configuration initiale est minimale et vos interfaces de contrat WCF continueront de fonctionner!

Vous aurez besoin d'une nouvelle référence à System.ServiceModel.Web

.

Marquez vos opérations avec WebInvoke ou 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 )

Il est facile de les ajouter à un site - ajoutez un fichier .svc :

<%@ServiceHost 
   Service="MyNamespace.MyServiceImplementationClass" 
   Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

La ligne d'usine indique à ASP.net comment activer le terminal - vous n'avez besoin d'aucune configuration côté serveur!

La construction de votre ChannelFactory est pratiquement inchangée, à l'exception du fait que vous n'avez plus besoin de spécifier de point de terminaison (ni de découvrir automatiquement celui que j'ai dans les autres réponses)

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

Notez que je n'ai pas spécifié ou découvert la configuration du client - aucune configuration locale n'est requise!

Un autre avantage important est que vous pouvez facilement passer à la sérialisation JSON, qui permet aux mêmes services WCF d'être consommés par Java, ActionScript, Javascript, Silverlight ou toute autre solution permettant de gérer facilement JSON et REST.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top