Connecting an add-on to SAP Business One
Presentation
Connecting a program to SAP Business One is the first thing every developer has to do and the (not so easy) answer dépends on to which part of the Platform the program has to connect.
Basically, the options are:
- Connect to the Data Interface (DI-API),
- Connect to the User Interface (UI-API),
- Connect to the UI then to the DI,
- Connect to the UI-DI then “derive” the connection to a different database,
- Connect to the server data interface (DIS),
- Connect to DIS thru the B1 Web Service extension.
We are now going to see all these possibilities.
As a warning, all the excerpts of program are in C# but they can easily be adapted to any other language and the target Platform is at least 8.8.
Connect to the Data Interface
By using this interface the program can gain an access to all the functionalities of the corresponding API. An interesting point here, is that the program can run on any computer provided the fact that the DI-API is installed.
Basically what has to be done to open a connection:
- Get an instance of the company object (the only instance which have to be created),
- Fill the mandatory parameters, which are:
- Database server,
- Database server type,
- Database name,
- License server,
- Company user name,
- Company user password.
And now the corresponding code:
private static SAPbobsCOM.Company _company; private static int ConnectDI() { int returnValue = -1; _company = new SAPbobsCOM.Company(); _company.Server = "192.168.90.118"; _company.DbServerType = BoDataServerTypes.dst_MSSQL2008; _company.CompanyDB = "DB_TestConnection"; _company.LicenseServer = "192.168.90.118:30000"; _company.UserName = "manager"; _company.Password = "password"; try { returnValue = _company.Connect(); } catch (Exception exception) { Console.WriteLine("Exception occurred: {0}", exception.Message); } return returnValue; }
The only thing here is that the license server string has to fully identify the service, so it has to include the port number.
When the work of the program is done, then it is mandatory to disconnect and to free the used objects. The next excerpt shows how:
int diConnect = ConnectDI(); if (0 == diConnect) { _company.Disconnect(); } Marshal.FinalReleaseComObject(_company);
The last line will free all instances of the COM object, allowing the garbage collector to get back the used memory.
Connect to the User Interface
A program can be connected to the user interface of the ERP, meaning to the local fat client. The way to do it is a bit different:
- The program has to get an instance of the current Gui manager (DCOM server),
- Connect to the application’s instance, thru a context string which identifies the development license Under which the program is developped.
The corresponding excerpt of program is the following:
private static SAPbouiCOM.Application _application; private static int ConnectUI(string connectionString = "") { int returnValue = 0; #if DEBUG if (string.IsNullOrEmpty(connectionString)) { connectionString = "0030002C0030002C00530041005000420044005F00440061007400650076002C0050004C006F006D0056004900490056"; } #endif var sboGuiApi = new SboGuiApi(); sboGuiApi.Connect(connectionString); try { _application = sboGuiApi.GetApplication(); } catch (Exception exception) { var message = string.Format(CultureInfo.InvariantCulture, "{0} Initialization - Error accessing SBO: {1}", "DB_TestConnection", exception.Message); Console.WriteLine(message); returnValue = -1; } Marshal.FinalReleaseComObject(sboGuiApi); return returnValue; }
The only trick here, is the use of the development context string, which allows to debug the program.
Connect to UI and DI
This type of connection will give the program a full access to all of the ERP’s API. It has to be noted that the way to connect has evolved with the version 8.8 of the ERP, allowing now to use the internal DI connection of the UI instead of having to create a specific DI connection: the direct results are a faster usage of the API and a smaller memory footprint.
Here is how to do it:
private static int ConnectUIDI(string connectionString = "") { int returnValue = ConnectUI(connectionString); if (0 == returnValue) { try { _company = (SAPbobsCOM.Company)_application.Company.GetDICompany(); } catch (Exception exception) { var message = string.Format(CultureInfo.InvariantCulture, "{0} Initialization - Error accessing SBO: {1}", "db_TestConnection", exception.Message); Console.WriteLine(message); returnValue = -1; } } return returnValue; }
There is nothing specific to note in this code.
Deriving a connection
Sometimes, it is necessary for the program being written to connect on the current fat client using the previous method and to temporarely open a connection on a different database, by using the same user. Since caching (even crypted) the password of any or all of the users is not an option, we have to:
- Create a new company object,
- Ask the APIs to fill its properties with the values of the opened connection,
- Change the database on which to connect,
- Finally connect.
Here is the corresponding code:
int uidiConnect = ConnectUIDI(); if (0 == uidiConnect) { SAPbobsCOM.Company comp2 = new SAPbobsCOM.Company(); try { var cookie = comp2.GetContextCookie(); var context = _application.Company.GetConnectionContext(cookie); comp2.SetSboLoginContext(context); comp2.CompanyDB = "DB_TestConnection2"; var retCode = comp2.Connect(); if (0 == retCode) { Console.WriteLine("Gui connected to {0}", _company.CompanyName); Console.WriteLine("New connection to {0}", comp2.CompanyName); Console.ReadLine(); } } catch (Exception exception) { Console.WriteLine(exception.Message); } finally { Marshal.FinalReleaseComObject(comp2); } }
There is nothing specific to note Inside this code.
Connect to DI-Server
To use this API, we have to generate xml documents and to send them to the COM interface of the SBODI_Server service.
Because of the verbosity of xml, the corresponding code excerpt is a bit longer:
private static int LastErrorCode; private static string LastErrorDescription; private static readonly Node DisObject = new Node(); private static string ConectDIS() { string returnValue = string.Empty; var enveloppeLogon = "{0} {1} {2} {4} {5} {6} "; var xmlString = string.Format(CultureInfo.InvariantCulture, enveloppeLogon, "192.168.90.118", "DB_TestConnection", "dst_MSSQL2008", "manager", "password", "ln_English", "192.168.90.118:30000"); var sb = new StringBuilder(); sb.Append("").Append(xmlString); var soapMessage = sb.ToString(); returnValue = DisObject.Interact(soapMessage); if (0 == LastErrorCode) { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(returnValue); var sessionNode = xmlDocument.SelectSingleNode("//*[local-name()='SessionID']"); if (null != sessionNode) { returnValue = sessionNode.InnerText; Console.WriteLine("Connected to DIS. SessionId: {0}", returnValue); } } return returnValue; }
Connect to DIS thru B1WS
The web service wrapper provided by SAP allow the programmer to use the services prodided by DIS, in a much easier manner. This interface has eveolved over time and is now in the version 1.2 which is specific to the 9.0 version of the ERP.
To ease the integration of web-serevices, the author is personally using SoapUI in its open-source version.
The connection functionality is done thru the LoginService and after having referenced its specific wsdl and created a request to the Login verb, we get (and modify) the xml definition of the message:
192.168.90.118 DB_TestConnection dst_MSSQL2008 manager Kuldip ln_English 192.168.90.118:30000
Conclusion
This is it for this document and while some specifics have not been covered (i.e. Single Sign On mode from version 9.0), this post reviewed all the ways (using the various APIs) to connect onto the ERP in an efficient manner.
Full working project (VisualStudio 2012) is attached to this document, so don’t hesitate to have a look at it.
Don’t forget to vote! and good programming.
New NetWeaver Information at SAP.com
Very Helpfull