Invocar operaciones en el sistema SAP mediante el modelo de canal WCF
Se invocan operaciones en el adaptador de SAP mediante una forma de canal IRequestChannel o IOutputChannel para enviar mensajes al adaptador. El patrón básico consiste en crear un generador de canales para la forma de canal necesaria mediante un enlace (SAPBinding) y un punto de conexión creado a partir de un URI de conexión. A continuación, se crea una instancia de Message que representa un mensaje SOAP que se ajusta al esquema de mensajes para la operación de destino. A continuación, puede enviar este mensaje al adaptador de SAP mediante un canal creado a partir del generador de canales. Si usa un IRequestChannel, recibirá una respuesta. Si hay un problema al ejecutar la operación en el sistema SAP, el adaptador de SAP produce una excepción Microsoft.ServiceModel.Channels.Common.TargetSystemException.
Para obtener información general sobre cómo enviar operaciones mediante IRequestChannel en WCF, consulte Programación de Channel-Level de cliente.
En las secciones de este tema se proporciona información para ayudarle a invocar operaciones en el adaptador de SAP mediante el modelo de canal WCF.
Admitir transacciones BAPI en el modelo de canal WCF
Todas las BAP que se invocan mediante la misma conexión SAP forman parte de la misma unidad lógica de trabajo (LUW) (o transacción) en el sistema SAP. Cada canal WCF representa una conexión única al sistema SAP. Para admitir transacciones BAPI mediante el modelo de canal WCF:
Asegúrese de que cada BAPI de una LUW (transacción) se envía a través del mismo canal. Esto incluye el BAPI_TRANSACTION COMMIT o las operaciones de BAPI_TRANSACTION_ROLLBACK.
Asegúrese de cerrar cualquier mensaje de respuesta recibido para un BAPI antes de invocar el siguiente BAPI en el canal. (Debe hacerlo para cada operación; pero es especialmente importante para las BAPIs).
Para obtener más información sobre las transacciones de BAPI, consulte Operaciones en BAPIs en SAP.
Streaming de IOC de archivos planos al adaptador de SAP
Use la operación SendIdoc para enviar un IDOC de archivo plano (cadena) al adaptador. Los datos del IDOC se representan como una cadena bajo un único nodo de esta operación. Por este motivo, el adaptador de SAP admite el streaming de valor de nodo en el mensaje de solicitud. Para realizar streaming de nodo-valor, debe crear el mensaje de solicitud para la operación SendIdoc mediante un System.ServiceModel.Channels.BodyWriter capaz de transmitir los datos de IDOC. Para obtener información sobre cómo hacerlo, consulte Streaming Flat-File IFC en SAP mediante el modelo de canal WCF.
¿Cómo se invoca una operación mediante un canal?
Para invocar una operación mediante un IRequestChannel, realice los pasos siguientes.
Cómo invocar una operación mediante una instancia de IRequestChannel
Cree un generador de canales (ChannelFactory<IRequestChannel>). Para ello, debe especificar un enlace (SAPBinding) y una dirección de punto de conexión. Puede especificar la dirección de enlace y punto de conexión de forma imperativa en el código o mediante declaración en la configuración. Debe establecer las propiedades de enlace necesarias para las operaciones que enviará antes de abrir el generador. Para obtener más información sobre cómo especificar el enlace y la dirección del punto de conexión en la configuración, consulte Creación de un canal mediante SAP.
// Create a binding SAPBinding binding = new SAPBinding(); // Create an endpoint address by using the connection URI EndpointAddress endpointAddress = new EndpointAddress("sap://Client=800;lang=EN@A/YourSAPHost/00"); // Create the channel factory ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(binding, address);
Establezca las credenciales de contraseña de nombre de usuario para el generador de canales mediante la propiedad ClientCredentials .
factory.Credentials.UserName.UserName = "YourUserName"; factory.Credentials.UserName.Password = "YourPassword";
Abra el generador de canales.
factory.Open();
Obtenga un canal del generador y ábralo.
IRequestChannel channel = factory.CreateChannel(); channel.Open();
Cree una instancia de Message para la operación de destino. Asegúrese de que se especifica la acción de mensaje para la operación de destino. En este ejemplo, el cuerpo del mensaje se pasa mediante la creación de un objeto XmlReader a través de una cadena. La operación de destino invoca el SD_RFC_CUSTOMER_GET RFC en un sistema SAP.
string inputXml = "\<SD_RFC_CUSTOMER_GET xmlns="http://Microsoft.LobServices.Sap/2007/03/Rfc/\"> <KUNNR i:nil=\"true\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"> </KUNNR> <NAME1>AB*</NAME1> <CUSTOMER_T> </CUSTOMER_T> </SD_RFC_CUSTOMER_GET>"; //create an XML reader from the input XML XmlReader reader = XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(inputXml))); //create a WCF message from our XML reader Message inputMessge = Message.CreateMessage(MessageVersion.Soap11, "http://Microsoft.LobServices.Sap/2007/03/Rfc/SD_RFC_CUSTOMER_GET", reader);
Invoque el método Request en el canal para enviar el mensaje al adaptador de SAP y recibir la respuesta. Si el sistema SAP encuentra una excepción, el adaptador produce una excepción TargetSystemException. (Otras excepciones son posibles para excepciones que no son de SAP). Puede obtener una descripción del error de SAP desde la propiedad InnerException.Message de TargetSystemException.
try { Message messageOut = channel.Request(messageIn); } catch (Exception ex) { // handle exception }
Procese la respuesta. En este ejemplo, se llama a GetReaderAtBodyContents en el mensaje de respuesta para obtener el cuerpo del mensaje.
XmlReader readerOut = messageOut.GetReaderAtBodyContents();
Cuando haya terminado de procesar el mensaje de respuesta, cierre el lector y el mensaje.
readerOut.Close(); messageOut.Close();
Cuando haya terminado de usar el canal y el generador de canales, ciérralos. Al cerrar el generador, se cerrarán todos los canales creados con él.
channel.Close() factory.Close();
Siga los mismos pasos para enviar un mensaje mediante la forma IOutputChannel , excepto:
En el paso 1 se crea un ChannelFactory<IOutputChannel> .
Llame al método Send en el canal en el paso 6.
channel.Send(messageIn);
.No se devuelve ningún mensaje de respuesta para un IOutputChannel.
Ejemplo
En el ejemplo siguiente se muestra cómo invocar una RFC mediante un canal IRequestChannel . En este ejemplo se invoca el SD_RFC_CUSTOMER_GET RFC para obtener una lista de clientes cuyos nombres comienzan por "AB". El mensaje de respuesta se consume mediante xmlReader y el número de cliente y el nombre de cada cliente devuelto se escribe en la consola.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.ServiceModel;
using Microsoft.Adapters.SAP;
using Microsoft.ServiceModel.Channels;
using System.ServiceModel.Channels;
namespace SapRfcClientCM
{
class Program
{
static void Main(string[] args)
{
//create a binding
SAPBinding binding = new SAPBinding();
//set up an endpoint address.
EndpointAddress endpointAddress = new EndpointAddress("sap://Client=800;lang=EN@A/YourSAPHost/00");
//create a channel factory, capable of sending a request to SAP and receiving a reply (IRequestChannel)
ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(binding, endpointAddress);
// add credentials
factory.Credentials.UserName.UserName = "YourUserName";
factory.Credentials.UserName.Password = "YourPassword";
//open the factory
factory.Open();
//obtain a channel from the factory by specifying the address you want to connect to
IRequestChannel channel = factory.CreateChannel();
//open the channel
channel.Open();
//create an XML message to send to the SAP system
//We are invoking the SD_RFC_CUSTOMER_GET RFC.
//The XML below specifies that we want to search for customers with names starting with "AB"
string inputXml = "<SD_RFC_CUSTOMER_GET xmlns=\"http://Microsoft.LobServices.Sap/2007/03/Rfc/\"> <KUNNR i:nil=\"true\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"> </KUNNR> <NAME1>AB*</NAME1> <CUSTOMER_T> </CUSTOMER_T> </SD_RFC_CUSTOMER_GET>";
//create an XML reader from the input XML
XmlReader readerOut = XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(inputXml)));
//create a WCF message from the XML reader
Message messageOut = Message.CreateMessage(MessageVersion.Default, "http://Microsoft.LobServices.Sap/2007/03/Rfc/SD_RFC_CUSTOMER_GET", readerOut);
//send the message to SAP and obtain a reply
Message messageIn = channel.Request(messageOut);
// Write the KUNNR and NAME1 fields for each returned record to the Console
Console.WriteLine("Results of SD_RFC_CUSTOMER_GET");
Console.WriteLine("KUNNR\t\tNAME1");
XmlReader readerIn = messageIn.GetReaderAtBodyContents();
while (readerIn.Read())
{
if (readerIn.IsStartElement())
{
switch (readerIn.Name)
{
case "RFCCUST":
Console.Write("\n");
break;
case "KUNNR":
readerIn.Read();
Console.Write(readerIn.ReadString() + "\t");
break;
case "NAME1":
readerIn.Read();
Console.Write(readerIn.ReadString() + "\t");
break;
default:
break;
}
}
}
// return the cursor
Console.WriteLine();
// Close the input reader
readerIn.Close();
// Close the input message. You should do this for every message you
// send on the channel
messageIn.Close();
// close the channel when you are done using it.
channel.Close();
//close the factory
//note: closing the factory will close all of its channels.
factory.Close();
}
}
}