C# SAP .net 连接器未返回与 SAP GUI 中相同的数据
C# SAP .net connector not returning the same data as seen in SAP GUI
我已遵循此网站上显示的代码:“https://www.veonconsulting.com/integrating-sap-using-nco/”,
我正在尝试从函数 BAPI_PRODORD_GET_DETAIL
获取数据,我在 SAP GUI 上测试了 <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>
,我可以看到 Header、组件和操作的数据,但是在代码,我没有得到相同的响应,请你帮忙。
代码:
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;
}
}
您遇到了 SAP 中外部和内部价值的经典问题。
您的屏幕截图显示了 SAP 系统中的 ABAP 功能模块测试屏幕。当您在屏幕中输入一个值时,它可能会在调用功能模块之前在内部进行转换。
这些被称为外部和内部格式。 “外部”是用户界面中显示的内容(键入或显示),“内部”是写入数据库的值。
例如,想象一个数据库对象,它的主键是一个 GUID,这是内部格式的对象键,但在用户界面中,这个对象总是通过它的名字(候选键)来引用或显示。
在您的具体情况下,当生产订单是数字时,内部格式始终包含 12 位数字的前导零,外部格式不显示它们。在 Function Module Test 屏幕中,如果您输入此 external 值:
1000262
它被转换为以下内部值,并用它调用 BAPI:
000001000262
一般来说,当您从另一个程序调用任何功能模块时,您必须指明内部值,因为两者之间没有隐含的用户界面。
即,在您的方法中使用此 XML 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>";
另请参阅有关外部和内部格式的回答:
如果您想以编程方式进行所需的字段转换,这在 Sandra Rossi 的回答中有解释,您可以使用 RFM BAPI_CONVERSION_EXT2INT、BAPI_CONVERSION_EXT2INT1、BAPI_CONVERSION_INT2EXT 和 BAPI_CONVERSION_INT2EXT1 这样做。
但是,每个额外的 RFC 调用当然会对性能产生负面影响。
此外,SAP Note 206068 是一个很好的资源,可以解释您也介入的一些 RFC BAPI 陷阱。
我已遵循此网站上显示的代码:“https://www.veonconsulting.com/integrating-sap-using-nco/”,
我正在尝试从函数 BAPI_PRODORD_GET_DETAIL
获取数据,我在 SAP GUI 上测试了 <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>
,我可以看到 Header、组件和操作的数据,但是在代码,我没有得到相同的响应,请你帮忙。
代码:
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;
}
}
您遇到了 SAP 中外部和内部价值的经典问题。
您的屏幕截图显示了 SAP 系统中的 ABAP 功能模块测试屏幕。当您在屏幕中输入一个值时,它可能会在调用功能模块之前在内部进行转换。
这些被称为外部和内部格式。 “外部”是用户界面中显示的内容(键入或显示),“内部”是写入数据库的值。
例如,想象一个数据库对象,它的主键是一个 GUID,这是内部格式的对象键,但在用户界面中,这个对象总是通过它的名字(候选键)来引用或显示。
在您的具体情况下,当生产订单是数字时,内部格式始终包含 12 位数字的前导零,外部格式不显示它们。在 Function Module Test 屏幕中,如果您输入此 external 值:
1000262
它被转换为以下内部值,并用它调用 BAPI:
000001000262
一般来说,当您从另一个程序调用任何功能模块时,您必须指明内部值,因为两者之间没有隐含的用户界面。
即,在您的方法中使用此 XML 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>";
另请参阅有关外部和内部格式的回答:
如果您想以编程方式进行所需的字段转换,这在 Sandra Rossi 的回答中有解释,您可以使用 RFM BAPI_CONVERSION_EXT2INT、BAPI_CONVERSION_EXT2INT1、BAPI_CONVERSION_INT2EXT 和 BAPI_CONVERSION_INT2EXT1 这样做。 但是,每个额外的 RFC 调用当然会对性能产生负面影响。
此外,SAP Note 206068 是一个很好的资源,可以解释您也介入的一些 RFC BAPI 陷阱。