huysentruitw/SapNwRfc

How to get the Structure Metadata and how we can access table in strucuture.

MaheshBollampally opened this issue · 5 comments

Dear Huysentruitw,

Could you please advise on how to get the structure metadata and how we can access the table in structure.

Thanks and Regards,
Mahesh B

we are moving the dot net framework application to dot net core so we are using your reference to achieve the same. we are able to connect SAP and get the function and its table data successfully but we are not able to get the structure metadata , etc. and we are not finding any references on it. so kindly share on how we can get the structure metadata etc.

I'm not sure what your question is about, can you share some code example of more details?

With the SAP .NET Connector everything was metadata based to query information about types / strutures / functions / etc. See

This library could expose the same information. (A lot of these interop calls are already available in my dynamic work.)

@MaheshBollampally what metadata exactly did you use before?

Proposal

namespace SapNwRfc
{
    public interface ISapConnection : IDisposable
    {
        // DECL_EXP RFC_TYPE_DESC_HANDLE SAP_API RfcGetTypeDesc(RFC_CONNECTION_HANDLE rfcHandle, SAP_UC const * typeName, RFC_ERROR_INFO* errorInfo);
        ISapTypeMetadata GetTypeMetadata(string typeName); 

        // DECL_EXP RFC_FUNCTION_DESC_HANDLE SAP_API RfcGetFunctionDesc(RFC_CONNECTION_HANDLE rfcHandle, SAP_UC const * funcName, RFC_ERROR_INFO* errorInfo);
        ISapFunctionMetadata GetFunctionMetadata(string functionName);
    }
}

namespace SapNwRfc
{
    public interface ISapFunction : IDisposable
    {
        // DECL_EXP RFC_FUNCTION_DESC_HANDLE SAP_API RfcGetFunctionDesc(RFC_CONNECTION_HANDLE rfcHandle, SAP_UC const * funcName, RFC_ERROR_INFO* errorInfo);
        ISapFunctionMetadata GetMetadata();

        // this can be removed
        bool HasParameter(string parameterName); 
    }
}

namespace SapNwRfc
{
    public interface ISapServerFunction : IDisposable
    {
        // DECL_EXP RFC_FUNCTION_DESC_HANDLE SAP_API RfcGetFunctionDesc(RFC_CONNECTION_HANDLE rfcHandle, SAP_UC const * funcName, RFC_ERROR_INFO* errorInfo);
        ISapFunctionMetadata GetMetadata();

        // this can be removed
        bool HasParameter(string parameterName); 
    }
}

namespace SapNwRfc.Metadata
{
    public interface ISapTypeMetadata
    {
        // DECL_EXP RFC_RC SAP_API RfcGetTypeName(RFC_TYPE_DESC_HANDLE typeHandle, RFC_ABAP_NAME bufferForName, RFC_ERROR_INFO* errorInfo);
        string GetTypeName();

        // DECL_EXP RFC_RC SAP_API RfcGetFieldCount(RFC_TYPE_DESC_HANDLE typeHandle, unsigned* count, RFC_ERROR_INFO* errorInfo);
        uint GetFieldCount();

        // DECL_EXP RFC_RC SAP_API RfcGetFieldDescByIndex(RFC_TYPE_DESC_HANDLE typeHandle, unsigned index, RFC_FIELD_DESC* fieldDescr, RFC_ERROR_INFO* errorInfo);
        ISapFieldMetadata GetFieldByIndex(uint index);

        // DECL_EXP RFC_RC SAP_API RfcGetFieldDescByName(RFC_TYPE_DESC_HANDLE typeHandle, SAP_UC const* name, RFC_FIELD_DESC* fieldDescr, RFC_ERROR_INFO* errorInfo);
        ISapFieldMetadata GetFieldByName(string name);

        bool HasField(string name);
    }
}

namespace SapNwRfc.Metadata
{
    public interface ISapFunctionMetadata
    {
        // DECL_EXP RFC_RC SAP_API RfcGetFunctionName(RFC_FUNCTION_DESC_HANDLE funcDesc, RFC_ABAP_NAME bufferForName, RFC_ERROR_INFO* errorInfo);
        string GetName();

        // DECL_EXP RFC_RC SAP_API RfcGetParameterCount(RFC_FUNCTION_DESC_HANDLE funcDesc, unsigned* count, RFC_ERROR_INFO* errorInfo);
        uint GetParameterCount();

        // DECL_EXP RFC_RC SAP_API RfcGetParameterDescByIndex(RFC_FUNCTION_DESC_HANDLE funcDesc, unsigned index, RFC_PARAMETER_DESC* paramDesc, RFC_ERROR_INFO* errorInfo);
        ISapParameterMetadata GetParameterByIndex(uint index);

        // DECL_EXP RFC_RC SAP_API RfcGetParameterDescByName(RFC_FUNCTION_DESC_HANDLE funcDesc, SAP_UC const* name, RFC_PARAMETER_DESC* paramDesc, RFC_ERROR_INFO* errorInfo);
        ISapParameterMetadata GetParameterByName(string name);

        bool HasParameter(string name);
    }
}

namespace SapNwRfc.Metadata
{
    // RFC_FIELD_DESC
    public interface ISapFieldMetadata
    {
        string Name { get; }
        RFCTYPE Type { get; }

        // ... maybe more see below for corresponding C++ struct

        // For RFCTYPE_STRUCTURE / RFCTYPE_TABLE
        ISapTypeMetadata GetTypeMetadata();
    }
}

namespace SapNwRfc.Metadata
{
    // RFC_PARAMETER_DESC
    public interface ISapParameterMetadata
    {
        string Name { get; }
        RFCTYPE Type { get; }
        RFC_DIRECTION Direction { get; }
        string Description { get; }

        // ... maybe more see below for corresponding  C++ struct

        // For RFCTYPE_STRUCTURE / RFCTYPE_TABLE
        ISapTypeMetadata GetTypeMetadata();
    }
}
/** \struct _RFC_FIELD_DESC
 * \ingroup repository
 *
 * Structure for reading (RfcGetFieldDescByIndex() or RfcGetFieldDescByName())
 * or defining (RfcAddTypeField()) the properties of a field in a structure/table.
 */
typedef struct _RFC_FIELD_DESC
{
	RFC_ABAP_NAME	name;		///< Field name, null-terminated string
	RFCTYPE		type;			///< Field data type
    /*SAPUNICODEOK_MIXEDLEN*/
	unsigned	nucLength;		///< Field length in bytes in a 1-byte-per-SAP_CHAR system
    /*SAPUNICODEOK_MIXEDLEN*/
	unsigned	nucOffset;		///< Field offset in bytes in a 1-byte-per-SAP_CHAR system
    /*SAPUNICODEOK_MIXEDLEN*/
	unsigned	ucLength;		///< Field length in bytes in a 2-byte-per-SAP_CHAR system
    /*SAPUNICODEOK_MIXEDLEN*/
	unsigned	ucOffset;		///< Field offset in bytes in a 2-byte-per-SAP_CHAR system
	unsigned    decimals;		///< If the field is of type "packed number" (BCD), this member gives the number of decimals.
	RFC_TYPE_DESC_HANDLE typeDescHandle; ///< Pointer to an RFC_STRUCTURE_DESC structure for the nested sub-type if the type field is RFCTYPE_STRUCTURE or RFCTYPE_TABLE */
	void* extendedDescription;	///< Not used by the NW RFC library. This parameter can be used by applications that want to store additional information in the repository (like F4 help values, e.g.).
}RFC_FIELD_DESC,*P_RFC_FIELD_DESC;

/** \struct _RFC_PARAMETER_DESC
 * \ingroup repository
 *
 * Structure for reading (RfcGetParameterDescByIndex() or RfcGetParameterDescByName())
 * or defining (RfcAddParameter()) the properties of a parameter in a function module.
 */
typedef struct _RFC_PARAMETER_DESC
{
	RFC_ABAP_NAME	name;		///< Parameter name, null-terminated string
	RFCTYPE		type;			///< Parameter data type
	RFC_DIRECTION direction;	///< Specifies whether the parameter is an input, output or bi-directional parameter
	unsigned	nucLength;		///< Parameter length in bytes in a 1-byte-per-SAP_CHAR system
	unsigned	ucLength;		///< Parameter length in bytes in a 2-byte-per-SAP_CHAR system
	unsigned    decimals;		///< Gives the number of decimals in case of a packed number (BCD)
	RFC_TYPE_DESC_HANDLE typeDescHandle;	///< Handle to the structure definition in case this parameter is a structure or table
	RFC_PARAMETER_DEFVALUE defaultValue;	///< Default value as defined in SE37
	RFC_PARAMETER_TEXT parameterText;		///< Description text of the parameter as defined in SE37. Null-terminated string.
	RFC_BYTE     optional;		///< Specifies whether this parameter is defined as optional in SE37. 1 is optional, 0 non-optional
	void* extendedDescription;	///< This field can be used by the application programmer (i.e. you) to store arbitrary extra information.
}RFC_PARAMETER_DESC,*P_RFC_PARAMETER_DESC;

Thank you so much for your help! But i am having queries on the below questions.

I have created Dot Net Core (3.1) Web API application.

I have added the package SapNWRfc (dotnet add package SapNwRfc) through Nuget and downloaded the SAP NetWeaver RFC Library 7.50 SDK C++ binaries and unzip the lib folder and placed in the path as metioned.

SAP NetWeaver RFC Library 7.50 SDK C++ binaries folders and files:-

bin
demo
doc
include
lib

lib folder files:-

libicudata50.a
libicudecnumber.so
libicui18n50.a
libicuu50.a
libsapnwrfc.so
libsapnucum.so

Then i have created the Homecontroller in dot net core web api and able to connect SAP and also able to create function and got the output (fields , table etc) through SapNwRfc successully.

see the below code for your reference.

using Microsoft.AspNetCore.Mvc;
using SapNwRfc;

namespace POCRfcConnectivity.Controllers
{
[ApiController]
[Route("[controller]")]
public class HomeController : Controller
{
[HttpGet]
public OrderListSAPReturnItem Home()
{
string connectionString = "SAPserverdetails";

        var connection = new SapConnection(connectionString);
        connection.Connect();
        var sapFunction = connection.CreateFunction("FUNCTIONName");
        var orderList = sapFunction.Invoke<OrderListSAPReturnItem>(new SAPInputParameter
        {
            CUSTOMER_NUMBER = "xxxxxxxxx",
            ORDER_COUNT = "10"
        });
        return orderList;
    }
    public class OrderListSAPReturnItem
    {
        [SapName("TABLENAME")]
        public OrderListSAPReturn[] ITEMS { get; set; }
    }
    public class OrderListSAPReturn
    {
        [SapName("DOC")]
        public string DOC { get; set; }
        [SapName("PURCH")]
        public string PURCH { get; set; }
        [SapName("SOLDTO")]
        public string SOLD { get; set; }
        [SapName("SHIPTO")]
        public string SHIP { get; set; }
        [SapName("SHIP_LOCATION")]
        public string SHIP_LOCATION { get; set; }
        [SapName("DOC_TYPE")]
        public string DOC_TYPE { get; set; }
        [SapName("DOC_DATE")]
        public string DOC_DATE { get; set; }
        [SapName("ORDER_STATUS")]
        public string ORDER_STATUS { get; set; }
    }
    public class SAPInputParameter
    {
        [SapName("CUSTOMER_NUMBER")]
        public string CUSTOMER_NUMBER { get; set; }
        [SapName("ORDER_COUNT")]
        public string ORDER_COUNT { get; set; }
    }
}

}

I dont find any function is available to get the GetStructureMetadata and CreateStructurefunction in sapnwrfc.
we are using the below GetStructureMetadata function through sapnco in dot net framework to get the structure metadata.

RfcStructureMetadata struct = sapRfcDestination.Repository.GetStructureMetadata("STRUCTURENAME");

we are using the below CreateStructure function through sapnco in dot net framework to createstructure and able to set the input for that structure.

structPartners = struct.CreateStructure();
structPartners.SetValue("Doc", strDocNum);
structPartners.SetValue("LineNum", iLineNum.ToString());

Kindly advise on how to achieve the above functionality (GetStructureMetadata, CreateStructure ) from your dynamic library.

Below are the only functions available in Assembly SapNwRfcDotNet.

#region Assembly SapNwRfcDotNet, Version=1.1.1.0, Culture=neutral, PublicKeyToken=e18ffa244882333d
// C:\Users\mahesh.b09.nuget\packages\sapnwrfc\1.1.1\lib\netstandard2.1\SapNwRfcDotNet.dll
#endregion

using System;
using System.Diagnostics.CodeAnalysis;

namespace SapNwRfc
{
public sealed class SapConnection : ISapConnection, IDisposable
{
[ExcludeFromCodeCoverage]
public SapConnection(SapConnectionParameters parameters);
[ExcludeFromCodeCoverage]
public SapConnection(string connectionString);

    public bool IsValid { get; }

    public void Connect();
    public ISapFunction CreateFunction(string name);
    public void Disconnect();
    public void Dispose();
    public SapConnectionAttributes GetAttributes();
    public bool Ping();
}

}

Kindly let me know in case of any details required for more clarification.

What are you doing with the structPartners? Instead of using CreateStructure you could create a class instead:

public class Partner
{
    [SapName("DOC")]
    public string Doc { get; set; }
    [SapName("LINE_NUM")]
    public string LineNum { get; set; }
}