WCF – Creación dinámica de una clase proxy a partir de un WSDL

 

No sé si a alguien le puede venir bien este ejemplo, pero seguro que sí, en cualquier caso, aquí está, 😛

Se trata de un proyecto C#  que permite crear “proxys” clientes a partir de un WSDL de forma dinámica.

Es un ejemplo de una calculadora muy sencillo pero que sin embargo y lo más importante es que puede modificarse y adaptase a nuestra necesidad con bastante facilidad.

 

He aquí la referencia para descargarlo y pegarse un poco más con el: http://wcf.netfx3.com/files/folders/development_tools/entry6148.aspx

 

Una vez Más espero haber ayudado un poquito.
Juanlu

Hosteando en IIS un WCF con Http Basic Authentication y Compatibilidad ASP.NET (HttpContext; Session, cookies, cache, etc)

Una vez más, sigo por aquí con VS2008 y con WCF, en esta ocasión trataré de comentar, como hostear en IIS un WCF basado en un binding “Http Basic Authentication” y conseguir hacer uso de nuestra conocida clase HttpContext. Son unos cuantos pasos muy fáciles y básicos, jejeje.. ¡claro, ahora que los conozco!

Los pasos a seguir para conseguir el objetivo de este post son:

  1. Crear un proyecto Web de tipo “WCF Service Application”.

  • La plantilla nos creará un proyecto con un Interfaz (Servicio) y una clase de datos (contrato), además un servicio, lo que es nuestro Web Service que ha de implementar obligatoriamente la Interfaz.
  • Seguidamente modificamos el Web.config del servicio manualmente o con nuestro maravilloso editor (Windows Communication Foundation (WCF) – BUG 1) estableciendo principalmente la configuración tal y como muestro aquí un par de pantallazos:

 

  • A continuación tenemos dos opciones para trabajar con la compatibilidad  ASP NET:
    • Anadir el attributo “AspNetCompatibilityRequirements([AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed)]) al servicio, Service1 tal y como se muestra a continuación. Aprovechamos para establecer el Namespace, :-D, ¡ya sabéis “best practices”! (tempuri.org con WCF).
1 [ServiceBehavior(Namespace="http://elGuerre.loc/Service1/")] 2 [AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed)] 3 public class Service1 : IService1 4 { 5 public string GetData(int value) 6 { 7 return string.Format("You entered: {0}", value); 8 } 9 10 public CompositeType GetDataUsingDataContract(CompositeType composite) 11 { 12 if (composite.BoolValue) 13 { 14 composite.StringValue += "Suffix"; 15 } 16 return composite; 17 }
    • y, añadir la siguiente línea en el web.config.
1 <system.serviceModel> 2 <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> 3 ...

O,

    • Añadir el atributo “AspNetCompatibilityRequirements” ([AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)] y,
    • no incluir la configuración en el web.config.
  • Publicar el servicio (“Publish”).
  • Modificar las propiedades del sitio Web en IIS:
    1. Quitar autenticación anónima
    2. Activar autenticación básica (dejar activa solamente esta casilla).

Ahora tenemos la compatibilidad con ASP.NET  pero con la potencia de WCF, nuestra clase HttpContext (session, cookies, cache, etc) está lista para ser usada.

Si estáis interesados en esto, aquí os dejo unas cuantas referencias:

 

Saludos @3Cantos
Juanlu

WCF – Creando un nuevo Behavior

Continuo con VS2008, con WCF (Windows Communication Foundation), en este caso integrando WCF con JAVA y más concretamente con una aplicación desarrollada en AXIS 1.1.0.xxx, vamos, “una patata” un problema, puesto que es la primera y obsoleta versión, no cumple muchos puntos del estandard WSDL, el principal  es que no permite las cláusulas <import>, es decir, es necesario generar un WSDL “to junto”, en fin, cosas del directo como se suele decir, jeje…

Para conocer como afrontar este inconveniente, os cuento lo que he hecho:

Se trata de crear una extensión para nuestro WCF y en cierta forma dotarlo de una nueva funcionalidad, para ello usaremos los interfaces; IWsdlExportExtension, IEndpointBehavior. Entrando más en detalle, necesitaremos añadir código al evento ExportEndPoint de IWsdlExportExtension tal y como muestro a continuación:

public void ExportEndpoint( WsdlExporter exporter, WsdlEndpointConversionContext context ) { XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas; foreach (WsdlDescription wsdl in exporter.GeneratedWsdlDocuments) { List<XmlSchema> importsList = new List<XmlSchema>(); foreach (XmlSchema schema in wsdl.Types.Schemas) { AddImportedSchemas(schema, schemaSet, importsList); } wsdl.Types.Schemas.Clear(); foreach (XmlSchema schema in importsList) { RemoveXsdImports(schema); wsdl.Types.Schemas.Add(schema); } } } private void AddImportedSchemas( XmlSchema schema, XmlSchemaSet schemaSet, List<XmlSchema> importsList ) { foreach (XmlSchemaImport import in schema.Includes) { ICollection realSchemas = schemaSet.Schemas(import.Namespace); foreach (XmlSchema ixsd in realSchemas) { if (!importsList.Contains(ixsd)) { importsList.Add(ixsd); AddImportedSchemas(ixsd, schemaSet, importsList); } } } } private void RemoveXsdImports(XmlSchema schema) { for (int i = 0; i < schema.Includes.Count; i++) { if (schema.Includes[i] is XmlSchemaImport) schema.Includes.RemoveAt(i--); } }

El resto de métodos a sobrescribir podrán dejarse vacíos.

Adicionalmente y para poder configurar nuestro WCF con la herramienta de configuración (WCF Service Configuration Editor), será necesario:

public class InlineXsdBehaviorSection : BehaviorExtensionElement { protected override object CreateBehavior() { return new InlineXsdInWsdlBehavior(); } public override Type BehaviorType { get { Type t = Type.GetType("MyProject.WCF.Extensions.InlineXsdInWsdlBehavior"); return t; } } }

Finalmente tendremos que incluir esta DLL en el GAC, creando previamente un Strong Key, o bien, incluir la referencia en nuestro proyecto, con “Copy Local = true”. Al menos durante el desarrollo os recomiendo que la incluyais en el GAC, evitará el estar constantemente seleccionando esta dll cada vez que editamos la configuración con el “WCF Service Configuration Editor”, “menuda lata, ¿no?”.

Para poner en marcha nuestro WCF:

  • Configurar el WS de forma normal
  • Cargar la nueva funcionalidad, para ello:
    • Abrir el editor y en el árbol de configuración (a la izquierda), desplegar”Advanced – Extensions”
    • seleccionar “behavior element extensions”.
    • En la ventana de la derecha crear un nuevo elemento, Click en “New…”
    • Buscar y seleccionar nuestra DLL y asignar un nombre.

  • Crear un nuevo “Endpoint Behavior”.
    • Seleccionar “Advanced – Endpoint Behavior” en el árbol de configuración y crear (“Add…”) un nuevo elemento.
    • El el siguiente cuadro de diálogo buscar y seleccionar el nombre dado a nuestra DLL.

  • Por último, asociar la nueva extensión a nuestro EndPoint:
    • seleccionar “Services – MyProject.WCF.Extensions.InlineXsdInWsdlBehavior – EndPoints – MyEndpoint”
    • Asignar el Endpoint beavior a nuestro servicio dando valor la la propiedad  “BehaviorConfiguration”

Si ahora comprobamos el WSDL de nuestro WCF veremos como ya no incluye ninguna clausula “import”.

Esto no es del todo cierto, jejeje… existe un inconveniente/restricción y dependerá de los Namespaces de nuestras clases, es decir, será necesario que todos los Namespaces sean iguales, vamos, que sólo exista un único Namespace.  Para ver como cambiar el namespace,  echad un vistazo a este otro post; “tempuri.org con WCF“.

 

Para mayor detalle y comprensión sobre los behaviors, os sugiero que le echéis un vistazo a un artículo de la MSDN Magazine de Diciembre de 2007:   http://msdn.microsoft.com/msdnmag/issues/07/12/ServiceStation/default.aspx?loc=es

 

Nota: Para el siguiente post contaré sobre “ASP NET Compatibility” y lo que ofrece sobre todo a aquellos que estamos empezando con WCF.

 

Saludos y suerte en vuestras nuevas extensiones
Juanlu

Evitando el namespace "http://tempuri.org" con WCF

Hace unos días me toco quitar el ya conocido http://tempuri.org del WSDL y asignarle un namespace específico, es más, esto es lo recomendado por seguridad y como buena practica, en fin, para conseguirlo bastará con lo siguiente:

  • Especificar el Namespace en el ServiceContract (Interfaces):
[ServiceContract(Namespace = "http://MyProject.Tests")]
  • Especificar el Namespace en cada uno de los tipos/clases de datos o contratos; DataContract
[DataContract(Namespace="http://MyProject.Tests")]
  • Quitar el http://tempuri.org de la definición del WSDL y para ello:

    • Añadir el siguiente atributo  al servicio:

    [ServiceBehavior(Namespace="http://MyProject.Tests")]
  • Modificar/Añadir valor a la propiedad “bindingNamespace” del endpoint del servicio según indico concretamente en la línea 2, si no se tiene en cuenta este punto, el namespace por defecto es es “tempuri.org” y aunque cambiemos el namespace en los tres puntos anteriores, este no cambiará:
1 <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> 2 <endpoint bindingNamespace="http://MyProject.Tests" address="" binding="wsHttpBinding" contract="WcfService1.IService1">

ó, graficamente:

El valor para esta propiedad, aunque puede ser cualquiera, ¡con un poco de sentido común, claro!, sería conveniente que tomara el mismo que el indicado para el “[ServiceBehavior]”.

Este último punto fue el que más tardé en encontrar, ¡y mira que está visible! 😀  ¡si leyera un poco de vez en cuando!, jeje… ¡si es que lo dice claramente al pie de la ventana! De todos modos, es curioso, porque todos los post y artículos que hacen referencia a los namespaces, pasan por alto este último punto.

 

Una ayudita más, un gran logro, :-D.

Saludos
Juanlu