Pregunta

Tengo un conjunto de servicios web WCF conectados dinámicamente mediante una aplicación de escritorio.

Mi problema son los ajustes de configuración realmente detallados que WCF requiere para funcionar.Hacer que SSL funcione implica configuraciones personalizadas.Hacer que MTOM o cualquier otra cosa funcione requiere más.¿Quieres compresión?Aquí vamos de nuevo...

WCF es realmente poderoso: puede usar muchas formas diferentes de conectarse, pero todas parecen implicar mucha configuración detallada.Si el host y el cliente no coinciden perfectamente, será difícil descifrar los errores.

Quiero que la aplicación de escritorio sea mucho más fácil de configurar; idealmente, algún tipo de descubrimiento automático.Los usuarios de la aplicación de escritorio deberían poder ingresar la URL y ella hará el resto.

¿Alguien sabe una buena manera de hacer esto?

Sé que Visual Studio puede configurar la configuración por usted, pero quiero que la aplicación de escritorio pueda hacerlo en función de una amplia variedad de configuraciones de servidor diferentes.

Sé que las herramientas de VS se pueden usar externamente, pero busco que los usuarios de las aplicaciones de escritorio no tengan que ser expertos en WCF.Sé que MS hizo esto intencionalmente complicado.

¿Existe alguna forma, mecanismo, biblioteca de terceros o algo que haga posible el descubrimiento automático de la configuración de WCF?

¿Fue útil?

Solución

Toda la información sobre el punto final está disponible en los metadatos de un servicio, puede escribir un cliente que explorará los metadatos del servicio y configurará el cliente.Para ver un ejemplo de código, puede consultar este excelente Explorador mexicano de Juval Lowy.

Otros consejos

Gracias, ese fue un código útil (+1).

Sin embargo, es más que un poco desordenado, tiene algunos errores (verificaciones que distinguen entre mayúsculas y minúsculas y que no deberían serlo, por ejemplo), tiene una gran cantidad de funciones de interfaz de usuario que no necesito y repite mucho código.

Tomé de él el mecanismo de descubrimiento real, lo reescribí y casi lo hago funcionar (se conecta, pero necesita algunos ajustes).

Primero, algunas funciones útiles utilizadas por el método principal:

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

Luego, un método que intenta conectarse de manera diferente y devuelve los puntos finales:

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

Ahora hay otra forma de hacer esto que no estaba disponible cuando hice la pregunta original.Microsoft ahora admite REST para servicios WCF.

  • La desventaja de utilizar REST es que se pierde el WSDL.
  • ¡La ventaja es la configuración mínima y las interfaces de su contrato WCF seguirán funcionando!

Necesitará una nueva referencia para System.ServiceModel.Web

Marque sus operaciones con cualquiera WebInvoke o 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 )

Agregarlos a un sitio es fácil: agregue un .svc archivo:

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

La línea de fábrica le dice a ASP.net cómo activar el punto final: ¡no necesita ninguna configuración del lado del servidor!

Luego construye tu ChannelFactory prácticamente no ha cambiado, excepto que ya no es necesario especificar un punto final (o descubrir uno automáticamente como lo hice en las otras respuestas)

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

Tenga en cuenta que no he especificado ni descubierto la configuración del cliente: ¡no se necesita ninguna configuración local!

Otra gran ventaja es que puede cambiar fácilmente a la serialización JSON, lo que permite que Java, ActionScript, Javascript, Silverlight o cualquier otra cosa que pueda manejar JSON y REST consuman los mismos servicios WCF.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top