Compartir a través de


Paso 7: Implementar el controlador de salida sincrónico para el adaptador de Echo

Paso 7 de 9

Tiempo de finalización: 30 minutos

En este paso, implementará la funcionalidad de salida sincrónica del adaptador echo. Según el SDK del adaptador de LOB de WCF, para admitir la funcionalidad de salida sincrónica, debe implementar la Microsoft.ServiceModel.Channels.Common.IOutboundHandler interfaz . Para el adaptador echo, el Asistente para desarrollo de adaptadores genera automáticamente una clase derivada denominada EchoAdapterOutboundHandler.

En las secciones siguientes, actualizará la clase EchoAdapterOutboundHandler para comprender mejor cómo implementar Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A, cómo analizar el mensaje de solicitud WCF entrante y cómo generar mensajes de respuesta WCF salientes.

Requisitos previos

Antes de comenzar este paso, debe haber completado correctamente el paso 6: Implementar el controlador de resolución de metadatos para el adaptador de eco. Una familiaridad básica con Microsoft.ServiceModel.Channels.Common.IOutboundHandler también es útil.

La interfaz IOutboundHandler

Microsoft.ServiceModel.Channels.Common.IOutboundHandler se define como:

public interface IOutboundHandler : IConnectionHandler, IDisposable  
{  
    Message Execute(Message message, TimeSpan timeout);  
}  

El Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A método ejecuta el mensaje de solicitud WCF entrante invocando el método correspondiente en el sistema de destino y, a continuación, devuelve un mensaje de respuesta WCF saliente. Las definiciones de sus parámetros se enumeran en la tabla siguiente:

Parámetro Definición
message Mensaje de solicitud WCF entrante.
timeout Intervalo de tiempo en el que se debe completar esta operación. La operación debe producir un System.TimeoutException si se supera el tiempo de espera especificado antes de que se complete la operación.

Si el adaptador realiza un envío unidireccional (no hay ningún mensaje de respuesta esperado por el adaptador), este método debe devolver null. Si el adaptador está realizando una operación bidireccional con Microsoft.ServiceModel.Channels.Common.OperationResult igual a Microsoft.ServiceModel.Channels.Common.OperationResult.Empty%2A, este método devuelve un mensaje de respuesta WCF con un cuerpo vacío. De lo contrario, debe devolver el mensaje de respuesta WCF con un cuerpo que contenga los valores del Microsoft.ServiceModel.Channels.Common.OperationResult objeto . Para construir la cadena de acción de respuesta, use Microsoft.ServiceModel.Channels.Common.OperationMetadata.OutputMessageAction%2A.

Salida sincrónica del adaptador de eco

En función de las operaciones del sistema de destino, hay muchas maneras de implementar el Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A método . Para el adaptador echo, hay tres operaciones de salida y sus identificadores de nodo asignados y nombres para mostrar son:

  • string[] EchoStrings(string data), node ID = Echo/EchoString, display name=EchoString

  • Greeting[] EchoGreetings(Greeting greeting), node ID=Echo/EchoGreetings, display name=EchoGreetings

  • CustomGreeting EchoCustomGreetingFromFile(Uri greetingInstancePath), nodeID=Echo/EchoCustomGreetingFromFile, display name=EchoGreetings

    Para analizar correctamente el mensaje de solicitud WCF entrante y generar el mensaje de respuesta WCF saliente, debe estar familiarizado con los siguientes elementos dentro del mensaje SOAP usado por el SDK del adaptador de LOB de WCF:

    Para el mensaje de solicitud WCF entrante:

  • Acción del mensaje de entrada de WCF = identificador de nodo de la operación

  • Cuerpo del mensaje entrante = El elemento inicial del cuerpo es <el nombre> del parámetro displayname><{data}</parameter name></displayname>

    Para el mensaje de respuesta WCF saliente:

  • Acción del mensaje de salida de WCF = identificador de nodo de la operación + "/response"

  • Cuerpo del mensaje saliente = El elemento inicial del cuerpo es <displayname + "Response",> seguido de <displayname + "Result"> y seguido del <tipo>de datos data</datatype></displayname+"Result></displayname + "Response">

    Por ejemplo, operation string[] EchoStrings(string data), node ID = Echo/EchoStrings y display name= EchoStrings:

    La acción del mensaje de entrada wcF = "Echo/EchoStrings"; y el cuerpo de entrada tiene el siguiente aspecto, ya que el nombre del parámetro es data.

<EchoStrings>  
<data>{data}  
</data>  
</EchoStrings>  

La acción del mensaje de salida de WCF = "Echo/EchoStrings/response"; y el cuerpo de salida tiene el siguiente aspecto, ya que el tipo de datos es string.

<EchoStringsResponse>  
<EchoStringsResult>  
<string>{data}</string>  
</EchoStringsResult>  
</EchoStringsResponse>  

Al analizar el mensaje de solicitud WCF entrante, puede usar para System.Xml.XmlDictionaryReader recuperar contenido dentro del mensaje WCF; al redactar el mensaje de respuesta wcF, puede usar para System.Xml.XmlWriter hacerlo.

Implementación de IOutboundHandler

Implemente el método Execute de Microsoft.ServiceModel.Channels.Common.IOutboundHandler. En primer lugar, obtiene un Microsoft.ServiceModel.Channels.Common.OperationMetadata objeto basado en la acción del mensaje de entrada. A continuación, analiza el mensaje WCF entrante y ejecuta la funcionalidad de eco asociada en función de cada operación. Por último, crea un mensaje de respuesta WCF saliente mediante el formato del cuerpo del mensaje saliente.

Para implementar el método Execute de la clase EchoAdapterOutboundHandler

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

  2. En el editor de Visual Studio, agregue las dos directivas using siguientes al conjunto existente de directivas using.

    using System.Xml;  
    using System.IO;  
    
  3. Dentro del método Execute , reemplace la lógica existente por lo siguiente:

    1. Esta lógica comprueba la operación solicitada.

    2. Obtiene el Microsoft.ServiceModel.Channels.Common.OperationMetadata objeto basado en la acción de mensaje de entrada SOAP.

    3. En función del tipo de acción, analiza el mensaje de solicitud WCF e invoca la operación adecuada.

    // Trace input message  
    EchoAdapterUtilities.Trace.Trace(System.Diagnostics.TraceEventType.Verbose, "http://Microsoft.Adapters.Samples.Sql/TraceCode/InputWcfMessage", "Input WCF Message", this, new MessageTraceRecord(message));  
    // Timeout is not supported in this sample  
    OperationMetadata om = this.MetadataLookup.GetOperationDefinitionFromInputMessageAction(message.Headers.Action, timeout);  
    if (om == null)  
    {  
        throw new AdapterException("Invalid operation metadata for " + message.Headers.Action);  
    }  
    if (timeout.Equals(TimeSpan.Zero))  
    {  
        throw new AdapterException("time out is zero");  
    }  
    
    switch (message.Headers.Action)  
    {  
        case "Echo/EchoStrings":  
            return ExecuteEchoStrings(om as ParameterizedOperationMetadata, message, timeout);  
    
        case "Echo/EchoGreetings":  
            return ExecuteEchoGreetings(om as ParameterizedOperationMetadata, message, timeout);  
    
        case "Echo/EchoCustomGreetingFromFile":  
            return ExecuteEchoCustomGreetingFromFile(om, message, timeout);  
    }  
    return null;              
    
  4. Ahora agregue el método ExecuteEchoStrings para controlar la operación string[] EchoStrings(string data). Esta función auxiliar lee el mensaje de solicitud WCF, comprueba si el elemento URI echoInUpperCase está establecido en true; si es así, convierte la cadena de entrada en mayúsculas tantas veces como indica la variable count. A continuación, genera el mensaje de respuesta WCF en el formato de: EchoStringsResponse><EchoStringResult><string>{data}</string></EchoStringResult></EchoStringsResponse>. <

    private Message ExecuteEchoStrings(ParameterizedOperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // ** Read the WCF request  
        // ** <EchoStrings><name>{text}</name></EchoStrings>  
        XmlDictionaryReader inputReader = message.GetReaderAtBodyContents();  
        while (inputReader.Read())  
        {  
            if ((String.IsNullOrEmpty(inputReader.Prefix) && inputReader.Name.Equals("data"))  
                || inputReader.Name.Equals(inputReader.Prefix + ":" + "data")) break;  
        }  
        inputReader.Read();  
        // if the connection property "echoInUpperCase" is set to true, it echoes the data in upper case  
        bool echoInUpperCase = this.Connection.ConnectionFactory.ConnectionUri.EchoInUpperCase;  
        string inputValue = echoInUpperCase ? inputReader.Value.ToUpper() : inputReader.Value;  
        int arrayCount = this.Connection.ConnectionFactory.Adapter.Count;  
    
        // ** Generate the WCF response  
        // ** <EchoStringsResponse><EchoStringResult>{Name}</EchoStringResult></EchoStringsResponse >  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        if (om.OperationResult.IsArray)  
        {  
            for (int count = 0; count < arrayCount; count++)  
            {  
                replywriter.WriteElementString("string", "http://schemas.microsoft.com/2003/10/Serialization/Arrays", inputValue);  
            }  
        }  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  5. Continúe agregando el método ExecuteEchoGreetings para controlar la operación EchoGreetings. Esta función auxiliar lee el mensaje de solicitud WCF, resuelve la operación y el tipo por los ResolveOperationMetadata métodos y ResolveTypeMetadata de la Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler interfaz y y, a continuación, genera el mensaje de respuesta WCF con el formato de: <EchoGreetingsResponse><EchoGreetingsResult>... Mensaje...</EchoGreetingsResult></EchoGreetingsResponse>.

    private Message ExecuteEchoGreetings(ParameterizedOperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // NOTE this method doesn't return response in upper case based on   
        // connection property echoInUpperCase  
    
        // ** Read the WCF request  
        String inputValue = String.Empty;  
        using (XmlDictionaryReader inputReader = message.GetReaderAtBodyContents())  
        {  
    
            bool foundGreeting = inputReader.ReadToDescendant("greeting");  
            if (foundGreeting)  
            {  
                inputValue = inputReader.ReadInnerXml();  
            }  
        }  
    
        int arrayCount = this.Connection.ConnectionFactory.Adapter.Count;  
    
        // ** Generate the WCF response  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        for(int i = 0; i < arrayCount; i++ )  
        {  
            ComplexQualifiedType cqtResult = om.OperationResult.QualifiedType as ComplexQualifiedType;  
            StructuredTypeMetadata tmResult = MetadataLookup.GetTypeDefinition(cqtResult.TypeId, timeout) as StructuredTypeMetadata;  
            replywriter.WriteStartElement(tmResult.TypeName, tmResult.TypeNamespace);  
            replywriter.WriteRaw(inputValue);  
            replywriter.WriteEndElement();  
        }  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  6. Ahora agregue el método ExecuteEchoCustomGreetingFromFile para controlar la operación EchoCustomGreetingFromFile. Esta función auxiliar lee el mensaje de solicitud WCF, lee el mensaje del archivo especificado y, a continuación, genera el mensaje de respuesta WCF con el formato de: <EchoGreetingsFromFileResponse><EchoGreetingsFromFileResult>... Mensaje...</EchoGreetingsFromFileResult></EchoGreetingsFromFileResponse>.

    private Message ExecuteEchoCustomGreetingFromFile(OperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // NOTE this method doesn't return response in upper case based on   
        // connection property echoInUpperCase  
    
        // ** Read the WCF request  
        Uri path;  
        using (XmlDictionaryReader inputReader = message.GetReaderAtBodyContents())  
        {  
            inputReader.MoveToContent();  
            inputReader.ReadStartElement(om.DisplayName);  
            inputReader.MoveToContent();  
            // The path contains the location of the XML file that contains the instance of Greeting object to read   
            path = new Uri(inputReader.ReadElementContentAsString());  
            inputReader.ReadEndElement();  
        }  
    
        // ** Generate the WCF response  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        // Read the XML file and set it to the reply writer here  
        FileStream stream = new FileStream(path.AbsolutePath, FileMode.Open);  
        XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());  
        xdr.MoveToContent();  
        string rawGreeting = xdr.ReadInnerXml();  
        replywriter.WriteRaw(rawGreeting);  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  7. En Visual Studio, en el menú Archivo , haga clic en Guardar todo.

  8. En el menú Compilar , haga clic en Compilar solución. Debe compilarse sin errores. Si no es así, asegúrese de que ha seguido todos los pasos anteriores. Ahora, puede cerrar Visual Studio de forma segura o continuar con el paso 8: Implementar el controlador de entrada sincrónico para el adaptador de eco.

¿Qué hice?

En este paso, ha aprendido a implementar la funcionalidad de mensajería saliente sincrónica del adaptador echo. Para ello, implementó el Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A método de Microsoft.ServiceModel.Channels.Common.IOutboundHandler. Este método anó el mensaje de solicitud WCF entrante, realizó las acciones necesarias y, a continuación, generó el mensaje de respuesta WCF saliente.

En concreto, para el mensaje de solicitud WCF entrante, usó WCF System.ServiceModel.Channels.Message.Headers.Action%2A para recuperar la acción del mensaje de entrada al comprender aún más la estructura básica del cuerpo del mensaje entrante. Para el mensaje de respuesta WCF saliente, ha usado Microsoft.ServiceModel.Channels.Common.OperationMetadata.OutputMessageAction%2A para recuperar la acción del mensaje de salida mediante la comprensión más detallada de la estructura básica del cuerpo del mensaje saliente. Al analizar y componer mensajes WCF, solía System.Xml.XmlDictionaryReader leer el mensaje de solicitud WCF entrante y usaría System.Xml.XmlWriter para escribir un mensaje de respuesta WCF saliente.

Pasos siguientes

Compile e implemente el adaptador echo.

Consulte también

Paso 6: Implementar el controlador de resolución de metadatos para el adaptador de Echo
Paso 8: Implementar el controlador de entrada sincrónico para el adaptador de Echo