Thursday 29 July 2021

Connecting to sap business one from c#

What do you need to do in order to connect to sap business one from c#?

First of all you need to know which version of the API do you want to use and does API is 32bit or 64bit. 

The API is called "DI API" and can be found on the same server where you did the SAP installation in the same directory.

For example, DI API version 100 is located in


Before you actually can use the API you need to register the SAP Com object. Inside "DI API" directory you will find a file "SAPbobsCOM100.dll" (for version 100) and register it with 

%systemroot%\System32\regsvr32.exe C:\DI API 100\SAPbobsCOM100.dll

Note that we use "regsrv32.exe" is used for the 64bit version.

After COM object is installed you can add it from Visual Studio "Add references"
Add COM object as reference "SapBob"

 Once we have the COM object we can start coding. A basic object which is used for connection is called "Company"


  static void Main(string[] args)
        {
            Company oCompany = new Company();
            oCompany.Server = "Sap-10-Sql";
            oCompany.language = BoSuppLangs.ln_English;
            oCompany.DbServerType = BoDataServerTypes.dst_MSSQL2019;
            oCompany.CompanyDB = "MyCompanyDb";
            oCompany.UserName = "admin";
            oCompany.Password = "pass";
            oCompany.DbUserName = "sa";
            oCompany.DbPassword = "pass";
            oCompany.UseTrusted = false;
        
            var lRetCode = oCompany.Connect();
            if (lRetCode == 0)
                Console.WriteLine("Done");
            string sErrMsg = string.Empty;
            oCompany.GetLastError(out lRetCode, out sErrMsg);
            Console.WriteLine(sErrMsg);
            oCompany.Disconnect();

        }

"Server" is the DB server and not an application server.
"CompanyDB" is the name of the database of the database server.
"UseTrusted" controls if DB authentication using DB credential or Windows credentials.

Now if you think everything will work after this, you are wrong :)
Probably you will get the following error
Failed to connect SLD, make sure SLD server is correct and available

This is because you also need to define the URL for SLD server (have no idea what is it, but you need it) and the license server.

You can do it programmatically by setting



oCompany.LicenseServer = "sap-10-app:40000";
oCompany.SLDServer = "sap-10-app:30010";

or you can do it in the conf file. In the same location where "DI API 100" folder is located, search for the folder called "Conf". Inside the conf directory open the file b1-local-machine.xml and modify the following values



Now you are good to go!

Wednesday 14 July 2021

Running embedded PowerShell script from .Net program

 I have a web UI that allows writing Powershell scripts. Later this script is being sent to the backend and executed.

In this post, I will focus how to execute the Powershell inside c#. 

First of all you need to add to you project "System.Management.Automation" reference. If you are not sure where to take it from, just open windows PowerShell windows and type

[psobject].assembly.location

The output is the exact location of the DLL.

In my program, the purpose of the PowerShell is to give the user the ability to manipulate the data of some DataTable object. For this purpose the program will person 3 operations.
1. Create DataTable
2. Pass it to Powershell 
3. Change the DataTable from inside the PowerShell
4. Return the DataTable 

Create DataTable

  1. DataTable dt = new DataTable();
  2. dt.Columns.Add("ID",typeof(Int32));
  3. DataRow dr = dt.NewRow();
  4. dr["ID"] =22;
  5. dt.Rows.Add(dr);

Create a Powershell object and pass this DataTable to it


  1. InitialSessionState iss = InitialSessionState.CreateDefault();
  2. Runspace rs = RunspaceFactory.CreateRunspace(iss);
  3. rs.Open();
  4.  
  5. string powershell = @"Param([system.Data.DataTable]$dt)
  6. [system.Data.DataRow]$row = $dt.NewRow();
  7. $row.ID = 3;
  8. $dt.Rows.Add($row);
  9.  
  10. return ,[system.Data.DataTable]$dt; "; //here is the catch ","
  11.  
  12.  
  13. using (PowerShell powerShellInstance = PowerShell.Create())
  14. {
  15. powerShellInstance.Runspace = rs;
  16. powerShellInstance.AddScript(powershell);
  17. powerShellInstance.AddParameter("dt", dt);
  18.  
  19. DataTable outDt = null;
  20.  
  21. Collection<PSObject> PSOutput = powerShellInstance.Invoke();


Note the Powershell parameter. It expects to get the DataTable . After this the script adds a new record into the DataTable.
This problematic point that took me some time to figure is how to return the DataTable.
The "," sign before [system.Data.DataTable]$dt; is not a misstake.
If you don't put it the script will return System.Data.DataRow!!! object.
You actually need "," to specify that you are returning the collection of DataRows

What is left now is to read the content of the output. You can check if there are some errors
  1. //catch the errors
  2. foreach (var err in powerShellInstance.Streams.Error)
  3. {
  4. var ex = err.Exception?.Message;
  5. }
and actually read the output DataTable
  1. //catch the output
  2. foreach (PSObject pSObject in PSOutput)
  3. {
  4. outDt = (DataTable)pSObject.ImmediateBaseObject;
  5. }
  6.  
  7. }



If we check the "outDt" is debugger, we will see row with a value "3" that we added in the

Powershell script


Debug View of DataTable created from Powershell
Datatable created by Powershell manipulation



P.S. Point of concern. I am trying to figure out how I can secure the PowerShell
script from harming my backend. I could not find a way in PowerShell to restrict my 
PowerShell access to my file system. To solve this problem, I wrapped the whole 
code in a custom restricted AppDomain.