viernes, 15 de febrero de 2008
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.
- Abrir el editor y en el árbol de configuración (a la izquierda), desplegar"Advanced - Extensions"
- 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.
- Seleccionar "Advanced - Endpoint Behavior" en el árbol de configuración y crear ("Add...") un nuevo elemento.
- 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"
- seleccionar "Services - MyProject.WCF.Extensions.InlineXsdInWsdlBehavior - EndPoints - MyEndpoint"
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
lunes, 11 de febrero de 2008
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! :-D ¡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
Etiquetas: Framework .NET, Visual Studio 2008, WCF, Windows Communication Foundation