Search code examples
c#sap-dotnet-connector

C# SAP .net connector not returning the same data as seen in SAP GUI


I have followed the code shown on this site: "https://www.veonconsulting.com/integrating-sap-using-nco/",

I'm trying to get data from the function BAPI_PRODORD_GET_DETAIL, I tested <bapi_prodord_get_detail><number>1000262</number><struct><order_objects><header>X</header><operations>X</operations><components>X</components></order_objects></struct></bapi_prodord_get_detail>, on SAP GUI, I can see data for Header, Components & Operations, but in the code, I 'm not getting the same response, could you please help.

Code:

public bool testConnection()
{
  bool state = false;
  string rfcRequest = "<RFC_READ_TABLE><QUERY_TABLE>MARD</QUERY_TABLE><DELIMITER>*"
    + "</DELIMITER><ROWSKIPS>0</ROWSKIPS><ROWCOUNT>0</ROWCOUNT><TABLE><OPTIONS><ROW>"
    + "<TEXT>MATNR IN (</TEXT></ROW><ROW><TEXT>'testConnection'</TEXT></ROW><ROW>"
    + "<TEXT>)</TEXT></ROW></OPTIONS></TABLE></RFC_READ_TABLE>";

  Utils.RfcClient client = new Utils.RfcClient();
  try
  {
    XElement response = client.PullRequestToSAPrfc(rfcRequest);
    state = true;
  }
  catch (RfcLogonException ex)
  {
    Console.Write("Logon Failed");
  }
  catch (RfcInvalidStateException ex)
  {
    Console.Write("RFC Failed");
  }
  catch (RfcBaseException ex)
  {
    Console.WriteLine("communication error" + ex.Message);
  }
  catch (Exception ex)
  {
    Console.Write("Connection error");
  }
  finally
  {
    //client.disconnectDestination();
  }
  return state;
}

public bool testConnection()
{
  bool state = false;
  string rfcRequest = "<bapi_prodord_get_detail><number>1000262</number><struct>"
    + "<order_objects><header>X</header><operations>X</operations><components>X"
    + "</components></order_objects></struct></bapi_prodord_get_detail>";

  Utils.RfcClient client = new Utils.RfcClient();
  try
  {
    XElement response = client.PullRequestToSAPrfc(rfcRequest);
    state = true;
  }
  catch (RfcLogonException ex)
  {
    Console.Write("Logon Failed");
  }
  catch (RfcInvalidStateException ex)
  {
    Console.Write("RFC Failed");
  }
  catch (RfcBaseException ex)
  {
    Console.WriteLine("communication error" + ex.Message);
  }
  catch (Exception ex)
  {
    Console.Write("Connection error");
  }
  finally
  {
    //client.disconnectDestination();
  }
  return state;
}

public XElement PullRequestToSAPrfc(string XMLRequest)
{
  IRfcFunction requestFn;
  requestFn = PrepareRfcFunctionFromXML(XElement.Parse(XMLRequest));

  RfcSessionManager.BeginContext(_ECCsystem);
  requestFn.Invoke(_ECCsystem);
  RfcSessionManager.EndContext(_ECCsystem);

  XElement XMLResponse = PrepareXMLFromrfc(requestFn);

  return XMLResponse;
}

public IRfcFunction PrepareRfcFunctionFromXML(XElement xmlFunction)
{
  RfcRepository repo = _ECCsystem.Repository;
  IRfcFunction RfcFunction = repo.CreateFunction(xmlFunction.Name.ToString());
  foreach (XElement xelement in xmlFunction.Elements())
  {
    if (xelement.Name.ToString().Equals("TABLE"))
    {
      if (NotProcessSpecialTable(xelement))
        continue;
      IRfcTable options = RfcFunction.GetTable(xelement.Descendants().First().Name.ToString());
      foreach (XElement row in xelement.Elements().First().Elements())
      {
        options.Append();
        foreach (XElement rowElement in row.Elements())
        {
          string elementName = rowElement.Name.ToString();
          RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
          var elementValue = getValueAsMetadata(ref elementMeta, rowElement.Value);
          if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
          options.SetValue(elementName, elementValue);
        }
      }
    }
    else if (xelement.Name.ToString().Equals("STRUCT"))
    {
      IRfcStructure options = RfcFunction.GetStructure(xelement.Descendants().First().Name.ToString());
      foreach (XElement structElement in xelement.Elements().First().Elements())
      {
        string elementName = structElement.Name.ToString();
        RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
        var elementValue = getValueAsMetadata(ref elementMeta, structElement.Value);
        if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
        options.SetValue(elementName, elementValue);
      }
    }
    else
    {
      string elementName = xelement.Name.ToString();
      RfcElementMetadata elementMeta = RfcFunction.GetElementMetadata(elementName);
      var elementValue = getValueAsMetadata(ref elementMeta, xelement.Value);
      if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
      RfcFunction.SetValue(elementName, elementValue);
    }
  }
  return RfcFunction;
}

public XElement PrepareXMLFromrfc(IRfcFunction rfcFunction)
{
  var XMLRoot = new XElement(rfcFunction.Metadata.Name);
  for (int functionIndex = 0; functionIndex < rfcFunction.ElementCount; functionIndex++)
  {
    var functionMatadata = rfcFunction.GetElementMetadata(functionIndex);
    if (functionMatadata.DataType == RfcDataType.TABLE)
    {
      var rfcTable = rfcFunction.GetTable(functionMatadata.Name);
      var XMLTable = new XElement(functionMatadata.Name);
      foreach (IRfcStructure rfcStracture in rfcTable)
      {
        XElement XMLRow = new XElement("ROW");
        for (int i = 0; i < rfcStracture.ElementCount; i++)
        {
          RfcElementMetadata rfcElementMetadata = rfcStracture.GetElementMetadata(i);
          if (rfcElementMetadata.DataType == RfcDataType.BCD)
          { XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name))); }
          else
          {
            XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name)));
          }
        }

        XMLTable.Add(XMLRow);
      }
      XMLRoot.Add(XMLTable);
    }
    else if (functionMatadata.DataType == RfcDataType.STRUCTURE)
    {
      var rfcStructure = rfcFunction.GetStructure(functionMatadata.Name);
      XElement XMLRow = new XElement(functionMatadata.Name);
      for (int elementIndex = 0; elementIndex < rfcStructure.ElementCount; elementIndex++)
      {
        RfcElementMetadata eleMeta = rfcStructure.GetElementMetadata(elementIndex);
        XMLRow.Add(new XElement(eleMeta.Name, rfcStructure.GetString(eleMeta.Name)));
      }
      XMLRoot.Add(XMLRow);
    }
    else
    {
      RfcElementMetadata rfcElement = rfcFunction.GetElementMetadata(functionIndex);
      XMLRoot.Add(new XElement(rfcElement.Name, rfcFunction.GetString(rfcElement.Name)));
    }
  }
  return XMLRoot;
}

# Below function is used for the data types.

private object getValueAsMetadata(ref RfcElementMetadata elementMeta, string value)
{
  switch (elementMeta.DataType)
  {
    case RfcDataType.BCD:
      return value;
    case RfcDataType.NUM:
      if (value.Contains("."))
      {
        int elementValue;
        int.TryParse(value, out elementValue);
        return elementValue;
      }
      else
      {
        return Convert.ToInt32(value);
      }
    case RfcDataType.INT1:
      return Convert.ToInt32(value);
    case RfcDataType.INT2:
      return Convert.ToInt32(value);
    case RfcDataType.INT4:
      return Convert.ToInt32(value);
    case RfcDataType.INT8:
      return Convert.ToInt64(value);
    case RfcDataType.CHAR:
      return value;
    case RfcDataType.DATE:
      return DateTime.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);


    default:
      return string.Empty;
  }
}

Solution

  • You are confronted to the classic issue of external and internal values in SAP.

    Your screenshot shows the ABAP Function Module Test screen in SAP system. When you enter a value in the screen, it may be transformed internally before calling the function module.

    These are called the external and internal formats. "External" is what is shown in the User Interface (typed or displayed), "internal" is the value written to the database.

    For instance, imagine a database object whose primary key is a GUID, this is the object key in internal format, but in the user interface this object is always referred or shown by its name (candidate key).

    In your precise case, when a Production Order is a number, the internal format always contains leading zeroes on 12 digits, and the external format does not display them. In the Function Module Test screen, if you enter this external value:

    1000262

    it's converted to the following internal value and the BAPI is called with it:

    000001000262

    Generally speaking, when you call any function module from another program, you must indicate the internal value, because there's no user interface implied between the two.

    i.e., use this XML in your method testConnection:

      string rfcRequest = "<bapi_prodord_get_detail><number>000001000262</number><struct>"
        + "<order_objects><header>X</header><operations>X</operations><components>X"
        + "</components></order_objects></struct></bapi_prodord_get_detail>";
    

    See also this answer about external and internal formats: Converting MATNR via conversion exit fails for custom table