Relativity Services API (RSAPI) DTOs have been deprecated and are no longer supported. For more information and alternative APIs, see RSAPI deprecation process.

Best practices for the Services API

Use these guidelines to optimize your application development with the Services API.

This page contains the following information:

Use Relativity services or DTOs

Relativity Services API (RSAPI) DTOs have been deprecated and are no longer supported. For more information and alternative APIs, see RSAPI deprecation process.

Use of strongly typed DTOs as the preferred programming model for the Services API. DTOs provide type-safe access to common Relativity object types. In addition, they offer the benefit of consistent Field names and result datatypes. See Basic Services API concepts and RSAPI reference for .NET.

Note: While the Services API continues to support the use of the ArtifactManagerProxy as an access method, the DTOs provide similar functionality as well as these additional benefits.

Create the proxy using the Relativity API Helpers

The Relativity API Helpers simplify the creation of the RSAPIClient proxy in custom pages, event handlers, and agents by providing a helper method for this purpose. The CreateProxy() method is available on the IServicesMgr interface in the Relativity API namespace. In your code, call this method on the object returned by the GetServiceManager() method. GetServiceManager() is available on the agent, custom page, and event handler helper classes also provided in the Relativity API Helpers. This CreateProxy() method uses the ExecutionIdentity enumeration to specify the authentication type.

The ExecutionIdentity enumeration includes the CurrentUser, System, and Manual enums. The behavior of the CurrentUser and System enums differ by the context in which you use them as summarized in the following table:

Context CurrentUser enum System enum
Agent Logs in as the Service account.

Uses IntegratedAuthCredentials.
Logs in as the Service account.

Uses IntegratedAuthCredentials.
Custom page or event handler Logs in as a web user.

Uses TokenCredentials.
Logs in as the Service account.

Uses IntegratedAuthCredentials.

The Manual enum on the ExecutionIdentity enumeration requires the consumer (such as an agent or event handler) to provide a username and password at login. After creating the proxy, you must call the LoginWithCredentials() method.

You can find code samples illustrating how to use the helper method and ExecutionIdentity enumeration on the following pages:

Create the proxy within the using block in the code.

Create the Services API proxy within a using statement in your code, as in the following example:

 using (IRSAPIClient proxy = helper.GetServicesManager().CreateProxy<IRSAPIClient>(ExecutionIdentity.System))
    {
        //All operations on the Services API DTO objects must be enclosed in the using block
    }

Omit additional code for logging out or closing the session, since the RSAPIClient proxy automatically completes these tasks.

Bring back only Fields that you need for optimum performance

When you make request for all Fields on an Artifact, it increases the overhead on your application. To ensure optimum performance, don’t use the AllFields directive unless your client side-code requires every Field on an Artifact. Avoid returning Fields that your code never uses.

Don’t use the Services API to bulk-load data

Avoid or minimize the use of the Services API when loading large amounts of data into Relativity. In general, the Services API is designed for end-user application access patterns. Although it does have the ability to bulk-load data, the Services API isn’t optimized for that use case. Consider using the Import API when you have large amounts of data to load. Loading data through the Services API and Import API is complementary and can be used within the same application. Try benchmarking both approaches in your environment so that you can determine which API offers the optimum performance. See Import API.

Work in batches

Use batches to send medium-to-large data sets to the Services API. Break your create operations into batch sizes appropriate for your data and environment. Batches of 1,000 objects are far better than batches of 1 million. For example, single request to create 10,000Dynamic Objects is hard on memory and bloats your message payload. You may even reach the configured limits for maximum message size, which you want to avoid doing even though this setting can be overridden through server instance settings.

Use GUIDs to reference Fields and object types

Make your custom applications resilient by using unique identifiers (GUIDs) when referring to Fields, object types, and Choices. This approach offers significant advantages over programming against the name of an Artifact when using the Application Deployment System (ADS) to develop custom applications. It avoids name conflicts that can occur when Artifacts from a custom application are imported into a Relativity workspace, containing objects with similar names. The ADS provides the ability to rename Fields during import, since it assigns a GUID to each Artifact. While a powerful technique for working with custom applications, it also requires correct handling. The use of GUIDs simplifies development since changes in the names of Fields and object types can occur at any time.

On your development machine, you can also search the ArtifactGuid table for a workspace to find a GUID for a specific Artifact. We recommend that you add GUIDs to a constants class in your code base and use those constants in your code.

When you enable Developer mode for Relativity, you can view the GUIDs for the components in your applications. You can click the Show Component GUIDs link available on the Relativity Applications tab to view a list of GUIDs. For more information, see View component GUIDs.

You can use GUIDs to perform read, update, and delete operations on Choice, Field, ObjectType and RDOs as follows:

  • ArtifactGuid can be substituted for ArtifactID.
  • ArtifactTypeGuid can be substituted for ArtifactTypeID.

You can also use GUIDs for operations on instances of RDOs:

  • Create - ArtifactTypeGuid can be substituted for ArtifactTypeID or ArtifactTypeName.
  • Read, update, and delete - ArtifactGuid can be substituted for ArtifactID.

For code samples, see RDO.

Install and uninstall applications through the ADS

When building your application, take advantage of the ADS provided by Relativity. The ADS is designed for packaging your schema into an application and deploying it to the workspace you are developing against. While you can create object types and Fields using the Services API, this system provides powerful tools for setting up your schema in a workspace. For information about administering Relativity applications, see Relativity applications on the Relativity Documentation site.

Use the APIOptions token property

With the inclusion of the APIOptions as a property on the RSAPIClient class, you don't need to explicitly track the token returned from the Login(), LoginWithCredentials(), or TokenLogin() method. A successful call to either of these methods automatically populates the Token property of the APIOptions property.

Note: The Token property is automatically populated with a token value when the user is authenticated so you don’t need to explicitly call a login method. However, if you want to switch to another user, you can call one of the login methods to authenticated the new user.

See the following code sample:

try {
     proxy.Login();
} catch (Exception ex) {
     throw new Exception(String.Format("An error occurred logging in: {0}", ex.Message), ex);
}
Console.WriteLine("APIOptions.Token is {0}", proxy.APIOptions.Token);
        

The result of the call to Login() method isn't explicitly stored, and it is automatically available via the Token property of APIOptions.

Avoid specific version assembly references

When you are developing with a reference to the kCura.Relativity.Client assembly, avoid using the Specific Version reference on the Reference Properties window in Visual Studio.

Visual Studio assembly properties

When a custom assembly is loaded for an event handler, agent, or custom page, common .dll files (such as kCura.Relativity.Client.dll) are automatically copied into the domain from the lib folder. If you set the Specific Version option in Visual Studio, it may not match the version of the .dll files installed on the environment. This mismatch may prevent your application from executing properly, if at all.

Note: Don't package the kCura.Relativity.Client.dll with your application. If you package this .dll file with your application, it may be overwritten or ignored when you deploy the application in Relativity.

Use constant Field names for Read() and Query() methods

When calling the Read() and Query() methods on DTOs, you can reference the constant strings assigned to Field names. See Constant Field names

You can also use the AllFields directive while in the development phase to discover available Fields: FieldValue.AllFields.

Use Services API enumerations or constants

The Services API provides enumerations and constants that you can use instead of strings or integers in your code. For example, this code illustrates how to use the constant DescriptorArtifactTypeID on the ObjectTypeFieldNames class instead of the string "Descriptor Artifact Type ID":

objectTypeQuery.Condition = 
     new WholeNumberCondition(ObjectTypeFieldNames.DescriptorArtifactTypeID, NumericConditionEnum.EqualTo, 1000035);
        

For more information, see ArtifactType under the kCura.Relativity.Client namespace, or ObjectTypeFieldNames under the kCura.Relativity.Client.DTOs namespace in the Services API class library.

Use await/async pattern

When calling the Services API asynchronous methods, use the async/await pattern. The async/await pattern leverages asynchronous support in the .NET Framework 4.5 and the Windows Runtime. It allows you to easily implement asynchronous processing while retaining a logical structure that resembles synchronous code.

These best practices are recommended when using the async and await pattern:

Use Task.FromResult()

If you have a raw value that needs to be returned from an async method, you can use the Task.FromResult() helper method for convenience.

The following code:

var response = await Task.Run(() => result).ConfigureAwait(false);  // Verbose
return response;

Can be shortened to:

return Task.FromResult(result);  // Good

Task.FromResult creates a task that is immediately fulfilled with the value of “result.” Make sure you return concrete values instead of blocking on a method as in the following example:

return Task.FromResult(SomeSlowMethod());  // Bad - doesn’t return a task to the caller right away

Don’t fire-and-forget your tasks

When you instantiate a new Task object, make sure that task is properly monitored. The following example illustrates the problem:

private void Save()
{
    //Do something 
    …

Task.Run(() => engine.UpdateData(foo));  // BAD – we spin a Task into the .NET ether

    //Do something else
    …

}

Notice that we instantiate a new task, but we don’t bind that task to a variable. That means we are spinning off a background task that is not attached to anything. This code will crash in a web app. If ASP.Net finishes the HTTP request and rips down the HTTPContext before your task is complete, this will cause an error.

When you create a task, you should always do something with that task:

Use ConfigureAwait() only with clear purpose

ConfigureAwait() is a useful tool, but it serves two very specific purposes:

  1. Improves performance.
  2. Prevents deadlocks with blocking code.

For the deadlock scenario there are situations where mixing async/await and Task.Result can create a deadlock in ASP.Net. Therefore, don’t use ConfigureAwait() unless there a specific need and you are explicitly choosing to use it.