.net - explained - wcf soap service web config
Hacer que WCF sea más fácil de configurar (3)
Tengo un conjunto de servicios web WCF conectados dinámicamente por una aplicación de escritorio.
Mi problema es la configuración de configuración realmente detallada que WCF requiere para funcionar. Hacer que SSL funcione implica una configuración personalizada. Hacer que MTOM o cualquier otra cosa funcione requiere más. ¿Quieres compresión? Aquí vamos de nuevo...
WCF es realmente poderoso: puedes usar una gran cantidad de formas diferentes de conectarte, pero todas parecen involucrar muchas configuraciones detalladas. Si el host y el cliente no coinciden perfectamente, es difícil descifrar los errores.
Quiero que la aplicación de escritorio sea mucho más fácil de configurar, idealmente un tipo de descubrimiento automático. Los usuarios de la aplicación de escritorio solo deberían poder ingresar la URL y 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 base a una amplia variedad de configuraciones de servidor diferentes.
Sé que las herramientas de VS se pueden usar externamente, pero estoy buscando usuarios de las aplicaciones de escritorio para que no tengan que ser expertos de WCF. Sé que MS hizo esto intencionalmente más complicado.
¿Hay alguna manera, mecanismo, biblioteca de terceros o algo para hacer posible el descubrimiento automático de la configuración de WCF?
Gracias, ese fue un código útil (+1).
Sin embargo, es un poco más que un poco desordenado, tiene algunos errores (por ejemplo, las comprobaciones que distinguen mayúsculas de minúsculas) que tienen una carga de funcionalidad de IU que no necesito y repite una gran cantidad de código.
Tomé de él el mecanismo de descubrimiento real, lo reescribí y casi lo hago funcionar (se conecta, pero necesita un poco de precisión).
Primero algunas funciones util 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 una forma diferente de conectarse 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;
}
Toda la información sobre el punto final está disponible en los metadatos de un servicio, puede escribirle a un cliente qué explorará los metadatos del servicio y configurará el cliente. Para un ejemplo de código, puede buscar en este excelente Mex Explorer de Juval Lowy.
Ahora hay otra manera de hacer esto que no estaba disponible cuando hice la pregunta original. Microsoft ahora es compatible con REST para servicios WCF.
- La desventaja de usar REST es que pierdes el WSDL.
- ¡Lo bueno es la configuración mínima y las interfaces de contrato de WCF seguirán funcionando!
Necesitará una nueva referencia a System.ServiceModel.Web
Marque sus operaciones con 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 )
Agregar estos a un sitio es fácil: agregue un archivo .svc
:
<%@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 configuración del servidor en absoluto!
Luego, la construcción de su ChannelFactory
prácticamente no se modifica, excepto que ya no necesita especificar un punto final (o autodescubrir uno 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 es necesaria una configuración local!
Otra gran ventaja es que puede cambiar fácilmente a la serialización JSON, que permite que los mismos servicios WCF sean consumidos por Java, ActionScript, Javascript, Silverlight o cualquier otra cosa que pueda manejar JSON y REST fácilmente.