2010-09-13 61 views
31

Estoy creando un componente .NET que llamará a un servicio web externo. Utilicé el cuadro de diálogo "Agregar referencia de servicio" para agregar el servicio web a mi componente, que genera el código necesario para consumir el servicio y agrega la configuración al archivo app.config.Consuma un servicio web SOAP sin depender de la aplicación.config

Estoy probando el componente agregando una referencia a su DLL desde una aplicación de consola y llamando al método apropiado que crea una nueva instancia del servicio web: ... = new MyServiceSoapClient(). Sin embargo, cuando hago esto, me sale el siguiente excepción:

InvalidOperationException

no se pudo encontrar el elemento extremo predeterminado que hace referencia a un contrato 'MyServicesSoap' en la sección de configuración del cliente de ServiceModel. Esto podría deberse a que no se encontró ningún archivo de configuración para su aplicación, o porque no se pudo encontrar ningún elemento de punto final que coincida con este contrato en el elemento del cliente.

Esto tiene sentido ya que el app.config no se presenta con la DLL del componente. ¿Cómo puedo llamar al servicio web sin tener que depender de la configuración en la App.Config?

+0

posible duplicado de [InvalidOperationException al crear la instancia del servicio web wcf] (http://stackoverflow.com/questions/24993/invalidoperationexception-while-creating-wcf-web-service-instance) –

+0

En pocas palabras: Esas configuraciones de configuración desde el componente debe copiarse a ConsoleApplication1.exe.config –

+0

@Josh que no funcionará en mi caso. No mencioné esto en mi pregunta, pero esta .NET DLL se llamará desde una aplicación VB6 COM, por lo que el componente .NET que estoy escribiendo tiene que poder llamar al servicio web sin tener que depender de nada de la aplicación consumidora –

Respuesta

65

La configuración en <system.ServiceModel> en el archivo app.config le indicará al componente cómo conectarse al servicio web externo. El xml es simplemente una representación textual de las clases y enumeraciones necesarias para establecer la conexión predeterminada al servicio web.

Por ejemplo, este es el código que se ha generado para el servicio web que añadí:

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

Esto se puede traducir a código de este modo:

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

Por lo general, cuando se utiliza el constructor sin parámetros (es decir, new MyServicesSoapClient()), se usará la configuración en el archivo app.config. Sin embargo, puede eludir el archivo app.config al establecer explícitamente los valores binding y endpoint en el código y pasar esas instancias al constructor.

+1

+1 Genial, gracias por esto. Aunque descubrí que en el enlace solo necesitaba agregar una cantidad mínima de configuraciones. Solo usé los tiempos de espera en los enlaces y todo pasó bien. – Deano

+0

Estaba teniendo problemas con una aplicación VB6 que hace referencia a .NET dll que llamó a un servicio web. El problema surgió del archivo app.config del dll, ya que la lectura de los archivos de configuración de dll no es del todo sencilla, y esto me permitió omitir por completo el archivo de configuración. – RoastBeast

+0

¿Qué pasa con los otros atributos ? –

-1

Si se trata de un servicio WCF (que suena, a partir de los mensajes de error), entonces, en su mayor parte, necesitará algo es la aplicación.config, porque es el app.config que le dice a la resto de WCF que MyServiceSoapClient es un servicio web (con un pequeño cambio en los dos archivos app.config, esto podría convertirse en un servicio de canalización con nombre, sin tener que recompilar el código ....)

Ahora, si realmente quiere hacer esto sin la aplicación.config, entonces tiene que lanzar el generado MyServiceSoapClient(), y escribir el suyo, basado en HttpWebRequest.

0

Ajuste de la configuración Encuadernación y punto final en el código es una manera, pero hay otra manera de utilizar la DLL del consumidor y dejar que la estancia en el archivo de configuración App.config existente.

La razón por la que el InvalidOperationException se produce es porque el archivo DLL no contiene la configuración de configuración. Siempre confía en App.config para proporcionarlo, pero como está utilizando el DLL en otra aplicación de consola, no encuentra la configuración.

Cuando utilizamos el cuadro de diálogo "Agregar referencia de servicio" para agregar el servicio web al componente del cliente y crear una instancia del servicio web, dejamos que Visual Studio maneje la creación del canal de comunicación y cargue la configuración de configuración. podemos crear dicho canal explícitamente a nosotros mismos y luego podemos administrar los ajustes de configuración.

Microsoft ofrece clases para este propósito, ConfigurationChannelFactory<TChannel> Clase es uno. Estados de MSDN:

Proporciona la funcionalidad genérica para crear un elemento de configuración de canal para un tipo específico.

El ConfigurationChannelFactory permite la gestión central de configuración de cliente WCF.

Uso de diálogo "Agregar referencia de servicio" para agregar el servicio web al componente de cliente, ya que necesitamos la instancia de interfaz de canal de servicio.

En primer lugar cambiar el nombre del generada App.config archivo a App.dll.config y en sus propiedades del archivo cambiar el Copiar al Directorio de salida propiedad a Copiar siempre

Crear una clase que tiene un método que devuelve el objeto Canal para acceder al servicio web, como este:

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

Como hemos establecido la propiedad Copiar siempre VS copia la DLL del proyecto, así como la App.dll.config en la carpeta bin. Assembly.GetExecutingAssembly().Location devolver la ubicación de montaje y ConfigurationManager.OpenExeConfiguration

abre el archivo de configuración del cliente especificada como un objeto de configuración.

PluginConfig contiene el archivo de configuración de objetos app.config y ConfigurationChannelFactory<T> lo utiliza para comunicarse con el servicio.

Este método puede ser invocado por los que pasa el objeto de interfaz de canal de servicio como esto:

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

SampleService es el espacio de nombres de mi servicio web. Client contiene la instancia del servicio web.

Si necesita manejar Comunicación dúplex y devoluciones de llamada, entonces puede mirar ConfigurationDuplexChannelFactory<TChannel> Class.

Cuestiones relacionadas