Compartir a través de


Paso 6: Implementar el controlador de resolución de metadatos para el adaptador de Echo

Paso 6 de 9

Tiempo de finalización: 45 minutos

En este paso, implementará la interfaz para resolver la Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler operación y escribir metadatos para el adaptador de eco. Independientemente de la funcionalidad del adaptador, debe implementar esta interfaz. El Asistente para desarrollo de adaptadores genera automáticamente la clase derivada denominada EchoAdapterMetadataResolverHandler automáticamente.

En la sección siguiente, actualizará la clase EchoAdapterMetadataResolverHandler para comprender mejor cómo implementar esta interfaz. Cuando complete este paso, tendrá un controlador de resolución de metadatos de trabajo para el adaptador de eco.

Requisitos previos

Antes de comenzar este paso, debe haber completado correctamente el paso 5: Implementar el controlador de búsqueda de metadatos para el adaptador de eco. También debe comprender las siguientes clases de operación y tipo:

  • Microsoft.ServiceModel.Channels.Common.ParameterizedOperationMetadata

  • Microsoft.ServiceModel.Channels.Common.OperationMetadata

  • Microsoft.ServiceModel.Channels.Common.OperationParameter

  • Microsoft.ServiceModel.Channels.Common.OperationResult

  • Microsoft.ServiceModel.Channels.Common.TypeMetadata

  • Microsoft.ServiceModel.Channels.Common.StructuredTypeMetadata

  • Microsoft.ServiceModel.Channels.Common.TypeMember

  • Microsoft.ServiceModel.Channels.Common.SimpleQualifiedType

  • Microsoft.ServiceModel.Channels.Common.ComplexQualifiedType

Interfaz IMetadataResolverHandler

public interface IMetadataResolverHandler : IConnectionHandler, IDisposable  
  {  
      bool IsOperationMetadataValid(string operationId, DateTime lastUpdatedTimestamp, TimeSpan timeout);        
      bool IsTypeMetadataValid(string typeId, DateTime lastUpdatedTimestamp, TimeSpan timeout);  
      OperationMetadata ResolveOperationMetadata(string operationId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved);  
      TypeMetadata ResolveTypeMetadata(string typeId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved);  
  }  

En la tabla siguiente se describe lo que hace cada método:

Nombre de método Descripción
IsOperationMetadataValid Devuelve un valor true si los metadatos de tipo no han cambiado desde la fecha y hora especificadas.
IsTypeMetadataValid Devuelve un valor booleano que indica si los metadatos de tipo especificados son válidos.
ResolveOperationMetadata Resuelve un identificador de operación en el correspondiente. Microsoft.ServiceModel.Channels.Common.OperationMetadata
ResolveTypeMetadata Resuelve un typeId de metadatos proporcionado en un objeto correspondiente Microsoft.ServiceModel.Channels.Common.TypeMetadata.

Para implementar el método IsOperationMetadataValid

  1. En Explorador de soluciones, haga doble clic en el archivo EchoAdapterMetadataResolverHandler.cs.

  2. En el editor de Visual Studio, haga clic con el botón derecho en cualquier parte del editor, en el menú contextual, seleccione Esquematización y, a continuación, haga clic en Detener esquematización.

  3. En el editor de Visual Studio, busque el método IsOperationMetadataValid , dentro de este método, reemplace el existente por la siguiente instrucción única para indicar que todos los metadatos de la operación especificados son válidos.

    return true;  
    

Para implementar el método IsTypeMetadataValid

  • En el editor de Visual Studio, busque el método IsTypeMetadataValid , dentro de este método, reemplace el existente por la siguiente instrucción única para indicar que todos los metadatos de tipo especificados son válidos.

    return true;  
    

Para implementar el método ResolveOperationMetadata

  1. En el editor de Visual Studio, busque el método ResolveOperationMetadata , dentro de este método, reemplace el existente por el siguiente para resolver la operación OnReceiveEcho, void OnReceiveEcho(Uri path, long fileLength).

    extraTypeMetadataResolved = null;  
    switch( operationId )  
    {  
        case "Echo/OnReceiveEcho":  
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, "OnReceiveEcho");  
            om.OriginalName = "lobNotification";  
            om.Description = "This operation echoes the location and length of a file dropped in the specified file system.";  
            om.OperationGroup = "EchoInboundContract";  
            om.OperationNamespace = EchoAdapter.SERVICENAMESPACE;  
            // syntax: void OnReceiveEcho(Uri path, long fileLength)  
            OperationParameter parmPath = new OperationParameter("path", OperationParameterDirection.In, QualifiedType.UriType, false);  
            parmPath.Description = "Absolute path of the file";  
            OperationParameter parmLength = new OperationParameter("length", OperationParameterDirection.In, QualifiedType.LongType, false);  
            parmLength.Description = "Length of the file received in this location.";  
            om.Parameters.Add(parmPath);  
            om.Parameters.Add(parmLength);  
            om.OperationResult = OperationResult.Empty;  
            return om;  
    
  2. Siga agregando lo siguiente para resolver la operación Echo/EchoStrings, string[] EchoStrings(string data).

    case "Echo/EchoStrings":  
        om = new ParameterizedOperationMetadata(operationId, "EchoStrings");  
        om.OriginalName = "lobEchoStrings";  
        om.Description = "This operation echoes the incoming string COUNT number of times in a string array.";  
        om.OperationGroup = "EchoOutboundContract";  
        om.OperationNamespace = EchoAdapter.SERVICENAMESPACE;  
        // syntax: string[] EchoStrings(string data)  
        OperationParameter parmData = new OperationParameter("data", OperationParameterDirection.In, QualifiedType.StringType, false);  
        parmData.Description = "Input string";  
        om.Parameters.Add(parmData);  
        om.OperationResult = new OperationResult(QualifiedType.StringType, true);  
        return om;  
    
  3. Continúe agregando la siguiente lógica para resolver la operación Echo/EchoStrings, string[] EchoStrings(string data).

    case "Echo/EchoGreetings":  
        om = new ParameterizedOperationMetadata(operationId, "EchoGreetings");  
        om.OriginalName = "lobEchoGreetings";  
        om.Description = "This operation echoes the incoming Greeting object COUNT number of times in an array of type Greeting.";  
        om.OperationGroup = "EchoOutboundContract";  
        om.OperationNamespace = EchoAdapter.SERVICENAMESPACE;  
        // syntax: Greeting[] EchoGreetings(Greeting greeting)  
        ComplexQualifiedType cqtGreeting = new ComplexQualifiedType("Types/GreetingType");  
        OperationParameter parmGreeting = new OperationParameter("greeting", OperationParameterDirection.In, cqtGreeting, false);  
        parmGreeting.Description = "Input greeting";  
        om.Parameters.Add(parmGreeting);  
        om.OperationResult = new OperationResult(cqtGreeting, true);  
        return om;  
    
  4. Siga agregando la siguiente lógica para resolver la operación CustomGreeting EchoCustomGreetingFromFile(Uri greetingInstancePath).

    case "Echo/EchoCustomGreetingFromFile":  
        om = new ParameterizedOperationMetadata(operationId, "EchoCustomGreetingFromFile");  
        om.OriginalName = "lobEchoGreetingUsePredefinedMetadata";  
        om.Description = "This operation echoes the incoming Greeting object COUNT number of times in an array of type Greeting.  The Greeting type metadata is created using predefined XSD file.";  
        om.OperationGroup = "EchoOutboundContract";  
        om.OperationNamespace = EchoAdapter.SERVICENAMESPACE;  
        OperationParameter parmGreetingInstancePath = new OperationParameter("greetingInstancePath", OperationParameterDirection.In, QualifiedType.UriType, false);  
        om.Parameters.Add(parmGreetingInstancePath);  
        ComplexQualifiedType cqtGreetingXsd = new ComplexQualifiedType("Types/CustomGreetingFromXsdType");  
        om.OperationResult = new OperationResult(cqtGreetingXsd, false);  
    
        // resolve extra typemetadata here  
        extraTypeMetadataResolved = new TypeMetadataCollection();  
    
        // use a predefined schema to generate metadata for this type  
        CustomGreetingTypeMetadata tmGreetingXsd = new CustomGreetingTypeMetadata("Types/CustomGreetingFromXsdType", "CustomGreeting");  
        extraTypeMetadataResolved.Add(tmGreetingXsd);                   
        return om;  
    
    
  5. Siga agregando lo siguiente para controlar el caso predeterminado.

        default:  
            throw new AdapterException("Cannot resolve metadata for operation identifier " + operationId);  
    }  
    

Para implementar el método ResolveTypeMetadata

  • En el editor de Visual Studio, busque el método ResolveTypeMetadata , dentro de este método, reemplace el existente por el siguiente para devolver un Microsoft.ServiceModel.Channels.Common.TypeMetadata objeto .

    extraTypeMetadataResolved = null;  
    string typeNamespaceForGreeting = EchoAdapter.SERVICENAMESPACE + "/Types";  
    switch (typeId)  
    {  
        case "Types/GreetingType":  
            StructuredTypeMetadata tmGreeting = new StructuredTypeMetadata(typeId, "Greeting");  
            tmGreeting.TypeNamespace = typeNamespaceForGreeting;  
            tmGreeting.Members.Add(new TypeMember("id", QualifiedType.GuidType, false));  
            tmGreeting.Members.Add(new TypeMember("sentDateTime", QualifiedType.DateTimeType, false));  
            ComplexQualifiedType cqtName = new ComplexQualifiedType("Types/NameType");  
            tmGreeting.Members.Add(new TypeMember("name", cqtName, false));  
            tmGreeting.Members.Add(new TypeMember("greetingText", QualifiedType.StringType, false));  
            return tmGreeting;  
    
        case "Types/NameType":  
            StructuredTypeMetadata tmName = new StructuredTypeMetadata(typeId, "Name");  
            tmName.TypeNamespace = typeNamespaceForGreeting;  
            ComplexQualifiedType cqtSalutation = new ComplexQualifiedType("Types/SalutationType");  
            tmName.Members.Add(new TypeMember("salutation", cqtSalutation, false));  
            tmName.Members.Add(new TypeMember("firstName", QualifiedType.StringType, false));  
            tmName.Members.Add(new TypeMember("middleName", QualifiedType.StringType, false));  
            tmName.Members.Add(new TypeMember("lastName", QualifiedType.StringType, false));  
            return tmName;  
    
        case "Types/SalutationType":  
            EnumTypeMetadata tmSalutation = new EnumTypeMetadata(typeId, "Salutation", new string[] { "Mr.", "Mrs.", "Dr.", "Ms.", "Miss" });  
            tmSalutation.TypeNamespace = typeNamespaceForGreeting;  
            return tmSalutation;  
    
        default:  
            throw new AdapterException("Cannot resolve metadata for type identifier " + typeId);  
    }  
    
    

Para definir la clase de metadatos de tipo de saludo personalizado

  1. En Explorador de soluciones, haga clic con el botón derecho en el proyecto Adaptador de eco, seleccione Agregar y, a continuación, haga clic en Nuevo elemento.

  2. En el cuadro de diálogo Agregar nuevo elemento , en Plantillas, haga clic en Clase.

  3. En el cuadro de texto Nombre , escriba CustomGreetingTypeMetadata.

  4. Haga clic en Agregar.

  5. En el editor de Visual Studio, reemplace el código existente por lo siguiente:

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
    using Microsoft.ServiceModel.Channels.Common;  
    using System.Xml;  
    using System.Xml.Schema;  
    using System.IO;  
    
    namespace Microsoft.Adapters.Samples.EchoV2  
    {  
        public class CustomGreetingTypeMetadata : TypeMetadata  
        {  
            private const string CONST_METADATA_FILE_NAME = "Microsoft.Adapters.Samples.EchoV2.CustomGreeting.xsd";  
    
            public CustomGreetingTypeMetadata(string typeId, string typeName)  
                : base(typeId, typeName)  
            {  
                this.TypeNamespace = EchoAdapter.SERVICENAMESPACE + "/PreDefinedTypes";  
                this.Description = " ";  
                this.CanUseCommonCache = true;  
                // if the nillable is not set to true, the generated proxy wraps the operation  
                // with request and response objects  
                this.IsNillable = true;  
            }  
    
            /// <summary>  
            /// Override the base ExportXmlSchema to provide own   
            /// custom XML Schema  
            /// </summary>  
            /// <param name="schemaExportContext"></param>  
            /// <param name="metadataLookup"></param>  
            /// <param name="timeout"></param>  
            public override void ExportXmlSchema(XmlSchemaExportContext schemaExportContext, MetadataLookup metadataLookup, TimeSpan timeout)  
            {  
                if (schemaExportContext == null)  
                {  
                    throw new AdapterException("Schema export context is null.");  
                }  
                // Read in XML Schema file or create XmlSchema object yourself  
                Stream predefinedXsdFile = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(CONST_METADATA_FILE_NAME);  
                XmlReader reader = XmlReader.Create(predefinedXsdFile);  
                XmlSchema schema = XmlSchema.Read(reader, null);  
                if (!IsComplexTypeAlreadyDefined(schemaExportContext.SchemaSet, schema))  
                {  
                    schemaExportContext.SchemaSet.Add(schema);  
                    if (!schemaExportContext.NamespacePrefixSet.ContainsKey(this.TypeNamespace))  
                    {  
                        schemaExportContext.NamespacePrefixSet.Add(this.TypeNamespace, getUniqueNamespacePrefix(schemaExportContext, 0));  
                    }  
                }  
                reader.Close();  
            }  
    
            /// <summary>  
            /// A default value cannot be set for this type metadata.  
            /// </summary>  
            public override bool CanSetDefaultValue  
            {  
                get { return false; }  
            }  
    
            /// <summary>  
            /// Helper function to see if the schema is already defined in the   
            /// XmlSchemaSet.  
            /// </summary>  
            /// <param name="oldschemaset"></param>  
            /// <param name="newschema"></param>  
            /// <returns></returns>  
            public static bool IsComplexTypeAlreadyDefined(XmlSchemaSet oldschemaset, XmlSchema newschema)  
            {  
                // ensure correct namespace was defined in the passed-in schema  
                foreach (XmlSchema schema in oldschemaset.Schemas(newschema.TargetNamespace))  
                {  
                    foreach (XmlSchemaObject newschemaObject in newschema.Items)  
                    {  
                        if (newschemaObject is XmlSchemaComplexType)  
                        {  
                            //check for the definition of complex type in the schemaset             
                            foreach (XmlSchemaObject schemaObject in schema.Items)  
                            {  
                                XmlSchemaComplexType complexType = schemaObject as XmlSchemaComplexType;  
                                // Definition of this Complex Type already exists  
                                if (complexType != null && String.Compare(complexType.Name, ((XmlSchemaComplexType)newschemaObject).Name, false, System.Globalization.CultureInfo.InvariantCulture) == 0)  
                                    return true;  
                            }  
                        }  
                    }  
                }  
                return false;  
            }  
    
            /// <summary>  
            /// Helper function to generate a unique namespace prefix  
            /// </summary>  
            /// <param name="schemaExportContext"></param>  
            /// <param name="startSuffix"></param>  
            /// <returns></returns>  
            private string getUniqueNamespacePrefix(XmlSchemaExportContext schemaExportContext, int startSuffix)  
            {  
                string defaultPrefix = "ns";  
                string val = defaultPrefix + startSuffix;  
                if (schemaExportContext.NamespacePrefixSet.ContainsValue(val))  
                {  
                    return getUniqueNamespacePrefix(schemaExportContext, ++startSuffix);  
                }  
                else  
                {  
                    return val;  
                }  
            }  
        }  
    }  
    
  6. En Visual Studio, en el menú Archivo , haga clic en Guardar todo.

Para crear la definición de esquema XML de saludo personalizado

  1. En Explorador de soluciones, haga clic con el botón derecho en el proyecto Adaptador de eco, seleccione Agregar y, a continuación, haga clic en Nuevo elemento.

  2. En el cuadro de diálogo Agregar nuevo elemento , en Plantillas, haga clic en Esquema XML.

  3. En el cuadro de texto Nombre , escriba CustomGreeting.

  4. Haga clic en Agregar.

  5. En Explorador de soluciones, haga clic con el botón derecho en el archivo CustomGreeting.xsd y elija Ver código.

  6. En el editor de Visual Studio, comience reemplazando el código existente por el código siguiente que comienza la definición del esquema CustomGreeting:

    <?xml version="1.0" encoding="utf-8" ?>   
    <xs:schema id="XMLSchema1"   
                      targetNamespace="http://tempuri.org/XMLSchema1.xsd"  
                      elementFormDefault="qualified"  
                      xmlns="http://tempuri.org/XMLSchema1.xsd"  
                      xmlns:mstns="http://tempuri.org/XMLSchema1.xsd"  
                      xmlns:xs="http://www.w3.org/2001/XMLSchema">  
    </xs:schema>  
    

    con el código siguiente que comienza la definición del esquema CustomGreeting:

    <?xml version="1.0" encoding="utf-16"?>  
    <xsd:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="echov2://microsoft.adapters.samples.echov2/PreDefinedTypes" elementFormDefault="qualified" targetNamespace="echov2://microsoft.adapters.samples.echov2/PreDefinedTypes" xmlns:xsd ="http://www.w3.org/2001/XMLSchema">  
    
  7. Agregue lo siguiente para definir el elemento CustomGreeting:

    <xsd:element name="greeting" type="CustomGreeting" />  
    
  8. Ahora agregue la definición del tipo complejo CustomGreeting:

    <xsd:complexType name="CustomGreeting">  
      <xsd:sequence>  
        <xsd:element name="address" type="UsAddress" />  
        <xsd:element name="greetingText" type="xsd:string" />  
      </xsd:sequence>  
    </xsd:complexType>  
    
  9. Continúe con la definición del esquema CustomGreeting agregando el tipo complejo UsAddress:

    <xsd:complexType name="UsAddress">  
      <xsd:sequence>  
        <xsd:element minOccurs="1" maxOccurs="1" name="street1" nillable="true" type="xsd:string" />  
        <xsd:element minOccurs="0" maxOccurs="1" name="street2" type="xsd:string" />  
        <xsd:element minOccurs="1" maxOccurs="1" name="city" type="xsd:string" />  
        <xsd:element minOccurs="1" maxOccurs="1" name="state" type="xsd:string" />  
        <xsd:element name="zip" type="PostalCode" />  
      </xsd:sequence>  
    </xsd:complexType>  
    
  10. Complete la definición del esquema CustomGreeting agregando el tipo simple PostalCode y la etiqueta de cierre para el esquema:

      <xsd:simpleType name="PostalCode">  
        <xsd:restriction base="xsd:positiveInteger">  
          <xsd:pattern value="\d{5}" />  
        </xsd:restriction>  
      </xsd:simpleType>  
    </xsd:schema>  
    
  11. Ahora, actualice la acción de compilación de este archivo para que se trate como un recurso incrustado. Para ello, en el panel de la solución de Visual Studio, haga clic con el botón derecho en el archivo y elija Propiedades. Cambie Acción de compilación de Ninguno a Recurso incrustado.

  12. En Visual Studio, en el menú Archivo , haga clic en Guardar todo.

Nota

Ya ha guardado su trabajo. Puede cerrar Visual Studio de forma segura en este momento o ir al paso siguiente, Paso 7: Implementar el controlador de salida sincrónico para el adaptador de eco.

¿Qué hice?

Acaba de implementar la funcionalidad de resolución de metadatos para el adaptador de eco.

Pasos siguientes

En el paso siguiente, implementará el controlador de salida sincrónico para el adaptador de eco. A continuación, implemente el controlador de entrada sincrónico y, a continuación, compile e implemente el adaptador de eco.

Consulte también

Paso 5: Implementar el controlador de búsqueda de metadatos para el adaptador de Echo
Paso 7: Implementar el controlador de salida sincrónico para el adaptador de Echo
Tutorial 1: Desarrollar el adaptador de Echo