Infor Mongoose IDO Development Guide PDF
Infor Mongoose IDO Development Guide PDF
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Use this guide if you are developing your own IDOs based on the Infor Mongoose framework, or if you
are extending the functionality of an existing IDO by adding methods and event handlers.
This guide describes the classes and libraries available to you, and provides some examples of their
use.
Intended audience
The primary audience for this guide includes form and application developers who need to develop
their own Intelligent Data Objects (IDOs) for Mongoose-based applications. Secondary audiences
include training, support, marketing, and other personnel.
Related documents
You can find the documents in the product documentation section of the Infor Xtreme Support portal,
as described in "Contacting Infor" on page 6. These additional resources are available:
Integrating IDOs with External Applications - Includes an overview of what IDOs are and the
different ways that applications can interface with IDOs. It provides examples and syntax showing
how to set up IDO requests and responses in different protocols (XML documents, the application
event system, .NET Web service, and so on).
Guide to the Application Event System - Describes the Application Event System, which
developers and system administrators can use to create events and event handlers that automate
tasks. It also contains sample scenarios that will help you understand how you can take
advantage of the Application Event System.
Modifying SyteLine - Includes a list and descriptions of the tools available for creating and editing
forms, IDOs, application events, and event handlers. It also describes the administrative and
development utilities to use for managing a development project and deploying an application.
This guide also includes information you may need about external touch points, application
messages, licensing for IDOs, and so on. We strongly recommend that you read through this
guide before creating or modifying IDOs, especially for SyteLine.
Contacting Infor
If you have questions about Infor products, go to the Infor Xtreme Support portal at http://
www.infor.com/inforxtreme.
If we update this document after the product release, we will post the new version on this Web site.
We recommend that you check this Web site periodically for updated documentation.
If you have comments about Infor documentation, contact [email protected].
Overview
Developers can use the IDO .NET class library to programmatically access the Mongoose business
objects, which are called IDOs (Intelligent Data Objects).
Interactions with an IDO are based on requests and responses. The caller constructs an IDO request
and sends it to the IDO runtime service to be executed. The IDO runtime service constructs and
returns a response to the caller containing the results of the action requested.
All client access to the application database is through the IDOs. The primary responsibilities of the
IDO runtime service include querying data sets (LoadCollection), saving data (UpdateCollection), and
calling methods (Invoke).
Each IDO request has a request type such as OpenSession, LoadCollection, UpdateCollection, or
Invoke. It also contains an optional request payload that is dependent on the request type. For
example, the payload for an OpenSession request contains logon information for a user, such as user
ID, password, and configuration.
The API is used by standalone client applications, WinStudio scripts, user controls, and within IDO
extension classes. The same programming interface is available on the client using the
Mongoose.IDO.Client class and from an IDO extension class using the Me.Context.Commands
property. This chapter focuses on use of the class library; the extension classes are described in
Chapter 2, “IDO Extension Classes."
AppDB Class
The AppDB class, part of the Mongoose.IDO.DataAccess namespace, is available only to extension
classes. It provides direct access to the application database, plus access to common framework
features such as application messages and session variables. For more information about this class,
see “AppDB Class” on page 55.
The syntax for using the IIDOCommands interface is different in other contexts, such as a form script
or a standalone client application.
GetPropertyInfo
Use GetPropertyInfo to retrieve a list of properties and their attributes for an IDO.
Properties
This table describes the properties available on the LoadCollectionRequestData class
GetPropertyInfo Example
Note: The remaining code examples in this chapter are given for C# unless otherwise indicated.
GetPropertyInfoResponseData response;
LoadCollection
Queries are performed using the LoadCollection API and associated protocol classes. LoadCollection
requests can be constructed using the LoadCollectionRequestData IDO protocol class.
Properties
This table describes the properties available on the LoadCollectionRequestData class.
request.IDOName = "SLItems";
request.PropertyList.SetProperties( "Item, Description, QtyOnHand" );
request.Filter = "Item LIKE N'AB%'";
request.OrderBy = "QtyOnHand";
request.RecordCap = 0;
response = this.Context.Commands.LoadCollection( request );
qty = 0;
for (int row = 0; row < response.Items.Count; row++)
{
qty += response[row, "QtyOnHand"].GetValue<int>();
}
UpdateCollection
Updates (includes inserts, updates and deletes) are performed using the UpdateCollection API and
associated protocol classes. UpdateCollection requests can be constructed using the
UpdateCollectionRequestData IDO protocol class. This table describes the properties available on
the UpdateCollectionRequestData class.
Properties
Property Data Type Description
IDOName System.String Identifies the IDO used to execute the
request.
CollectionID System.String An identifier associated with this
UpdateCollection request.
RefreshAfterUp System.Boolean A boolean value used to indicate if the caller
date wants the response to contain the updated
items refreshed after they were saved.
CustomInsert System.String These properties are used to specify
CustomUpdate custom actions to use when saving items.
Note: This is the same as a custom INS/
CustomDelete
UPD/DEL in WinStudio.
LinkBy Mongoose.IDO.Protocol. Applies to inner nested UpdateCollection
PropertyPair array requests only and specifies the relationship
between a parent and child IDO in terms of
property pairs. Use the SetLinkBy method to
set this property.
Default: Empty
Items Mongoose.IDO.Protocol. An instance of the IDOUpdateItems class
IDOUpdateItems that contains zero or more IDOUpdateItem
instances. The IDOUpdateItem class
contains the update information for a single
item.
TxnScope Mongoose.IDO.Protocol.T When the TxnScope is set to Item, each
xnScope individual item in the UpdateCollection
request is saved in a separate transaction.
For a hierarchical (nested) UpdateCollection
request, the value of the TxnScope attribute
at the root level determines the behavior for
the entire UpdateCollection request. This
attribute has no effect when it is included in
an inner UpdateCollection within
hierarchical requests.
UpdateCollection Example
UpdateCollectionRequestData request = new
UpdateCollectionRequestData();
UpdateCollectionResponseData response;
IDOUpdateItem newCust = new IDOUpdateItem();
request.IDOName = "SLCustomers";
request.RefreshAfterUpdate = true;
newCust.Action = UpdateAction.Insert;
newCust.ItemNumber = 1;
// used for error reporting
newCust.Properties.Add( "CustNum", "C000100" );
newCust.Properties.Add( "Name", "Boxmart" );
newCust.Properties.Add( "CurrCode", "USD" );
newCust.Properties.Add( "BankCode", "BK1" );
request.Items.Add( newCust );
LoadCollection/UpdateCollection Example:
Saving Changes to Existing Records
This example loads data from an IDO, updates the data and saves the collection.
public void DoUpdate()
{
LoadCollectionResponseData Loadresponse =
LoadCollectionResponseData;
string sCoNum = null;
string sFilter = null;
sCoNum =
ThisForm.PrimaryIDOCollection.GetCurrentObjectProperty("CoNum");
sFilter = "CoNum = '" + sCoNum + "'";
Invoke
IDO methods (not including custom load methods) are called using the Invoke API and associated
protocol classes. Invoke requests can be constructed using the InvokeRequestData IDO protocol
class. This table describes the properties available on the InvokeRequestData class.
Properties
Property Data Type Description
IDOName System.String Identifies the IDO used to execute the request.
MethodName System.String Identifies the IDO method to be executed.
Parameters Mongoose.IDO.Protocol. A collection containing instances of the
InvokeParameterList InvokeParameter class corresponding to the
IDO method parameters.
To execute an Invoke request, first construct an instance of the InvokeRequestData class, and pass it
to the Invoke method on the IIDOCommands interface.
Invoke Example 1
InvokeRequestData request = new InvokeRequestData();
InvokeResponseData response;
request.IDOName = "UserNames";
request.MethodName = "UserValidSp";
request.Parameters.Add( "ajones" );
// user name, input
request.Parameters.Add( IDONull.Value );
// user ID, output
request.Parameters.Add( IDONull.Value );
// description, output
request.Parameters.Add( IDONull.Value );
// infobar, output
if ( response.IsReturnValueStdError() )
{
// get infobar output parameter
string errorMsg = null;
errorMsg = response.Parameters[3].Value;
}
else
{
int userID = 0;
string desc = null;
userID = response.Parameters[1].GetValue<int>();
if ( !response.Parameters[2].IsNull )
{
desc = response.Parameters[2].Value;
}
}
In many cases it is more convenient to call the overloaded version of the Invoke method that accepts
parameters for the IDOName, MethodName and method parameters InvokeRequestData properties.
Invoke Example 2
InvokeResponseData response;
response = this.Context.Commands.Invoke(
"UserNames",
"UserValid",
"ajones",
IDONull.Value,
IDONull.Value,
IDONull.Value );
if ( response.IsReturnValueStdError() )
{
// get infobar output parameter
string errorMsg = "";
errorMsg = response.Parameters[3].Value;
}
else
{
int userID = 0;
string desc;
userID = response.Parameters[1].GetValue<int>();
if ( !response.Parameters[2].IsNull )
{
desc = response.Parameters[2].Value;
}
}
{
if (!loadResponse(0, "UserId").IsNull)
{
userId = loadResponse(0, "UserId").GetValue<long>(-1);
}
}
Translation/Localization Considerations
All data values in IDO requests and responses are stored as string values in an "internal" format that
is independent of any regional settings for the application or local machine where the code is
executing.
Type Conversions
The IDO protocol classes store all property and parameter values internally as strings in a non-
localized internal format. However, the framework also provides methods that allow you to
transparently convert between supported native .NET CLR data types and the internal formatted
string values. You should always use strongly typed variables when getting values from, or putting
values into, any of the IDO protocol classes in order to take advantage of this feature and avoid
problems related to systems running with different regional settings. This is especially important when
working with date and numeric values.
The built-in VB functions for data type conversions (CStr, CDate, CInt, etc.) are sensitive to the
regional settings for the application or local machine.
invokeRequest.IDOName = "MyIDO";
invokeRequest.MethodName = "MyMethod";
invokeRequest.Parameters.Add("Mongoose");
invokeRequest.Parameters.Add(version);
invokeRequest.Parameters.Add(Guid.NewGuid());
invokeRequest.Parameters.Add(recordDate);
invokeRequest.Parameters.Add(IDONull.Value); // Set later.
Both the Add and SetValue methods accept a value of any supported .NET data type and
automatically handle the conversion to internal format, so that the developer does not need to think
about conversion issues.
// Set later.
updateItem.Properties.Add("UserName", "MGUser");
updateItem.Properties.Add("RecordDate", DateTime.Now);
updateItem.Properties.Add("RowPointer", Guid.NewGuid());
updateItem.Properties["UserId"].SetValue(100L);
updateRequest.IDOName = "MyIDO";
updateRequest.Items.Add(updateItem);
loadResponse = this.Context.Commands.LoadCollection("UserNames",
"UserId, UserName, RecordDate, RowPointer", "", "", 0);
userId = loadResponse[0, "UserId"].GetValue<long>();
userName = loadResponse[0, "UserName"].GetValue<string>();
recordDate = loadResponse[0, "RecordDate"].GetValue<DateTime>();
rowPointer = loadResponse[0, "RowPointer"].GetValue<Guid>();
loadResponse = this.Context.Commands.LoadCollection("UserNames",
"UserId, UserName, RecordDate, RowPointer", "", "", 0);
if (!userId.HasValue)
userId = -1;
SqlLiteral.Format Method
The static SqlLiteral.Format method accepts any supported .NET CLR typed value and converts it
into a literal that can be used when constructing a filter as shown in this example:
string filter = null;
filter = string.Format(
"SessionId = {0} AND trans_num = {1}",
SQL Literal.Format(SessionID),
SQL Literal.Format(TransNum));
The above example produces a filter with the appropriate syntax for the literal values, similar to this:
SessionId = N' 7A4930D6-AE9E-4F32-9687-17ABDBF4E818' and trans_num = 1234
You must always pass in a strongly typed value in order to get the correct result. For example, you
should not pass a string containing a date value.
This table shows some examples of input types, values, and the SqlLiteral.Format result for each.
System.String System.Char
System.Byte System.Single
System.Double System.Guid
System.Decimal System.Boolean
System.Byte[ ]
Transactions
The IDO runtime automatically executes all UpdateCollection requests in a transaction. It also
executes IDO methods in a transaction if they are marked as "transactional" methods. All other IDO
requests are executed without a transaction. Note that if a method is not marked "transactional" and
is called from a method that is marked "transactional", then it still executes in the caller's transaction.
For transactional IDO methods, if the method returns an integer value less than 5, the transaction is
committed. The exception is if the method was executed within an existing outer transaction. Then
the transaction commits only if and when the outer transaction commits. If the IDO method returns an
integer value greater than or equal to 5 the transaction is rolled back immediately. The Mongoose
standard is to return 16 to indicate a method failed. The transaction also rolls back if the method
throws an exception.
If you need more control over transaction scope, which is often necessary for long running processes,
this can be achieved while still allowing the IDO runtime to manage transactions.
For example, consider a method that posts a large batch of records. We need a method that reads
the batch, loops through each record, and attempts to post it. If the post is successful, the action
commits, otherwise it rolls back. The best way to accomplish this is to create two methods: a top level
entry point method that queries the records to be posted; and another method to do the posting. The
top-level method should not be marked as transactional, while the posting is transactional. The entry
point method queries the records to be posted and loops through each one, calling the posting
method to post each record. This way, if a record fails to post, it does not roll back all posted records,
only the failed record.
Parameters
messageSource - A short, user-defined identifier of the source of a message (for example, class
or project name)
messageType - One of the UserDefinedMessageType enumeration values; used for searching
and filtering log messages
message - A string containing the log message text
format - A log message format string (see “String.Format()” in the .NET Framework
documentation for more information about formatting strings)
args - A variable-length list of format-string substitution parameters
Examples
IDORuntime.LogUserMessage(
"SLCustomers",
UserDefinedMessageType.UserDefined0,
"Method A() called.");
IDORuntime.LogUserMessage(
"SLCustomers",
UserDefinedMessageType.UserDefined0,
"Parameter 1 is {0}.",
p1);
Wire Tap
You can use the Wire Tap feature of the IDO Runtime Development Server to monitor all the IDO
request and response documents generated by a specific user session. For more information see the
online help for the IDO Runtime Development Server.
Open Session
The OpenSession method is used to create a new session (log in) in the application.
OpenSession Example
This code sample creates a new Client instance accessing the IDO runtime using the URL in
requestServiceURL, where the URL is similar to this:
http://servername/IDORequestService/RequestService.aspx
Client client = new Client(requestServiceURL, IDOProtocol.Http);
OpenSessionResponseData response = OpenSessionResponseData;
using (client)
{
// Substitute a valid SL user, password, and configuration name:
response = client.OpenSession("user", "password", "config");
if (response.LogonSucceeded)
{
Console.WriteLine("Success");
}
Client client = new Client();
Close Session
The CloseSession method is used to close an existing session (log out).
The OpenSession example above also includes an example of CloseSession.
GetConfigurations
Mongoose configuration information is stored in MongooseConfigs.xml. By default, this file is created
and resides in C:\Documents and Settings\All Users\Application Data\Mongoose.
The Client class accesses configuration information through the ConfigServer.aspx page
(IDORequestService ASP.NET Web server application) in conjunction with the IDO Runtime Service
or the IDORuntimeHost.exe developer tool. The Web Server application, IDO Runtime Service and
IDORuntimeHost.exe are all installed as part of a utility server installation. Configuration information
obtained using the GetConfigurations static method includes a subset of configuration properties and
all of the referenced application properties.
In code that utilizes the Client class, include these using statements (Import statements if written in a
VB project):
using Mongoose.IDO;
using Mongoose.IDO.Protocol;
using Mongoose.Core.Configuration;
ConfigurationInfo Example 1
This snippet of code retrieves an array of ConfigurationInfo classes through the IDORequestService.
Infor IDO Runtime Service must be running for this method to work.
//*******************************************************************
// This line calls the IDORequestClient ASPX web application
// to retrieve the configuration list via an array of
// ConfigurationInfo classes.
// Parm -> URL to IDORequestClient's ConfigServer.apsx file.
//*******************************************************************
ConfigurationInfo Example 2
This snippet of code retrieves an array of ConfigurationInfo classes through IDORuntimeHost.exe.
(IDORuntimeHost.exe must be running for this method to work.)
//*******************************************************************
// This line calls through to the local IDO runtime service
// (IPC protocol) to retrieve the configuration list via an array of
// ConfigurationInfo classes.
// Note: No parameter is passed to the GetConfigurations() method.
//*******************************************************************
ConfigurationInfoList configList = null;
configList = Client.GetConfigurations();
// Config info can be enumerated as follows:
foreach ( ConfigurationInfo config in configList )
{
// Do whatever.
}
Properties
These configuration/application properties are available through the ConfigurationInfo class.
Caution: Some information in the MongooseConfigs.xml file related to database connections, user
names, passwords, etc., is encrypted. The methods described here simply retrieve the encrypted
strings for these entities. If they need programmatic access to this information (that is, decrypted
strings), contact Infor Professional Services to discuss methods for decrypting it.
public bool ActiveScriptingOnly;
public string AppName;
public string AppURL;
public string BaseHelpFile;
public bool ColSecurityPrimaryOnly;
public string CompanyName;
public string Copyright;
public string DefFormBGColor;
public string DefFormFGColor;
public string DefFormFont;
public string DefNormalBGColor;
public string DefNormalFGColor;
public string DefReadOnlyBGColor;
public string DefReadOnlyFGColor;
public string DefRequiredBGColor;
public string DefRequiredFGColor;
public string DefTbdBGColor;
public string DefTbdFGColor;
3 In code that utilizes the Client class, include these "using" statements (Import statements if written
in a VB project)
using Mongoose.Core.Configuration;
using Mongoose.Core.Common;
Example
This snippet of code retrieves an array of configuration names, gets the application name and a
couple of application properties, and finally retrieves the Runtime Forms Database name (encrypted):
// Create instance of ManageConfigs class:
MongooseConfigs ManageConfigs = null;
ManageConfigs = new MongooseConfigs();
// Load MongooseConfigs.xml:
ManageConfigs.Load(true);
Properties
These configuration/application properties are available through the Configuration class:
public string Application;
public string ConfigName;
Parameters
Parameter Description
@AccessKey The key value used to uniquely identify the external data store item. It is
up to the developer to create a unique key. For example, you might use
the user’s current session ID plus a row pointer as the key.
@Lifetime Numeric value that determines the lifetime of the external data store
item.
0 = Delete on fetch
1 = Delete on session close
2 = Keep until explicitly deleted
@Value The data value that is being stored/fetched.
@Infobar A message returned by the stored procedure in an output parameter.
Examples
// Create a new data store entry.
EXEC CreateDataStoreEntrySp
@AccessKey = 'my key'
, @Lifetime = 0
, @Value = 'my value'
, @Infobar = @Infobar OUTPUT
Parameters
Parameter Description
configName The configuration name
accessKey The key value used to uniquely identify the external data store item.
Examples
using Mongoose.IDO.Protocol;
using Mongoose.IDO;
IDOCore.dll
IDOBase.dll
IDOProtocol.dll
MGShared.dll
WSEnums.dll
7 From the Project menu, select Add New Item.
8 Select Code File, name the new file AssemblyInfo.vb, and click Add.
9 Open the new AssemblyInfo.vb source file and add this assembly attribute:
<Assembly: Mongoose.IDO.IDOExtensionClassAssembly("assembly-name")>
Substitute a meaningful name for the assembly-name parameter. This can be anything but
typically is the name of the IDO project associated with the classes in this assembly. When this
class library is imported to the IDO Custom Assemblies form, the name you specify here
becomes the name of the assembly.
Caution: If you add a reference to another assembly from your IDO extension class assembly, the
referenced assembly must also be imported as another custom assembly. When .NET tries to locate
the referenced assembly, the IDO runtime service searches the database for a matching assembly
and loads it on demand.
Importing Assemblies
To import assemblies, use the IDO Custom Assemblies form.
Link the IDO to the custom assembly on the IDOs form by checking out the IDO and entering the
Custom Assembly Name (the Assembly Name from the IDO Custom Assemblies form), the Ext
Class Name (the name of the class—usually the same as the IDO), and the Ext Class Namespace
(usually the same as the Project Name).
Link the methods in the extension class to the IDO by entering the Method Name and specifying the
Parameters list on the IDO Methods form. The Method Type will be Handcoded - Standard
Method or Handcoded - Custom Load Method.
Mongoose.IDO.IIDOExtensionClass Interface
In order for an extension class to access the calling user's context (session information, databases,
and so forth), the extension class should implement the IIDOExtensionClass interface in the
Mongoose.IDO namespace.
public interface IIDOExtensionClass
{
void SetContext(Mongoose.IDO.IIDOExtensionClassContext
context);
}
Mongoose.IDO.IIDOExtensionClassContext Interface
The SetContext method is called once when the extension class is created, passing a reference to
the IIDOExtensionClassContext interface for accessing the calling user's context.
public interface IIDOExtensionClassContext
{
Mongoose.IDO.IVirtualIDO IDO { get; }
Mongoose.IDO.IIDOCommandHelper Commands { get; }
}
It is generally a good idea to import some common framework namespaces to make your code less
verbose and more clear, and to enable the Explicit and Strict VB compiler options.
[IDOExtensionClass("class-name")]
public class class-name : ExtensionClassBase
{
// optionally override the SetContext method
// public override void SetContext(
// IIDOExtensionClassContext context )
// {
// call base class implementation
// base.SetContext(context);
//
// Add event handlers here, for example:
// context.IDO.PostLoadCollection +=
// new IDOEventHandler( IDO_PostLoadCollection );
// }
// ...Implementation goes here...
}
Adding Methods
To call a method on an IDO extension class, the method must be declared as public and it must also
be defined in the IDO metadata as a hand-coded method. This is different from previous versions of
the framework, where the metadata for a method was defined by convention, using the Do not
generate source attribute, but not required.
A hand-coded method can be either a standard method, which is a Function with zero or more input/
output parameters and returns an integer; or a custom load method, which is a Function with zero or
more parameters and returns an instance of either an IDataReader or a DataTable (see the .NET
Framework documentation for information about these).
When implementing a hand-coded method that will be callable through the IDO runtime, you could
add the optional IDOMethod attribute, which can be used in the future to facilitate adding the
necessary IDO metadata to make the method accessible.
IDOMethod Parameters
The IDOMethod attribute takes two optional parameters: flags and messageParm.
Flags
The flags parameter is one or more of the values defined by the MethodFlags enumeration. This
table shows the MethodFlags values:
MessageParm
The messageParm parameter is a string and is the name of the parameter that will be used to return
messages to the caller (Infobar). The parameter that is identified should be declared as a String and
passed by reference.
Remember that these attributes are not used at run time. They might be used in the future to facilitate
adding and synchronizing the IDO metadata for an extension class and its methods when an
assembly is imported.
LoadType: This is set to First, Last, Next, or Prev. First and Last are initial load types: when a
collection initially loaded, a bookmark is not needed and the framework expects either the first or
the last bunch to be returned. Next and Prev are used on subsequent loads with a bookmark, and
the framework expects the bunch either after or before the bunch identified by the bookmark. For
the Last and Prev load types (essentially, “browsing backward" through the collection), the
returned rows are expected to be sorted in reverse order.
RecordCap: This is the maximum number of rows the framework expects to be returned for a
single bunch. NOTE: The method is expected to return one extra row (RecordCap+1 rows total),
if it is available. The framework uses this information to determine whether there are more rows
available to be queried for the next bunch. The bookmark is still expected to identify uniquely the
set of rows that will be returned to the user; the extra row is not considered part of the set.
After the custom load method constructs the set of rows it is going to return, it is expected to update
the Bookmark variable with a unique value that represents the set of rows it is returning.
Custom load methods that are implemented as stored procedures receive these variables through the
use of process variables (see “Process Variables” on page 57). Before it calls into a custom load
method, the framework creates these variables from the load request that generated the call. Upon
return, the framework checks the process variable called “Bookmark” for the new bookmark. Custom
load methods that are implemented as hand-coded methods have access to the load request
structure, which contains these variables as properties of the request.
Bookmarking Algorithms
Although you must create the bookmarking algorithm for your custom load method, Infor provides
some examples.
Example 1: If you have a collection with a unique, consecutive integer row number property, your
bookmark could be a single number, and the custom load method sorts the collection by that property
and returns the top RecordCap+1 rows for a load type of First, setting the bookmark to the second-to-
last row's number. Loads of type Next return RecordCap+1 rows, where RowNumber > bookmark.
The method performs similarly for load types Last and Prev, except that it sorts in reverse order and
uses RowNumber < bookmark. The algorithm must have special cases for an empty result set, and
for a single row being returned.
Example 2: The algorithm the framework uses for standard loads is more complicated, since it must
work with any possible collection, combination of properties being loaded, etc. The bookmark is an
XML fragment with this schema:
<B>
<P><p>ColumnName1</p><p>ColumnName2</p>…</P>
<D><f>DescendingFlag1(true or false)</f><f>Flag2</f>…</D>
<F><v>FirstRowValue1</v><v>FirstRowValue2</v>…</F>
<L><v>LastRowValue1</v><v>LastRowValue2</v>…
</B>
This XML fragment is combined with the <RecordCap> and <LoadType> elements in the request.
The framework fills the bookmark with the data necessary to uniquely describe the set of rows that it
just retrieved. It uses either the RowPointer column, or a set of columns that make up a unique key,
together with a descending flag for each column, and the values of those columns in the first and last
rows of the set.
Event Description
PreLoadCollection Fires when a LoadCollection request is received.
PostLoadCollection Fires after a LoadCollection request has been processed.
PreUpdateCollection Fires when an UpdateCollection request is received.
PostUpdateCollection Fires after an UpdateCollection request has been processed.
These IDO events are available on the IDO property of the IIDOExtensionClassContext interface. To
add your handler to an IDO event you must override the ExtensionClassBase.SetContext method in
your IDO extension class and use the AddHandler keyword as shown in this example.
public override void SetContext(IIDOExtensionClassContext context)
{
// Call the base class implementation:
base.SetContext(context);
The second parameter is an instance of the IDOEventArgs class which allows you to access the
original IDO request that initiated the event, and for the Post events, the IDO response also.
public class IDOEventArgs : EventArgs
{
public PayloadBase RequestPayload { get; }
public PayloadBase ResponsePayload;
}
This table describes the contents of the IDOEventArgs parameter for each IDO event.
An event handler method can access the IDO request and response payloads as shown in this
examples.
private void HandlePreLoadCollection(object sender, IDOEventArgs
args)
{
// Get the original request:
LoadCollectionRequestData loadRequest = LoadCollectionRequestData;
loadRequest = (LoadCollectionRequestData)args.RequestPayload;
loadRequest = (LoadCollectionRequestData)args.RequestPayload;
loadResponse = (LoadCollectionResponseData)args.ResponsePayload;
updateRequest = (UpdateCollectionRequestData)args.RequestPayload;
updateResponse =
(UpdateCollectionResponseData)args.ResponsePayload;
updateArgs = (IDOUpdateEventArgs)args;
updateRequest = (UpdateCollectionRequestData)args.RequestPayload;
updateResponse =
(UpdateCollectionResponseData)args.ResponsePayload;
The ActionMask is usually a combination of Insert, Update and Delete (All), meaning the
UpdateCollection that was just performed executed all types of actions.
However, there are certain circumstances when this can be a subset of Insert, Update and Delete,
which means only the items that match the mask were actually saved. There are times when the IDO
runtime must save items in a particular order (with nested updates), and it might first process only
deleted items; then in another pass it executes all inserts and updates.
ActionMask is valid for both Pre- and PostUpdateCollection. The PreUpdateCollection parameters
are the same as the PostUpdateCollection parameters – but the action indicates which items are
about to be saved, rather than which items were just saved.
Properties
Property Description
eventName The name of the event to generate
synchronous Determines if the event handlers should be executed synchronously (True)
or asynchronously (False).
transactional Determines if the event handlers should be executed in a transaction. If
passed as False and one of the synchronous handlers fails, any database
activity performed by prior handlers remains committed.
result The value of the last RESULT() keyword executed on a Finish or Fail action
on any handler.
parameters An array of named parameters passed to the event handlers.
Example
using Mongoose.IDO;
using Mongoose.IDO.Protocol;
using Mongoose.IDO.DataAccess;
using Mongoose.Core.Common;
[IDOExtensionClass("MyIDO")]
public class TestFiringEvent : ExtensionClassBase
{
[IDOMethod(MethodFlags.None, "Infobar")]
public void FireMyEvent(string Parm1, long Parm2, ref string
Infobar)
{
ApplicationEventParameter[] ParmList = new
ApplicationEventParameter[2];
string result = null;
ParmList[0] = new ApplicationEventParameter();
ParmList[0].Name = "PString";
ParmList[0].Value = Parm1;
ParmList[1] = new ApplicationEventParameter();
ParmList[1].Name = "PNumeric";
ParmList[1].Value = Parm2.ToString();
if (!FireApplicationEvent("MyEvent", true, true, out result,
ref ParmList))
{
Infobar = result;
}
}
}
Code Samples
Caution: The examples in this section assume you are writing code in an IDO extension class that
inherits from the Mongoose.IDO.ExtensionClassBase class.
LoadCollection Examples
This sample code demonstrates executing a LoadCollection for the SLTtJobtMatPosts IDO, bringing
back the TransNum and TransSeq properties.
LoadCollectionResponseData loadResponse =
default(LoadCollectionResponseData);
loadResponse = this.Context.Commands.LoadCollection(
"SLTtJobtMatPosts",
"TransNum,TransSeq",
[filter],
string.Empty, 0);
This sample demonstrates executing a LoadCollection for the IDO that the extension class belongs to
(the current instance of the executing IDO).
LoadCollectionResponseData loadResponse = LoadCollectionResponseData;
loadResponse = this.LoadCollection(
"TransNum, EmpNum, EmpEmpType, EmpDept, DerJobPWcDept ",
[filter],
"Posted, LowLevel DESC, Job, Suffix, CloseJob, TransNum", 0);
UpdateCollection Examples
request.IDOName = "SLCustomers";
request.RefreshAfterUpdate = true;
customerItem.Action = UpdateAction.Insert;
customerItem.Properties.Add("CoNum", "C000100");
customerItem.Properties.Add("Name", "New Company");
customerItem.Properties.Add("CreditHold", 1);
request.Items.Add(customerItem);
response = this.Context.Commands.UpdateCollection(request);
loadResponse = this.Context.Commands.LoadCollection("SLCustomers",
"CoNum, Name, CreditHold", "CoNum = N'C000100'", "", 1);
if (loadResponse.Items.Count == 1)
{
request.IDOName = "SLCustomers";
request.RefreshAfterUpdate = true;
Invoke Example
This sample demonstrates invoking the JobtClsLogErrorSp method on the SLJobtCls IDO, passing
two parameters and retrieving the output value for the second parameter.
InvokeResponseData invokeResponse = new InvokeResponseData();
string message = null;
invokeResponse = this.Context.Commands.Invoke("SLJobtCls",
"JobtClsLogErrorSp", [transNum], IDONull.Value);
message = invokeResponse.Parameters[1].Value;
AppDB Class
The AppDB class, part of the Mongoose.IDO.DataAccess namespace, provides direct access to the
application database, plus access to common framework features such as application messages and
session variables. You can create a new instance of this class by calling the CreateAppDB method,
which is implemented by the ExtensionClassBase class.
AppDB db = Mongoose.IDO.IDORuntime.Context.CreateAppDB();
Application Messages
Access to translatable strings and messages stored in the application database message tables is
implemented by the AppDB class. The strings and messages that are returned are queried and
constructed according to the calling session's regional settings. Access is provided through the
IMessageProvider interface and makes use of application database messaging stored procedures
such as MsgAppSp.
Method Description
public string GetMessage( Get a string or message by message ID.
string msgID)
public string GetMessage( Get a string or message by message ID with
string msgID, substitution parameters.
params object[] args)
public string AppendMessage( Append a string or message by message ID.
string message,
string msgID)
public string AppendMessage( Append a string or message by message ID with
string message, substitution parameters.
string msgID,
params object[] args)
public string GetErrorMessage( Get a constraint error message by object name
string objectName, and type.
AppMessageType messageType)
public string GetErrorMessage( Get a constraint error message by object name
string objectName, and type with substitution parameters.
AppMessageType messageType,
params object[] args)
If you are writing code in an extension class method for a class that derives from
ExtensionClassBase, you can simply call the ExtensionClassBase.GetMessageProvider method as a
shortcut to getting a reference to the IMessageProvider interface, as shown in this example:
IMessageProvider messageProvider = null;
messageProvider = this.GetMessageProvider();
Session Variables
The AppDB class publishes these methods for manipulating session variables for the caller's session.
Method Description
public void SetSessionVariable( Set the value of a session variable.
string name,
string varValue)
public string GetSessionVariable( Get the value of a session variable.
string name)
public string GetSessionVariable( Get the value of a session variable, returning
string name, the specified default value if it does not exist.
string defaultValue)
public string GetSessionVariable( Get the value of a session variable, returning
string name, the specified default value if it does not exist,
string defaultValue, and delete it if it does exist.
bool delete)
public void Delete a session variable.
DeleteSessionVariable(
string name)
Process Variables
Process variables are similar to session variables, except the scope is tied to a single database
connection. This is unlike sessions, which span any number of database connections. A process
variable declared before one method call could be in a different scope than a later method call which
was run on a different database connection..
Method Description
public void SetProcessVariable( Create or update a process variable in the
string name, database.
string varValue)
public void SetProcessVariable( Get the value of a process variable.
string name,
string varValue,
bool ignoreError)
public string GetProcessVariable( Get the value of a process variable.
string name)
public string GetProcessVariable( Get the value of a process variable, using
string name, defaultValue if it does not exist.
string defaultValue)
Method Description
public string GetProcessVariable( Get the value of a process variable, using
string name, defaultValue if it does not exist. Delete the
string defaultValue, process variable after retrieving the value.
bool deleteVariable)
public void Delete the process variable.
DeleteProcessVariable(
string name)
Note that the AppDB instance is created as part of the Using…End Using block. This ensures that the
AppDB instance will be disposed and any resources it is holding will be released as soon as the
instance goes out of scope. See the .NET Framework documentation for more information on the
Using statement.
See the .NET Framework documentation for more information on the IDisposable interface.
Translation/Localization Considerations
Type Conversions
The built-in VB functions for data type conversions (CStr, CDate, CInt, etc.) are sensitive to the
regional settings for the application or local machine, and therefore should not be used for type
conversions in IDO extension class methods.
The framework stores all property values internally as strings regardless of their data type. In
WinStudio, this is also true for values stored in components, variables and IDO collections. The
internal string format is culture independent so the built-in string conversion functions may not work,
or may work inconsistently depending on the data or the current culture settings. The internal
formatted string value is always available, but when accessing numeric, date or Guid property values
programmatically, you should use the APIs provided by the framework that will convert the values
from internal string format to the proper “strong” data types.
// Perform LoadCollection:
// Access internal value for strings:
name = responseData[0, "Name"].Value;
Note that the name property simply gets the internal format, since string values do not need
conversion. Also note that the GetValue call for the cost property specifies an optional default value
to return if the property is null. You can also check for null values using the IsNull property.
The last line assigns a new value to the cost property. Passing in a decimal value to the SetValue
method allows the framework to perform the conversion to the internal string format automatically.
// Perform LoadCollection:
name = ThisForm.Components["NameEdit"].Value;
Note that there are individual methods for each data type, instead of a single generic method that is
supported in the IDOProtocol classes. Also, the methods all require a default value to return if the
requested value is null.
Again, the last line assigns a new value to the cost property. Passing in a decimal value to the
SetValue method allows the framework to perform the conversion to the internal string format
automatically.
appName/idoxca/configName
where:
appName is the application root folder, usually C:\Program Files\Infor\MongooseApp.
idoxca is a directory you must set up specifically for testing your application and configurations.
configName is the name of the configuration you will be using to test the DLL.
The IDO runtime checks this location first when it loads an assembly.
This might also be useful to developers working on different classes in the same assembly, since only
one developer can have an assembly checked out at a time.
You might need to discard the IDO metadata cache to force the IDO runtime to load the new version.
This section applies only if you have a Visual Studio version other than the "Express" edition.
You should now be able to set breakpoints in the Visual Studio debugger and step through code.
Example
This sample sends a message to the log each time the ValidateCreditCard method is called.
The first parameter is messageSource (String). This is the source identifier that displays in the log
viewer.
The second parameter is messageType (Mongose.IDO.UserDefinedMessageType). This is the
type identifier that displays in the log viewer.
The third parameter is message (String). This is the text of the message to be logged.
[IDOMethod(MethodFlags.None, "infobar")]
public int ValidateCreditCard(
string cardNumber,
DateTime expires,
decimal amount,
string infobar)
{
int result = 0;
return result;
}
B Debugging 26
C Dispose method 58
CollectionID property 16 E
ConfigServer.aspx page 29 EnableBookmark variable 44
G IDORequestClient.dll 28
I IIDOExtensionClassContext interface 46