EMC Developer Network

Accessing Service-based Business Objects (SBOs) from .NET

September 2004

Customization Types

SBO Access From .NET

Overview

This convenience class allows developers to access Documentum Service-based Business Objects (SBOs) from .NET languages. The class allows .NET developers to make use of the existing Java-based business objects that ship with Documentum products or are downloaded from the Component Exchange.

Software Environment

Feature Tested on
Operating System Windows 2000 Server SP4
Compiler MS Visual C# .NET Compiler version 7.10.3052.4
Runtime Environment MS .NET Runtime 1.1.4322.573
E-Content Server 5.2.5 SP1
DFC 5.2.5 SP2
DFC Primary Interop Assembly 5.2.5.12

Programming Languages

  • C#
  • Java

Dependencies

None

Architecture

Background

When programming in Java, a new SBO instance is instantiated by calling the IDfClient#newService() method. This method takes two parameters - the name of the service required and the session manager. Depending on the name of the service, the method constructs an instance of the specified SBO implementation class and returns it to the caller. When calling this method from Java, the caller can simply cast this returned instance to the appropriate SBO Java interface that the caller is expecting. However, casting does not work when IDfClient#newService() is called from a .NET language such as C# or VB.NET because the SBO interface is not known in the .NET world. The workaround to this is to invoke IDfClient#newService() from .NET using reflection.

To access an SBO from .NET the DFC Primary Interop Assembly (PIA) classes should be used everywhere except when calling the method IDfClient#newService(). Instead, this method should be invoked using reflection. This will return a COM object that represents the SBO instance. The SBO methods can then be invoked on this instance using reflection. The following code shows how this can be done,

IDfClientX clientX = new DfClientXClass();
IDfClient localClient = clientX.getLocalClient();
Type lcType = localClient.GetType();
object[] metParams = {serviceName,sessMgr};
object servObj = lcType.InvokeMember("newService",BindingFlags.InvokeMethod,null,localClient,metParams);

The servObj instance created above can then be used to make the SBO calls. For example,


Type serviceObjectType = servObj.getType();
IDfId folderid = clientX.getId("12345678");
string localFolderToImport = "c:\\devprog\\test";
object[] servMethodParams = {folderId,localFolderToImport};
IDfId newFolderId = (IDfId) serviceObjectType.InvokeMember("deepImportFolder",
             BindingFlags.InvokeMethod,null,servObj,servMethodParams);

In the above code sample, note the cast of the return type. It is only possible to cast the return type to PIA types and base .NET types such as string, int, and float. Also, only SBO methods that have these standard types can be accessed. It is not possible to access SBO methods that have custom Java classes as their arguments. For example, it is not possible to access the WebContentDownloader SBO, (available from the Component Exchange), because one of the arguments it accepts is the Java class java.net.URL.

Note: Only using the base .NET types or PIA types as arguments is an essential best practice for SBOs that may be used across Java and .NET.

Convenience Class

A convenience base class called SBOBridge has been created that wraps the above piece of code into utility methods. The public static method SBOBridge#NewService(...) creates a new service object and returns an instance of SBOBridge. This instance of SBOBridge contains the late-bound service COM object on which SBO methods can be invoked using reflection.

The SBOBridge contains another method called InvokeSBOMethod(...). It can be used to invoke methods on the contained SBO 'object'. Thus,


//Creating the deepExportService present on the component exchange
string serviceName = "com.documentum.devprog.deepexport.IDpDeepExportService";
IDfSessionManager sessMgr = ...
SBOBridge sbo = SBOBridge.NewService(serviceName,sessMgr);

//now invoke method on SBO
IDfId fldrId = clientX.getId("12345");
string localPath = "c:\\devprog\\exportTest";
string exportedLocalPath = (string)sbo.InvokeSBOMethod("deepExportFolder",fldrId,localPath);

The above code assumes that the deepExport SBO has been installed and registered in the DBOR .The SBO jar needs to be in the user CLASSPATH variable.

The SBOBridge implements the DFC's IDfService interface and provides implementation for the various methods of the IDfService interface. The implementation of these methods invokes the corresponding method on the contained service 'object'. Thus,


string version = sbo.getVersion();
string name = sbo.getName();

where getVersion() is a standard method of the IDfService interface

Creating custom accessors around existing SBOs

It is possible to subclass the SBOBridge class and provide custom wrapper methods instead of directly using the InvokeSBOMethod(..) method. This will ensure type-safety in C# and callers will be able to invoke a method whose name semantically corresponds to the operation the method is going to perform. This method could simply invoke the InvokeSBOMethod(...) or do some custom operations before invoking the SBO method. For example, the method below checks whether the filesystem path actually exists before invoking the SBO method.


class DeepExportService : SBOBridge
{

  public String deepExportFolder(IDfId folderId,String localFilesystemPath)
  {
    if(File.Exists(localFilesystemPath)
    {
      string localPath = (string) invokeSBOMethod("deepExportFolder",folderId,localFilesystemPath);
      return localPath;
    }

    return "";
  }
}

To support custom subclasses of SBOBridge, a public static method on SBOBridge called NewServiceWithClass(string serviceName,IDfSessionManager sessMgr,string assemblyFile,string className) is provided. This method instantiates a service with a .NET wrapper class specified by className contained in the assembly specified by assemblyFile. The class specified by className must be a subtype of SBOBridge. For example, the following code creates a new deep export SBO that has the previously defined .NET wrapper class DeepExportService.



string name = "com.documentum.devprog.deepexport.IDpDeepExportService";
IDfSessionManager sessMgr = ...
string className = "Documentum.Devprog.DeepExport.DeepExportService";
DeepExportService expServ = (DeepExportService)SBOBase.newService(name,sessMgr,className);
expServ.deepExportFolder(fldrId,"c:\\devprog\\test");

Disposing the SBO

The SBOBridge class or any of its subclasses will hold the late-bound SBO COM object. This COM object must be released after the service usage is over. The SBOBridge implements the IDisposable pattern and the release of the COM object happens in the Dispose() method. You can either call the Dispose() method explicitly or leave it to .NET to call Dispose() by coding with the using(...) {} paradigm.

try{..} finally{}

SBOBridge bridge = null;

try
{
  bridge = SBOBridge.NewService(...);

  //use service here

}

finally
{
  bridge.Dispose();
}


using(...){}


SBOBridge bridge = SBOBridge.NewService(...);
using(bridge)
{
  ....

}

Installation

Extract the SBOBridge.zip file into a location of your choice. The following files will be extracted:

  • Documentum.Devprog.Bof.SBOBridge.dll - This is the assembly that contains the SBOBridge class used to access SBOs from .NET. This assembly is not signed and hence cannot be added to the Global Assembly Cache (GAC). Thus, to use or reference this assembly it will need to be in one of the folders specified in the system PATH variable.
  • SBOBridgeTester.exe - This is an application used to test the SBOBridge class.
  • Documentation.zip - This file contains the HTML Help generated documentation.
  • Projects.zip - This file contains the VS.NET solution. You can open this using VS.NET and browse the source code
    • Unzip the Solution.zip into any location of your choice.
    • This should extract two folders 'SBOBridge' and 'SBOTester'
    • Open the file SBOBridge\Documentum.Devprog.Bof.sln
    • This should open up the VS.NET solution that contains two projects - SBOBridge and SBOTester

Configuration

To use the tester application, download and install the following SBOs from the Documentum Component Exchange. Make sure that their Java Archive (JARs) locations are referenced in the user CLASSPATH environment variable.

Testing

  • Make sure that the Documentum.Devprog.Bof.SBOBridge.dll assembly is in one of the directories specified in the PATH system variable or it is in the same folder as SBOBridgeTester.exe program
  • Run the SBOBridgeTester.exe program
  • Clicking on button labeled 'TestDeepExport' shows a window that accepts parameters to test the deep export service
  • Clicking on button labeled 'TestDeepImport' shows a window that accepts parameters to test the deep import service

Known Issues

None known at the time of release

Bug Submissions

If you find bugs or issues with the component, please contact developer_program@documentum.com with a short description of the issue, steps to reproduce it and the relevant software environment.