Invoke MiSys Equation API From .NET

Introduction

This article explains how to invoke MiSys Equation API (or any AS/400 program in general) through IBM i Access
for Windows component. The code is about calling an RPG compiled program (or
any OS/400 command) on IBM AS/400 iSeries server from .NET application

Background

MiSys Equation is the core banking system at one of my client, hosted on an iSeries server. we
need to expose Equation API/commands as .NET Services for any application to consume them regardless of the platform.
BizTalk and WCF is the platform for our middleware SOA implementation. IBM iSeries Access to Windows is a library from IBM to connect to iSeries application over TCP protocol.
This walk through describes how to expose MiSys Equation functionality as .NET library. we need to build a WCF or BizTalk service on top of this library method to expose it as web service.

Code Walk through

1. Install IBM iSeries Access to Windows. Also check for service packs
at this URL

http://www-03.ibm.com/systems/i/software/access/windows/casp.html

2. Create a new Console Application project in Visual Studio

3. Add Project Reference to cwbx.dll ActiveX from C:\Program Files
(x86)\IBM\Client Access\Shared

4. Add the attached API.cs file to your project

5. Now, we are going to connect to iSeries. we need to provide iSeries Server IP/Name, User Name and Password to connect.

//code snippet from attached API.cs

AS400System as400 = new AS400SystemClass()

Program program = new Program(); // iSeries Program (PGM)  

as400.Define("10.10.10.10"); //Server Name/IP
program.system  = as400;
program.system.UserID =User;
program.system.Password = Password;

as400.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);
//Connect to execute Remote commands only

6. Once we are connected to iSeries, we need to initialize
liability(context) with Equation application. This context specifies to which Equation application instance we are going to connect, as there could be multiple application instances running on the server.
Parameters.Append() is used to defined the parameters and their length. All the parameters will be passed as a Byte array and the response will be a Byte array as well.

program.LibraryName = "KAPBASELIB";
program.ProgramName = "KAPUNLIBL"; 

StringConverter stringConverter = new StringConverterClass();
ProgramParameters parameters = new ProgramParametersClass();

parameters.Append("Env", cwbrcParameterTypeEnum.cwbrcInput, 3);
parameters.Append("A1", cwbrcParameterTypeEnum.cwbrcInput,4); 

parameters["Env"].Value = stringConverter.ToBytes("DEV");//Equation Instance
parameters["A1"].Value = stringConverter.ToBytes("*DFT");//default value 

program.Call(parameters);

7. Next step is to define and assign values to In and Out parameters and call Equation
API. you need to consult MiSys Equation Journal File Documentation to check for parameters length and whether they are Input or Output parameters

program.ProgramName = "H46HMR";//Inquiry API Wrapper
ProgramParameters parameters = new ProgramParametersClass();

SetInParameter(ref parameters, "EPGM",10, "H68EER");//Bal Inq Function identifier
SetInOutParameter(ref parameters, "DSAIF",3000, "00001xxxxx"); //Account No. 

program.Call(parameters);

8. Final step is to parse the response received from Equation. As you can see in the above code, DSAIF is input/output parameter and will have the response from Equation in the form of Byte array. we need to parse the byte array through StringConverter helper method

_response.Bytes = parameters[2].Value;

StringConverter stringConverter = new StringConverterClass();
stringConverter.Length = 0; // Use all bytes in source byte array to build string
string str = stringConverter.FromBytes(_response.Fields["HZCUN"].Value);

Points of Interest

couple of points worth noting

1. Input and Output parameters are Byte array. i.e. you need to take
care of order of parameters when using parameters.append()

2. use StringConverter, PackedConverter helper methods to convert
from Byte array to string

see the attached zip file for a sample implementation for Account
Balance Inquiry API.

Thanks to Joe Rattz for this article, which was starting point for me.

BizTalk Server Monitoring

52 thoughts on “Invoke MiSys Equation API From .NET

  1. Helder Soares

    Hi Usman,

    I cant read you article at Code Project “invoking Equation API from .NET”

    Can you tell me where can I check you article.

    Many thks,

    Helder Soares
    (from Portugal)

    1. Hi Helder ,

      The article on code project is not approved yet, so I posted it here on my blog.
      If you cannot access the attached file, just send me an email, I’ll send you that file.

      1. Helder Soares

        Hi,
        thanks for your reply 😉
        I cant download your sample! Can you please send me for my Email (helder.soares[at]gmail[dot]com)

        I need to build one WCF Adapter for Biztalk to improve my communication with Misys Equation API.
        Thanks, your article was great help!

  2. Hi Usman,
    Great article! I am dying to see your code, but unfortunately cant download it. If possible, could you please email [m4shrur[at]gmail[dot]com] me the code?
    Thanks in advance

  3. Jake

    i have the following code which is passes two parameters to a as400 cl program but i get an error when i run it what am i doing wrong?

    Dim system As New cwbx.AS400System()
    Dim str As New cwbx.StringConverter

    system.Define(“as400”)
    system.UserID = “qsecofr”
    system.Password = “password”
    system.IPAddress = “192.1.1.2”
    system.Connect(cwbx.cwbcoServiceEnum.cwbcoServiceRemoteCmd)
    Dim program As New cwbx.Program
    program.LibraryName = “QGPL”
    program.ProgramName = “PASSWORDCH”
    Dim parmlength As Integer
    parmlength = 10
    Dim paramters As New cwbx.ProgramParameters
    paramters.Append(“USER”, cwbx.cwbrcParameterTypeEnum.cwbrcInput, 10)
    paramters.Append(“PASSWD”, cwbx.cwbrcParameterTypeEnum.cwbrcInput, 10)
    ‘ paramters[“USER”].vALUE=cwbx.stringConverter.ToBytes(“TCBOPR”)\
    paramters(“USER”).Value = str.ToBytes(“pinkda”)
    paramters(“PASSWD”).Value = str.ToBytes(“tcbopr”)
    ‘ Try

    program.Call(paramters)
    ‘Catch ex As Exception
    ‘For Each er As cwbx.Error In system.Errors
    ‘Call MsgBox(“Err.ToString()”)
    ‘ Console.WriteLine(Err.ToString())
    ‘Next

    ‘End Try

  4. Hi Jake,

    what is the exact error you’re getting?
    do you have cwbx.Error populated or have an exception in your program? details of the error will help us to find the cause

    Thanks
    Usman Shaheen

  5. mahesh

    Hi Usman
    Need your help. I am looking for documents or mannuals for Equation/3. Next week I am attending interview on Eq/3.
    six years before I have developed application to interface with Eq/3 in RPGLE but I forgot all these . To refresh my knowledge . Please send me some link or documents

    Thanks in advance

  6. hasan hadid

    Hi Usman,

    I am currently in charge of application development in a bank that utilizes Equation 3.9. I tried to run your code after converting to vb.net but did not succeed and could not access the attached file. I will be gratefull if can you send it to me on my email hrhhadid@yahoo.com

    Regards,

    Hasan

  7. Syed Hasan

    Hello Usman,

    Need your help. I want to use equation APIs in visual studio. Please forward me API.cs file whihc you mentioned at your blog. Also not very much familiar with visual studio if you suggest me or forward any document/manual/web site to learn visual studio .

    Thanks in advance

    Syed Hasan

  8. Antonio Carvalho

    Hi Usman,
    where can I get the code ? Could you please send me the code to my email (alberto.a.carvalho@gmail.com)?

    Thank you,
    António

  9. Marcus

    Hi Usman,

    Great article! I’ve been looking for help on this subject for a long time. Can you please send me a copy of the example files and the API.cs file? My e*mail is mubi99[at]gmail[dot]com…

    Cheers,
    MM

  10. Helo Usman,
    I’ve try the same code in java, but it’s return error as below :
    Filename QCEEMSG
    ID CEE9901
    Library QSYS
    Error Text Application error. RNX9001 unmonitored by H56HMR at statement *N, instruction X’0000′.
    Severity 30
    Type 15
    Help Cause . . . . . : The application ended abnormally because an exception occurred and was not handled. The name of the program to which the unhandled exception is sent is H56HMR H56HMR _QRNP_PEP_H56HMR. The program was stopped at the high-level language statement number(s) *N at the time the message was sent. If more than one statement number is shown, the program is an optimized ILE program. Optimization does not allow a single statement number to be determined. If *N is shown as a value, it means the real value was not available. Recovery . . . : See the low level messages previously listed to locate the cause of the exception. Correct any errors, and then try the request again.

    Could you give some advice about this error?
    Thanks in advance

  11. Alaa

    Hi Usman,

    Nice Article.

    However, have you thought about the connection pooling and multi-threading support for cwbx dll, i think it does not support the connection pooling and multiple calls into the dll will stack up one after the other until they are all executed?

    any ideas about this?

    Thanks,
    Alaa

  12. Hi Alaa,

    we implemented Asyn pattern in our .net code to improve performance where multiple API calls were involved, each API call is invoked in a separate thread. Also a common data area can be reused for subsequent Equation calls

  13. Anonymous

    Hi Usman,
    I saw your article above and it’s really great. But I would request something else – not sure if it is possible with you or not. I need a documentation of the Application/Business.
    Never mind if you are not in a position to share.
    Chinmoy
    Thanks & Regards

  14. Bil

    Dear,

    I am trying to call Equation ITA API from java.
    DGZH181 should be passed as a parameter of the API call through DSAIM. DGZH181 contains a lot of fields. Should I create a class for DGZH181 fill the values of fields then pass it to the API as object of this class?
    Should I initialize all fields of DGZH181 or the obligatory one only? How to place them in DGZH181?

    I couldn’t find the sample you attached. If it is not available can you send it plz to bilal.tay@gmail.com

    Do you have a sample of ITA or similar one?

    Thank you in advance.

  15. Anonymous

    Hi Usman,

    Would it be possible to get a copy of the cs and zip file? I can’t find where it is available for download on the page.

    Regards,

    Akiel

  16. Rose

    Hi Usman,
    Thank you so much for your valuable post
    please would you send me a copy of the cs and zip files?
    my email address is roseabrahamian@hotmail.com
    I am trying to call SSC10R (Retrieve available balance) API from java transformation through Informatica
    I am getting the below error
    Application error. RNX9001 unmonitored by SSC10R at statement *N, instruction X’0000′.

    My code is below

    // Create an AS400 object
    as400 = new AS400(HOST, UID, PWD);

    // Create a parameter list
    // The list must have both input and output parameters
    parmList = new ProgramParameter[31];

    // Convert the Strings to IBM format
    SCAB_IN_B= SCAB_IN.getBytes(“IBM285”);
    SCAN_IN_B= SCAN_IN.getBytes(“IBM285”);
    SCAS_IN_B= SCAS_IN.getBytes(“IBM285″);

    // Create the input parameter
    parmList[0] = new ProgramParameter(SCAB_IN_B);
    parmList[1] = new ProgramParameter(SCAN_IN_B);
    parmList[2] = new ProgramParameter(SCAS_IN_B);

    // Create the output parameter
    //Prarameterised Constructor is for the OUTPUT LENGTH. here it is 10
    parmList[3] = new ProgramParameter(4);
    parmList[4] = new ProgramParameter(6);
    parmList[5] = new ProgramParameter(3);
    parmList[6] = new ProgramParameter(15);
    parmList[7] = new ProgramParameter(3);
    parmList[8] = new ProgramParameter(1);
    parmList[9] = new ProgramParameter(2);
    parmList[10] = new ProgramParameter(8);
    parmList[11] = new ProgramParameter(8);
    parmList[12] = new ProgramParameter(8);
    parmList[13] = new ProgramParameter(8);
    parmList[14] = new ProgramParameter(8);
    parmList[15] = new ProgramParameter(8);
    parmList[16] = new ProgramParameter(8);
    parmList[17] = new ProgramParameter(8);
    parmList[18] = new ProgramParameter(8);
    parmList[19] = new ProgramParameter(8);
    parmList[20] = new ProgramParameter(8);
    parmList[21] = new ProgramParameter(8);
    parmList[22] = new ProgramParameter(8);
    parmList[23] = new ProgramParameter(8);
    parmList[24] = new ProgramParameter(8);
    parmList[25] = new ProgramParameter(8);
    parmList[26] = new ProgramParameter(8);
    parmList[27] = new ProgramParameter(1);
    parmList[28] = new ProgramParameter(1);
    parmList[29] = new ProgramParameter(1);
    parmList[30] = new ProgramParameter(1);

    /**
    * Create a program object specifying the name of the program and
    * the parameter list.
    */
    programCall = new ProgramCall(as400);
    programCall.setProgram(fullProgramName, parmList);

    // Run the program.
    if (!programCall.run()) {
    /**
    * If the AS/400 is not run then look at the message list to
    * find out why it didn’t run.
    */
    AS400Message[] messageList = programCall.getMessageList();
    for (AS400Message message : messageList) {
    System.out.println(message.getID() + ” – ” + message.getText());
    }
    } else {
    /**
    * Else the program is successfull. Process the output, which
    * contains the returned data.
    */
    outputData = parmList[3].getOutputData();
    SCAB = new String(outputData, “IBM285”).trim();

    outputData = parmList[4].getOutputData();
    SCAN = new String(outputData, “IBM285”).trim();

    outputData = parmList[5].getOutputData();
    SCAS = new String(outputData, “IBM285”).trim();

    outputData = parmList[6].getOutputData();
    SCSHN = new String(outputData, “IBM285”).trim();

    outputData = parmList[7].getOutputData();
    SCCCY = new String(outputData, “IBM285”).trim();

    outputData = parmList[8].getOutputData();
    CED = new String(outputData, “IBM285”).trim();

    outputData = parmList[9].getOutputData();
    SCACT = new String(outputData, “IBM285”).trim();

    outputData = parmList[10].getOutputData();
    SCODL = new String(outputData, “IBM285”).trim();

    outputData = parmList[11].getOutputData();
    SCLED = new String(outputData, “IBM285”).trim();

    outputData = parmList[12].getOutputData();
    SCRBA = new String(outputData, “IBM285”).trim();

    outputData = parmList[13].getOutputData();
    SCBAL = new String(outputData, “IBM285”).trim();

    outputData = parmList[14].getOutputData();
    BALST = new String(outputData, “IBM285”).trim();

    outputData = parmList[15].getOutputData();
    BALPC = new String(outputData, “IBM285”).trim();

    outputData = parmList[16].getOutputData();
    BALCC = new String(outputData, “IBM285”).trim();

    outputData = parmList[17].getOutputData();
    BALCA = new String(outputData, “IBM285”).trim();

    outputData = parmList[18].getOutputData();
    BALNA = new String(outputData, “IBM285”).trim();

    outputData = parmList[19].getOutputData();
    BALFW = new String(outputData, “IBM285”).trim();

    outputData = parmList[20].getOutputData();
    CLRNW = new String(outputData, “IBM285”).trim();

    outputData = parmList[21].getOutputData();
    CLRLT = new String(outputData, “IBM285”).trim();

    outputData = parmList[22].getOutputData();
    CLRTM = new String(outputData, “IBM285”).trim();

    outputData = parmList[23].getOutputData();
    CLRAF = new String(outputData, “IBM285”).trim();

    outputData = parmList[24].getOutputData();
    SCSUMD = new String(outputData, “IBM285”).trim();

    outputData = parmList[25].getOutputData();
    SCSUMC = new String(outputData, “IBM285”).trim();

    outputData = parmList[26].getOutputData();
    SCSUMA = new String(outputData, “IBM285”).trim();

    outputData = parmList[27].getOutputData();
    ODLEX = new String(outputData, “IBM285”).trim();

    outputData = parmList[28].getOutputData();
    BALEX = new String(outputData, “IBM285”).trim();

    outputData = parmList[29].getOutputData();
    SCAI17 = new String(outputData, “IBM285”).trim();

    outputData = parmList[30].getOutputData();
    SCAI32 = new String(outputData, “IBM285”).trim();
    generateRow();
    /* System.out.println(“Output is ” + SCAB );*/
    }

    } catch (PropertyVetoException | AS400SecurityException | ErrorCompletingRequestException | IOException | InterruptedException | ObjectDoesNotExistException e) {
    System.err.println(“:: Exception ::” + e.toString());
    } finally {
    try {
    // Make sure to disconnect
    if (as400 != null) {
    as400.disconnectAllServices();
    }
    } catch (Exception e) {
    System.err.println(“:: Exception ::” + e.toString());
    }
    }

Leave a reply to Jake Cancel reply