Show TOC

Background documentationData Container Classes Locate this document in the navigation structure

 

Data containers are objects into which you can fill your application data (input data in case of RFC client calls, output data in case your program acts as an RFC server) or from which you can read the SAP system’s data (output data in case of RFC client calls, input data in case your program acts as an RFC server).

The most commonly used data containers are structures, tables and function modules, but there are also special data containers for tRFC, qRFC and bgRFC logical units of work (LUWs), which will be discussed in the corresponding sections on tRFC, qRFC and bgRFC.

These classes are defined as interfaces, so that future changes to the internal data will not affect the applications.

You should almost never need to create a data container yourself. Just call the GetStructure()/GetTable() methods of RfcFunction or of the parent container and the .NET Connector creates the appropriate container (using lazy initialization). But for those rare cases where you really need to create one of your own, you can use the Create-APIs on the corresponding Metadata classes.

The abstract base class for all data containers is:

public interface IRfcDataContainer

public IRfcDataContainer Clone()

Creates a deep copy of the given data container (including creating clones for all child data containers contained in the given data container).

public <Type> Get<Type> (uint index)

Converts the value of the specified field into the data type given by <Type> and returns that value.

public <Type> Get<Type> (String name)

Converts the value of the specified field into the data type given by <Type> and returns that value.

public void SetValue(uint index , <Type> value)

Converts the data type given by <Type> into a value for the specified field and assigns the value to that field.

public void SetValue(String name, <Type> value)

Converts the data type given by <Type> into a value for the specified field and assigns the value to that field.

Here <Type> can be any of the standard C# data types char[ ], String, byte[ ], byte, short, int, long, double, decimal or of the .NET Connector types RfcDecF34, IRfcStructure and IRfcTable.

Normally you will never need to create a data container yourself, except for function modules. The other data containers can then be obtained from the function module via RfcDataContainer.GetStructure() or RfcDataContainer.GetTable(). The Create() functions of RfcStructure and RfcTable will be needed only rarely.

public interface IRfcStructure:IRfcDataContainer

public RfcStructureMetadata Metadata

Read-only property containing the metadata describing the fields of this structure.

public IRfcField this[uint index]

This is an alternative API to the Get <Type>()/SetValue() functions for reading/writing the fields of this structure. Whether you use this one or the getters/setters defined in IRfcDataContainer is basically a matter of taste. Developers used to the standard JCo or NetWeaver RFC API will find the getters/setters more intuitive, developers used to ADO .NET programming, will find the IRfcField approach more intuitive. IRfcField is described at the end of section 1.4.

public IRfcField this[String name]

See above.

public interface IRfcTable:IRfcDataContainer

public RfcTableMetadata Metadata

Read-only property containing the metadata describing the fields of this table.

public uint RowCount

The number of rows currently contained in this table.

(Read-only) public uint Capacity

Gives the number of rows that can be written into this table without needing to expand this table’s memory area.

(Read-only) public uint CurrentIndex

Index specifying the current position of the row cursor. Can be incremented in order to loop over the table.

public IRfcStructure CurrentRow

The row currently pointed to by the row cursor.

public IRfcStructure [int index]

The row pointed to by the given index. See above.

public void Append(IRfcStructure row)

Appends the given row to the end of the table and moves the row cursor to this row.

public void Insert(IRfcStructure row)

Inserts the given row at the current index. The existing rows from 0 up to CurrentIndex-1 are left unchanged, the rows from CurrentIndex to RowCount-1 are “moved down” by one position [so that they now occupy the positions CurrentIndex+1 to RowCount] and the new row is then copied into the free position at CurrentIndex. The row cursor now points to the first of the inserted rows, meaning the value of CurrentIndex remains the same.

public void Insert(IRfcStructure row, uint index)

Inserts the given row at the specified index. The rest is as described in Insert(IRfcStructure row). The row cursor now points to the inserted row (which in this case is possibly different from the original CurrentIndex value).

Note Note

In this operation the value index=RowCount is valid. It has the effect that no existing rows are “moved down” and the new row is appended at the end. (Basically the same as Append(row) does.)

End of the note.

public void Append(uint count)

Appends the given number of rows to the end of the table and moves the row cursor to the first of these rows. (If count is 0, this method does nothing.)

public void Insert(uint count)

Inserts the given number of rows at the current index. (If count is 0, this method does nothing.) The existing rows from 0 up to CurrentIndex-1 are left unchanged, the rows from CurrentIndex to RowCount-1 are “moved down” by count (so that they now occupy the positions CurrentIndex+1 to RowCount + count – 1). The row cursor now points to the first of the inserted rows, meaning the value of CurrentIndex remains the same.

public void Insert(uint count, int index)

Inserts the given number of rows at the specified index. The rest is as described in Insert(uint index). The row cursor now points to the first of the inserted rows (which in this case is possibly different from the original CurrentIndex value).

Note Note

In this operation the value index=RowCount is valid! It has the effect that no existing rows are “moved down” and the rows are appended at the end. (Basically the same as Append(uint) does.)

End of the note.

public void Clear()

Removes all rows.

public void Delete()

Deletes the current row. The rows from 0 to CurrentIndex-1 are untouched, row number CurrentIndex is deleted and the rows from CurrentIndex+1 to RowCount-1 are moved up one position so that they now occupy positions CurrentIndex to RowCount-2. The row cursor is left unchanged and RowCount is of course decremented by one.

public void Delete(int index)

Deletes the row given by index. For the rest see Delete(). The row cursor is left unchanged as well.

public interface IRfcFunction:IRfcDataContainer

public RfcFunctionMetadata Metadata

Read-only property containing the metadata describing the parameters/exceptions of this function module.

public void Invoke(RfcDestination destination)

Executes the function module in the given target system.

public IRfcParameter this[uint index]

This is an alternative API to the Get<Type>()/SetValue() functions for reading/writing the parameters of this function. Whether you use this one or the getters/setters defined in IRfcDataContainer is basically a matter of taste. Developers used to the standard JCo or NetWeaver RFC API will find the getters/setters more intuitive, developers used to ADO .NET programming, will find the IRfcParameter approach more intuitive.

public IRfcParameter this[String name]

See above.

public void SetActive(uint index, bool active)

Defines whether the specified parameter is active. This has the following meaning: In an RFC client application, by default all parameters are active in the beginning, except for the optional parameters. Only active importing, changing and tables parameters are sent to the backend during Invoke(), i.e. they are “supplied” to the backend system. And only active exporting, changing or tables parameters are “requested” from the backend, i.e. the backend will return values for them. So the “active” flag controls two things: for parameters that are input to the function module, it determines whether a value for that parameter is transferred to the backend system, and consequently whether the backend system will use this parameter’s default value as defined in SE37. And for parameters that are output of the function module, it controls whether a value for the parameter will be returned to you.

This feature can be used to significantly improve a function modules runtime performance as well as the network time: if a function module has several output tables, for which it potentially selects several thousand lines, but you are interested in only one of them, then you can set the other tables inactive. The function module’s ABAP code can test for this condition via the keyword IS REQUESTED and can then omit a time-consuming algorithm for selecting this unneeded data. And the backend’s RFC runtime can omit the work of serializing and sending that data over the network.

Another use case is: if you know that a default value is defined for this parameter in SE37 and you want to have the backend use that, you can set the parameter to inactive (if it isn’t already). Otherwise the .NET Connector would send the initial value corresponding to this parameter’s data type and the backend system will use that instead of the parameter’s default value!

Note Note

SE37 allows defining default values also for non-optional parameters.

End of the note.

Note Note

Although optional parameters are inactive in the beginning, once you set a value for one via one of the many SetValue() functions, it is automatically activated. (Same for non-optional parameters that have previously been deactivated using SetActive(false).) However, if you call SetActive(false), after you have set a value for that parameter, that value is not sent. Or in other words: the last activation/deactivation wins. RFC server applications will usually not need SetActive().

End of the note.

public void SetActive(String name, bool active)

See above.

public bool IsActive(uint index)

Checks whether a parameter is active. In an RFC server application, by default all parameters are active, which the backend system has supplied or requested. So in your application you can test, which of the input parameters the backend system has supplied (and use default values for the ones that are not supplied) and which of the output parameters the backend system has requested (and omit producing values for the ones that are not requested). RFC client applications will usually not need IsActive().

public bool IsActive(String name)

See above.

public bool ClassExceptionEnabled

Returns or sets whether for this particular function call ABAP class-based exceptions shall be supported. The default is “false”. Commonly used by RFC client applications.

For ABAP objects (as of today used in “class-based exceptions” and in the future possibly used for ABAP Remote Method Invocation (RMI)) the following container is used:

public interface IRfcAbapObject:IRfcDataContainer

public RfcAbapObjectMetadata Metadata

Read-only property containing the metadata describing the attributes of this ABAP object.

public IRfcAttribute [int index]

This is an alternative API to the Get <Type>()/SetValue() functions for reading/writing the attributes of this ABAP object. Whether you use this one or the getters/setters defined in IRfcDataContainer is basically a matter of taste. Developers who are familiar with the standard JCo or NetWeaver RFC API will find the getters/setters more intuitive, developers familiar with ADO .NET programming, will find the IRfcAttribute approach more intuitive. IRfcAttribute is described at the end of section 1.4.

public IRfcAttribute [String name]

See above. The following three classes are helper classes for the alternative way of reading/writing field and parameter values (the ADO .NET way).

public interface IRfcElement

public IRfcElement Clone()

Creates a deep copy of this element.

public <Type> Get <Type>()

Converts the value of this element into the data type given by <Type> and returns that value.

public void SetValue(<Type>, value)

Converts the data type given by <Type> into a value for this element and assigns the value to this element.

Here <Type> can be any of the standard C# data types char[ ], String, byte[ ], byte, short, int, long, double, decimal or of the .NET Connector types RfcDecF34, IRfcStructure and IRfcTable.

For structure/table fields:

public interface IRfcField:IRfcElement

public RfcFieldMetadata Metadata

Read-only property containing the metadata describing this field.

For function module parameters:

public interface IRfcParameter:IRfcElement

public RfcParameterMetadata Metadata

Read-only property containing the metadata describing this parameter.

public bool Active

Alternative way of activating/deactivating a function module parameter.

For ABAP object attributes:

public interface IRfcAttribute:IRfcElement

public RfcAttributeMetadata Metadata

Read-only property containing the metadata describing this attribute. Sample code illustrating the usage of field access in the “JCo way” and in the “ADO .NET way” Let’s suppose a function module we executed returned a table named ADDRESSES and we want to loop over it and print the column STREET. Here is first how this would look like in the JCo way:

Syntax Syntax

RfcFunction function = …;

RfcTable addresses = function.GetTable(“ADDRESSES”); Console.WriteLine(“STREET”);

for (addresses.CurrentIndex = 0;

addresses.CurrentIndex < addresses.RowCount; ++(addresses.CurrentIndex)){ Console.WriteLine(addresses.GetString(“STREET”));

}

End of the source code.

And here is how the coding would look like in the alternative ADO .NET way:

Syntax Syntax

RfcFunction function = …;

RfcTable addresses = function[“ADDRESSES”].GetTable(); Console.WriteLine(“STREET”);

for (int index = 0;

index < addresses.RowCount;

++index){ Console.WriteLine(addresses[index][“STREET”].GetString());

}

End of the source code.