Paso 7: Implementar el controlador de salida sincrónico para el adaptador de Echo
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
En Explorador de soluciones, haga doble clic en el archivo EchoAdapterOutboundHandler.cs.
En el editor de Visual Studio, agregue las dos directivas using siguientes al conjunto existente de directivas using.
using System.Xml; using System.IO;
Dentro del método Execute , reemplace la lógica existente por lo siguiente:
Esta lógica comprueba la operación solicitada.
Obtiene el
Microsoft.ServiceModel.Channels.Common.OperationMetadata
objeto basado en la acción de mensaje de entrada SOAP.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;
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); }
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 yResolveTypeMetadata
de laMicrosoft.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); }
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); }
En Visual Studio, en el menú Archivo , haga clic en Guardar todo.
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