Skip to Content

Introduction



Business APIs (BAPI) are defined in the Business Object Repository (BOR) as methods of SAP business object types or SAP interface types, and are implemented as function modules
in the ABAP code.
Each BAPI returns status information about its execution in a complex parameter named
Return in its output message.
This parameter reports exception messages or success messages back to the calling program.
BAPIs themselves must not trigger any messages (such as MESSAGE xnnn) in the
ABAP coding. In particular they must not generate terminations or display dialog boxes.
Instead, all messages must be intercepted internally and reported back to the calling program in the Return parameter.
If, in at least one of the entries of Return parameter, the field Type is filled with A (abort) or E (error), a database rollback is
executed in the standard programming model, that is, all tasks performed since the last COMMIT WORK are canceled.

In the past the only way to access a BAPI from .NET was to make RFC calls to the function modules on which the BAPI is based using the
+SAP
Connector for Microsoft .NET+ (NCo). However SAP NCo version 1.x and 2.x will not install inside
Visual Studio 2005. Instead developers have to build components in Visual Studio 2003 and use these in Visual Studio 2005 projects as described in the document

Using SAP Connector for MS .NET (NCO) in Microsoft Visual Studio 2005
.

As an alternative approach to RFC based communication made
available by the SAP connector for Microsoft .NET it is strongly recommended by
SAP to use Web Services as the de-facto standard for interoperability between
software (systems) of heterogeneous implementations. (see

SAP Note 943349
). SAP systems that are based on the SAP NetWeaver Application Server allow for a Web
service based communication since it is possible to create a Web service for every BAPI using the

Web Service Creation Wizard
.

If one of the error conditions mentioned above does occur when calling a BAPI one would like to throw an exception in
the calling .NET program.
If a BAPI is called using the SAP NCo the mechanism of throwing a BAPI specific .NET exception can be activated during design time.
The .NET proxy that is generated by the NCo then contains the .NET coding that performs this task. In contrast to a proxy generated by the NCo a Web service
proxy that is generated from a Web reference does not contain coding that throws
an exception.

In my blog I would therefore like to introduce a set of C#-classes that can be used to throw .NET exceptions in the calling .NET Web services client
thus allowing to have the same functionality of exception handling as it has
been available with the NCo.


“Checker” class SAP.NetWeaver.Bapi.BapiException.BapiRetCheck


Since the coding of the Web service proxy does not throw a .NET execption a new
checker class SAP.NetWeaver.Bapi.BapiException had to be implemented that
performs a check for the Return parameter in the calling .NET client. By just adding one line of code

checker.Check(bapiReturn);

an exception of type SAP.NetWeaver.BAPI.BapiException will be thrown if at least
in one of the entries of
the Return parameter (here: bapiReturn), the field Type is filled with A (abort) or E (error).


BAPI Return Parameter


The export parameter Return can be implemented in a BAPI in two different ways:


    1. As a structure, whereby it is defined in the function module as an export parameter.


     image
     

 

    1. As a table, whereby it is defined in the function module as a table parameter


     image
     

The Return parameter may thereby be based on one the following reference structures:


    1. BAPIRET2
    2. BAPIRET1
    3. BAPIRETURN
    4. BAPIRETURN1

While BAPIRET2 is used in new BAPIs the structures BAPIRET1, BAPIRETURN and BAPIRETURN1 may still partly
be used in old BAPIs. The structures BAPIRET1 and BAPIRETURN1 consist of the same fields as the BAPIRET2 structure excluding the fields PARAMETER, ROW, FIELD and SYSTEM. The structure BAPIRETURN consists of the same fields as BAPIRETURN1 and BAPIRET1 excluding the field NUMBER that is used to store the numeric value of the BAPI Return code. The BAPIRETURN structure therefore uses the field CODE instead.

Since the Return parameter may be based on one of the four mentioned reference structures and because it may be returned as a structure or a table a developer could be confronted with up to eight different options how a BAPI returns its Return code.
It was therefore one of the design goals to use a generic coding to check for the BAPI Return codes.


Reflection


The .NET Framework allows developers to
discover information about types included in their programs or in other
assemblies. This is referred to as Reflection and it is provided through a set
of .NET base classes included in the System.Reflection namespace. This
sample uses the System.Reflection namespace and some of the main classes
to gather information on the various types that may be used by a Return code
that is returned by the Web service proxy.</p>


How to use the Checker Class


Before digging into the coding of the checker class we first want to have a
look how it can be used. The coding that contains the class declarations resides in one code File BapiRet.cs
which can thus easily be added to any existing project.</p>


 Step 1: Add BapiException.cs to the project


          

  • In Solution Explorer, select a
    target project.
  • On the Project menu, select Add
    Existing Item.

In the Add Existing dialog box,
     locate and select the the file BapiException.cs that you want to add.</li>
     
               

 


               image
</ol>

Step 2: Add using directive for the Namespace SAP.NetWeaver.Bapi


Add the following using directive to your coding:

using SAP.NetWeaver.Bapi;


Step 3: Create Checker object


Now we have to create an instance of the checker object. To do this we add
the following line to the coding where the other varaibles are declared.



     

// Create a checker object

BapiRetCheck checker = new BapiRetCheck();


Step 4:  Perform check


As shown in the coding of a C# Web services command line
application below we just have to add one single line of code after the call of the
Web service proxy.



If the Return parameter is defined as a structure the Web service call will look like

          


               


If the Return parameter is defined as a table the Web service call will look like


               


Step 5: Add exception handling


We now have to add the exception handling.for the BAPI Exceptions that might be
raised. It is recommended to have at least two catch blocks.
The first catch statement is for the SAP specific exceptions of type +
SAP.NetWeaver.Bapi.BapiException +and the second for others (generic),
for example errors from the runtime or other resources.

If the Return parameter does not contain an error message the content of
the Return parameter can also be retrieved using the property ReturnTable
of the checker object.


Example: C# Web services client commandline application


Sample Code


The sample code consists out of three classes that are using the namespace +
SAP.NetWeaver.Bapi+.  The class BapiRetCheck is used to check the
Return Parameter of a BAPI that is called via Web services. The class ReturnParameters
is used as a generic storage for the content that is retrieved from the Return
parameter. The class  BapiException  is derived from System.Exception.
If  in at least one of the entries of Return parameter, the field Type is filled with A (abort) or E (error)
an exception of type SAP.NetWeaver.Bapi.BapiException.</p>

Class BapiRetCheck


The method check takes the Return parameter as an argument. </span>The
Return parameter is passed as an object called bapiReturn. If the+
Return+ parameter in the BAPI is implemented as a table bapiReturn is
an array.

!https://weblogs.sdn.sap.com/weblogs/images/11352/bapiRet2Table.png|height=380|alt=image|width=600|src=https://weblogs.sdn.sap.com/weblogs/images/11352/bapiRet2Table.png|border=0!

If the+ Return+ parameter in the BAPI is implemented as an export
parameter bapiReturn is a complex structure.</p>
image

As a first step it is checked whether the object bapiReturn is an array. If
the object bapiReturn is an array of objects a loop is performed to iterate
through all members. Check then passes the single object(s) to the private method +
PerformCheck+.

PerformCheck first checks whether bapiReturn has has either
the structure of BAPIRET2
, BAPIRET1 BAPIRETURN or BAPIRETURN1. If the check went OK the content of the
fields of the Return parameter are assigned to an ReturnParameters object
bapiReturnParameters.

Now +
PerformCheck+ checks whether the property +Type +of +bapiReturnParameters
+contains “A” or “E” which would raise an exception of type +BapiException.
+Otherwise the content is added as an additional item to the property ReturnTable..</p>


     

if ((bapiReturnParameters.Type == “E”) || (bapiReturnParameters.Type ==
“A”))

    throw new BapiException(bapiReturnParameters); // in case if
real error otherwise just return

else

    this.ReturnTable.Add(bapiReturnParameters);


Class BapiException


The class BapiException is derived from System.Exception.
If this exception is raised it gets the the
entry of the Return parameter where the field Type filled with A (abort) or E (error)
as an argument. The argument is a ReturnParameters object that is used to store
the content of the different Bapi Return structures generically.

It is thus possible to retrieve the content of each field of the error message allowing for the development of an appropriate exception handler.


    catch (BapiException e)n e)

    {

        Console.WriteLine("BAPI Exception caught");

        Console.WriteLine("NUMBER: " + e.BapiReturn.Number);

        Console.WriteLine("Message: " + e.BapiReturn.Message);

    }   

 

It is recommended to have at least two catch blocks.
The first catch statement is then used for the SAP specific exceptions of type BapiException
while the second is used for others (generic) exceptions,
for example errors from the runtime or other resources.


Class ReturnParameters


The class ReturnParameters  is used to store
generically the content of the complex structures BAPIRET2, BAPIRET1, BAPIRETURN
and BAPIRETURN1.  It therefore has properties for each field that can be
returned by on of the four structures. The property ReturnTable is used
by +BapiRet +objects to hold a list of objects based on ReturnParameters.

Property Type Description BAPIRET2 BAPIRET1 BAPIRETURN BAPIRETURN1
TYPE string Message type:

    1. S (Success) for success messages
    2. E (Error) for erroneous situations
    3. W (Warning) for warnings
    4. I (Info) for information messages
    5. A (Abort) for abort messages

X X X X
ID string Message, message class X X   X
CODE string Message, message code     X  
NUMBER string Message, message number X X   X
MESSAGE string Message text X X X X
LOG_NO string Application log: Log number X X X X
LOG_MSG_NO string Application log: Message number running internally within log X X X X
MESSAGE_V1 string Message, message variables

Up to four variable values
can be used in a message.

Variables are used in the same order as the
variables

appear in the message text

X X X X
MESSAGE_V2 string X X X X
MESSAGE_V3 string X X X X
MESSAGE_V4 string X X X X
PARAMETER string Name of parameter in which the error message occurred X      
ROW int Row in parameter in which the error message occurred X      
FIELD string Field in parameter in which the error message occurred X      
SYSTEM string System (logical system) from which the message originates X      

Table: Structure of ReturnParameters.</p>


To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Holger Boskugel
    Hello Andre,

    a very nice and cool implementation of Type
    handling and use of reflection. But may be I
    can’t see it right. The code :

                    // Create a proxy
                    Z__MY_Service myProxy = new Z_MY_Service();

    should be :

                    // Create a proxy
                    Z_MY_Service myProxy = new Z_MY_Service();

    right ?

    Regards

    Holger

    (0) 
    1. Andre Fischer Post author
      Hi Holger,
      yes you are right.
      I changed the original coding using notepad so that it fits better in the layout :-(.
      Thanks and Best regards,
      André
      (0) 
  2. srinivas m
    Hello Andre,

    I used Exceptions instead of return table in a RFC. Can u please tell me how the .net Connector will catch this exceptions.

    Thanks & Regards,
    Srini.

    (0) 
    1. Andre Fischer Post author
      Hi Srini,

      this blog is not about the .NET connector and exception handling but about exception handling for Web services based on Business APIs (BAPI).

      I suggest that you post a question in the .NET interop forum

      Interoperability .NET

      Best regards,
      André

      (0) 

Leave a Reply