Configuración de WCF sin un archivo de configuración

90

¿Alguien sabe de un buen ejemplo de cómo exponer un servicio WCF mediante programación sin el uso de un archivo de configuración? Sé que el modelo de objetos de servicio es mucho más rico ahora con WCF, así que sé que es posible. Simplemente no he visto un ejemplo de cómo hacerlo. Por el contrario, también me gustaría ver cómo se consume sin un archivo de configuración.

Antes de que alguien pregunte, tengo una necesidad muy específica de hacer esto sin archivos de configuración. Normalmente no recomendaría tal práctica, pero como dije, hay una necesidad muy específica en este caso.

Kilhoffer
fuente
1
¿Por qué no recomendaría tal práctica (exponer el servicio programáticamente sin configuración)?
BornToCode

Respuestas:

115

Consumir un servicio web sin un archivo de configuración es muy simple, como he descubierto. Simplemente necesita crear un objeto de enlace y un objeto de dirección y pasarlos al constructor del proxy del cliente oa una instancia de ChannelFactory genérica. Puede mirar el archivo app.config predeterminado para ver qué configuraciones usar, luego crear un método auxiliar estático en algún lugar que instancia su proxy:

internal static MyServiceSoapClient CreateWebServiceInstance() {
    BasicHttpBinding binding = new BasicHttpBinding();
    // I think most (or all) of these are defaults--I just copied them from app.config:
    binding.SendTimeout = TimeSpan.FromMinutes( 1 );
    binding.OpenTimeout = TimeSpan.FromMinutes( 1 );
    binding.CloseTimeout = TimeSpan.FromMinutes( 1 );
    binding.ReceiveTimeout = TimeSpan.FromMinutes( 10 );
    binding.AllowCookies = false;
    binding.BypassProxyOnLocal = false;
    binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
    binding.MessageEncoding = WSMessageEncoding.Text;
    binding.TextEncoding = System.Text.Encoding.UTF8;
    binding.TransferMode = TransferMode.Buffered;
    binding.UseDefaultWebProxy = true;
    return new MyServiceSoapClient( binding, new EndpointAddress( "http://www.mysite.com/MyService.asmx" ) );
}
devios1
fuente
Personalmente, me gusta este enfoque por ejemplos cuando va a usar el archivo en un asunto diferente, por ejemplo, si ha cifrado su app.config (o archivo de configuración equivalente) y no necesita usar el WCF integrado capacidades de lectura en una conexión
Noah
18
Para el uso de https, agregue binding.Security.Mode = BasicHttpSecurityMode.Transport;
ciscoheat
Esto funcionó bastante bien para mí. La única diferencia para mí es que también configuro ReaderQuotas y la información de seguridad. Hice uso de los consejos de ciscoheat y configuré Security.Transport.Mode en Transport si uso https (para mí, esto no se sabe en el momento de la compilación).
Kirk Liemohn
2
Acabo de verificar que todas las propiedades que se establecen son iguales a las predeterminadas en WCF 4, fwiw. (Pero tenga en cuenta que el valor Security.Modepredeterminado es None.)
ladenedge
19

Si está interesado en eliminar el uso de la sección System.ServiceModel en web.config para el alojamiento IIS, he publicado un ejemplo de cómo hacerlo aquí ( http://bejabbers2.blogspot.com/2010/02/wcf -zero-config-in-net-35-part-ii.html ). Muestro cómo personalizar un ServiceHost para crear tanto metadatos como puntos finales de enlace wshttp. Lo hago de forma general que no requiere codificación adicional. Para aquellos que no están actualizando inmediatamente a .NET 4.0, esto puede ser bastante conveniente.

John Wigger
fuente
John, estoy seguro de que es una gran publicación de blog, pero dado que hay una respuesta aceptada de hace 17 meses, ¿realmente tiene algún propósito tu respuesta?
John Saunders
36
Dado que esta es mi primera respuesta de Stack Overflow, puede que no sea la forma en que normalmente se hacen las cosas. Al estar familiarizado con los libros de Lowy y Bustamante, que son grandes referencias, creo que mi respuesta va mucho más allá de las muestras que ofrecen. Utilizo principalmente Stack Overflow cuando busco en Google, así que leo publicaciones que son más antiguas con frecuencia. Tener respuestas más actualizadas solo ayuda desde mi perspectiva. Busqué en Google esta publicación antes de escribir mi código para evitar reinventar la rueda.
John Wigger
48
Como usuario frecuente de SO, encuentro bastante deseable leer nuevas publicaciones sobre temas antiguos. Me ayuda a hacer mejor mi trabajo, lo que aumenta el valor de este sitio (ya que yo y otros lo visitarán más). En lugar de ser estricto con las reglas, ¿por qué no permitir que las personas discutan para que se puedan descubrir mejores respuestas? ¿No es ese el punto?
7
Parece que John Saunders fue puesto en su lugar con la respuesta a su propia pregunta (ninguna de las cuales ha aceptado como respuesta, debo agregar). Personalmente, no tengo ningún problema con las respuestas tardías a las preguntas y, por lo general, estoy encantado de ver una nueva respuesta a una pregunta que hice, meses o años después. Irónicamente, gané mi propia insignia de Nigromante con mi respuesta aceptada a esta misma pregunta. :)
devios1
3
Tuve el mismo problema y la respuesta aceptada no me ayudó, pero esto sí, ¡hurra por las respuestas tardías! Si no hubiera sido por las respuestas tardías, habría tenido que crear una pregunta duplicada de esto.
Didier A.
15

Aquí, este es un código completo y funcional. Creo que te ayudará mucho. Estaba buscando y nunca encuentro un código completo, por eso traté de poner un código completo y funcional. Buena suerte.

public class ValidatorClass
{
    WSHttpBinding BindingConfig;
    EndpointIdentity DNSIdentity;
    Uri URI;
    ContractDescription ConfDescription;

    public ValidatorClass()
    {  
        // In constructor initializing configuration elements by code
        BindingConfig = ValidatorClass.ConfigBinding();
        DNSIdentity = ValidatorClass.ConfigEndPoint();
        URI = ValidatorClass.ConfigURI();
        ConfDescription = ValidatorClass.ConfigContractDescription();
    }


    public void MainOperation()
    {
         var Address = new EndpointAddress(URI, DNSIdentity);
         var Client = new EvalServiceClient(BindingConfig, Address);
         Client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerTrust;
         Client.Endpoint.Contract = ConfDescription;
         Client.ClientCredentials.UserName.UserName = "companyUserName";
         Client.ClientCredentials.UserName.Password = "companyPassword";
         Client.Open();

         string CatchData = Client.CallServiceMethod();

         Client.Close();
    }



    public static WSHttpBinding ConfigBinding()
    {
        // ----- Programmatic definition of the SomeService Binding -----
        var wsHttpBinding = new WSHttpBinding();

        wsHttpBinding.Name = "BindingName";
        wsHttpBinding.CloseTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.OpenTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.ReceiveTimeout = TimeSpan.FromMinutes(10);
        wsHttpBinding.SendTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.BypassProxyOnLocal = false;
        wsHttpBinding.TransactionFlow = false;
        wsHttpBinding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
        wsHttpBinding.MaxBufferPoolSize = 524288;
        wsHttpBinding.MaxReceivedMessageSize = 65536;
        wsHttpBinding.MessageEncoding = WSMessageEncoding.Text;
        wsHttpBinding.TextEncoding = Encoding.UTF8;
        wsHttpBinding.UseDefaultWebProxy = true;
        wsHttpBinding.AllowCookies = false;

        wsHttpBinding.ReaderQuotas.MaxDepth = 32;
        wsHttpBinding.ReaderQuotas.MaxArrayLength = 16384;
        wsHttpBinding.ReaderQuotas.MaxStringContentLength = 8192;
        wsHttpBinding.ReaderQuotas.MaxBytesPerRead = 4096;
        wsHttpBinding.ReaderQuotas.MaxNameTableCharCount = 16384;

        wsHttpBinding.ReliableSession.Ordered = true;
        wsHttpBinding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);
        wsHttpBinding.ReliableSession.Enabled = false;

        wsHttpBinding.Security.Mode = SecurityMode.Message;
        wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
        wsHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
        wsHttpBinding.Security.Transport.Realm = "";

        wsHttpBinding.Security.Message.NegotiateServiceCredential = true;
        wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
        wsHttpBinding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic256;
        // ----------- End Programmatic definition of the SomeServiceServiceBinding --------------

        return wsHttpBinding;

    }

    public static Uri ConfigURI()
    {
        // ----- Programmatic definition of the Service URI configuration -----
        Uri URI = new Uri("http://localhost:8732/Design_Time_Addresses/TestWcfServiceLibrary/EvalService/");

        return URI;
    }

    public static EndpointIdentity ConfigEndPoint()
    {
        // ----- Programmatic definition of the Service EndPointIdentitiy configuration -----
        EndpointIdentity DNSIdentity = EndpointIdentity.CreateDnsIdentity("tempCert");

        return DNSIdentity;
    }


    public static ContractDescription ConfigContractDescription()
    {
        // ----- Programmatic definition of the Service ContractDescription Binding -----
        ContractDescription Contract = ContractDescription.GetContract(typeof(IEvalService), typeof(EvalServiceClient));

        return Contract;
    }
}
SM Khaled Reza
fuente
¡Muy buen ejemplo! Demuestra casi todos los aspectos de la configuración manual. ¡Bien hecho!
Kilhoffer
5
No entiendo cómo se ajusta EvalServiceClient en este código. Se hace referencia, pero no se define. ¿Por qué el servidor está creando un cliente?
BlueMonkMN
3

Toda la configuración de WCF se puede realizar mediante programación. Entonces es posible crear servidores y clientes sin un archivo de configuración.

Recomiendo el libro "Programación de servicios WCF" de Juval Lowy, que contiene muchos ejemplos de configuración programática.

Paul Lalonde
fuente
2

Es muy fácil de hacer tanto en el lado del cliente como en el del servidor. El libro de Juval Lowy tiene excelentes ejemplos.

En cuanto a su comentario sobre los archivos de configuración, diría que los archivos de configuración son el segundo de los pobres para hacerlo en código. Los archivos de configuración son excelentes cuando controlas todos los clientes que se conectarán a tu servidor y te aseguras de que estén actualizados, y que los usuarios no puedan encontrarlos ni cambiar nada. Encuentro que el modelo de archivo de configuración de WCF es limitante, un poco difícil de diseñar y una pesadilla de mantenimiento. Considerándolo todo, creo que fue una muy mala decisión de MS hacer que los archivos de configuración fueran la forma predeterminada de hacer las cosas.

EDITAR: Una de las cosas que no puede hacer con el archivo de configuración es crear servicios con constructores no predeterminados. Esto conduce a variables estáticas / globales y singletons y otros tipos de sin sentido en WCF.

Steve
fuente
2

Encontré muy interesante la publicación del blog en el siguiente enlace sobre este tema.

Una idea que me gusta es la de poder simplemente pasar una sección XML de enlace o comportamiento o dirección de la configuración al objeto WCF apropiado y dejar que maneje la asignación de las propiedades; actualmente no puede hacer esto.

Al igual que otros en la web, tengo problemas con la necesidad de que mi implementación de WCF use un archivo de configuración diferente al de mi aplicación de alojamiento (que es un servicio de Windows .NET 2.0).

http://salvoz.com/blog/2007/12/09/programmatic-setting-wcf-configuration/

Tono
fuente