Relativity Services API Guide - Relativity Developer Documentation

Transcription

Relativity Services API Guide - Relativity Developer Documentation
Services API Guide
Version 8.1 | October 11, 2013
For the most recent version of this document, visit our Relativity 8.1 Developers website.
Table of Contents
1 Relativity Services API
9
2 Configuring the Services API
9
2.1 Configuration prerequisites
9
2.2 SSL certificate for HTTPS
10
2.3 SSL certificate for HTTP or Net.TCP
10
2.4 Creating a self-signed certificate
12
2.5 Configuring HTTP or HTTPS connectivity to IIS
13
2.5.1 Verifying HTTP and HTTPS site bindings
14
2.6 Configuring Net.Pipe or Net.TCP connectivity
16
2.6.1 Enabling non-HTTP activation for WCF
16
2.6.2 Configuring the Net.Pipe or Net.TCP protocols
17
2.6.3 Verifying Net.Pipe and Net.TCP site bindings
18
2.6.4 Starting the Net.Pipe or Net.TCP listener adapter service
18
2.7 Manually configuring the Services API for the Relativity platform
18
2.8 Configuration overrides
19
2.8.1 Setting client configuration overrides
19
2.8.2 Setting server configuration overrides
20
2.8.3 Server-side override values
22
2.8.4 Override configuration references
24
2.9 Testing the Services API configuration
25
2.9.1 Relativity Services API Diagnostic Tool
25
2.9.2 Viewing errors in the Services API Diagnostic Tool
28
2.10 Troubleshooting the Services API Configuration
30
2.10.1 Logging and debugging settings in the web.config
31
2.10.2 Production environment trace settings
31
2.10.3 Test environment trace settings
32
2.10.4 FailureAuditing Configuration Override Setting
33
2.10.5 Attempting to access .svc file causes keyset error
33
2.10.6 Catching EndpointType exceptions
34
2.10.7 Connection errors in load-balanced systems
34
2.10.8 Could not load type 'System.ServiceModel.Activation.HttpModule'
34
2.10.9 Erroneous calls to internal web server in load-balanced systems
35
2.10.10 HTTP error 404.17 or 404.3
35
2.10.11 Incorrect version of .NET enabled for application pools
36
Relativity | Services API Guide - 2
2.10.12 Missing handler mappings
36
2.10.13 Pipe endpoint could not be found
38
2.10.14 System.ServiceModel.ExceptionDetail Error
38
2.10.15 Unable to access .svc file path in browser
38
2.10.16 Unable to access website
39
2.10.17 Updating the HTTP host header
39
3 Upgrading the Services API
3.1 Upgrading from Relativity 8
39
39
3.1.1 Upgrade guidelines for the Relativity 8.1
39
3.1.2 Upgrade guidelines from the Relativity 8.0.291.1 patch release
40
3.2 Upgrading from Relativity 7.5
41
3.3 Upgrading from Relativity 7.4 and earlier
42
4 Getting started with the Services API
42
4.1 Prerequisites for a development environment
42
4.2 Services API materials available in the SDK Installer
42
4.3 Setting up a project in Visual Studio
43
4.4 Creating a simple program with the Services API
45
4.4.1 Before you begin
45
4.4.2 Adding directives for required namespaces
46
4.4.3 Adding the Main method
46
4.4.4 Creating the RSAPIClient proxy
47
4.4.5 Querying for a Workspace
48
4.4.6 Creating a Relativity Dynamic Object DTO
49
4.4.7 Creating a Field on a RDO
50
4.4.8 Updating Fields on an RDO
51
4.4.9 Reading an RDO
52
4.4.10 Querying for RDOs
53
4.4.11 Deleting a Field on an RDO
54
4.4.12 Deleting an RDO
54
4.4.13 Exiting the program
55
4.4.14 Writing success and failure messages
55
4.4.15 Building and running the program
56
5 Basic Services API concepts
57
5.1 Services API features
57
5.2 Services API and the Relativity Platform
58
Relativity | Services API Guide - 3
5.3 Client Proxy
5.3.1 Backwards Compatibility
5.4 Deploying the Services API
59
59
60
5.4.1 Deploying the Services API
60
5.4.2 Transport protocols
60
5.4.3 AuthenticationType classes supported by the RSAPIClient
60
5.4.4 Summary of authentication methods and endpoint types
61
5.5 Creating the RSAPIClient proxy
61
5.5.1 RSAPIClient class overview
61
5.5.2 APIOptions class
62
5.5.3 RSAPIClientSettings class
62
5.5.4 RSAPIClientServiceOperationFailed event
62
5.5.5 Best practices for proxy creation
62
5.5.6 Creating the proxy in an agent, custom page, or event handler
63
5.5.7 Code samples for proxy creation in a console application
63
5.6 Token login
65
5.6.1 Creating the proxy using a token
65
5.6.2 Generating an authorization token for Relativity
66
5.7 Data Transfer Objects (DTOs)
67
5.7.1 DTO Features
67
5.7.2 Supported DTOs
68
5.8 Untyped base Artifacts
69
5.8.1 RSAPIClient support for ArtifactTypes
69
5.8.2 Limited support for Create() on Fields
70
5.8.3 Field (untyped)
70
5.9 StrictMode property and Field directives
73
5.9.1 StrictMode property for DTOs
73
5.9.2 Field directives for DTOs
73
5.9.3 StrictMode and the TextIdentifer property (untyped layer)
74
5.9.4 Field directives (untyped layer)
74
5.10 Best practices for the Services API
75
5.10.1 Use DTOs whenever possible
75
5.10.2 Bring back only Fields that you need for optimum performance
75
5.10.3 Don’t use the Services API to bulk-load data
75
5.10.4 Work in batches
75
Relativity | Services API Guide - 4
5.10.5 Use GUIDs to reference Fields and object types
75
5.10.6 Install and uninstall applications through the ADS
76
5.10.7 Use of the APIOptions token property
76
5.10.8 Avoid specific version assembly references
76
5.10.9 Use constant Field names for Read() and Query()methods
77
5.10.10 Use Services API enumerations or constants
77
5.11 GUIDs in application development
78
5.11.1 Using GUIDs as best practice
78
5.11.2 Using GUIDs in read, update, and delete operations
78
5.11.3 Viewing GUIDs for your application components
78
5.12 Asynchronous framework
78
5.13 Terminology
79
6 DTO reference and code samples
6.1 Batch
81
82
6.1.1 Updating and reading a Batch
82
6.1.2 Querying for a Batch
84
6.2 BatchSet
85
6.2.1 Creating, updating, and querying BatchSet objects
85
6.2.2 Creating and deleting a BatchSet
88
6.2.3 Creating Batches for a BatchSet
90
6.2.4 Querying for a Batch Set
91
6.2.5 Canceling the creation of a BatchSet
91
6.2.6 Purging Batches for a BatchSet
93
6.2.7 Event handlers used in code samples
94
6.3 Choice
95
6.3.1 Reading a Choice
95
6.3.2 Querying on a Choice
96
6.4 Client
97
6.4.1 Creating a Client
97
6.4.2 Reading a Client
98
6.4.3 Updating a Client
100
6.4.4 Deleting a Client
101
6.4.5 Querying for a Client
102
6.5 Document
6.5.1 Fields on a Document DTO
Relativity | Services API Guide - 5
103
103
6.5.2 Creating a Document
103
6.5.3 Reading a Document
105
6.5.4 Updating a Document
106
6.5.5 Deleting a Document
108
6.5.6 Querying for a Document
109
6.5.7 Downloading a native file
111
6.6 Error
6.6.1 Writing to the error log
6.7 Field
112
112
113
6.7.1 System type fields
113
6.7.2 Field types
114
6.7.3 Supported operations for Field types
128
6.7.4 Field code samples
128
6.7.5 File field
135
6.7.6 Fields used by Field type, User, and Group
141
6.7.7 Constant Field names
146
6.8 Folder
153
6.8.1 Creating a Folder
153
6.8.2 Reading a Folder
154
6.8.3 Deleting a Folder
155
6.8.4 Querying for a Folder
157
6.9 Group
158
6.9.1 Creating a Group
158
6.9.2 Reading a Group
159
6.9.3 Updating a Group
160
6.9.4 Deleting a Group
161
6.9.5 Querying for a Group
162
6.10 Layout
163
6.10.1 Reading a Layout
164
6.10.2 Querying for a Layout
165
6.11 MarkupSet
166
6.11.1 Creating a MarkupSet
166
6.11.2 Reading a MarkupSet
167
6.11.3 Updating a MarkupSet
168
6.11.4 Deleting a MarkupSet
169
Relativity | Services API Guide - 6
6.11.5 Querying for a MarkupSet
6.12 ObjectType
170
172
6.12.1 Creating an ObjectType
172
6.12.2 Reading an ObjectType
173
6.12.3 Updating an ObjectType
174
6.12.4 Deleting an ObjectType
175
6.12.5 Querying for an ObjectType
176
6.13 RDO
177
6.13.1 Creating an RDO
177
6.13.2 Creating an RDO as a child object
179
6.13.3 Reading an RDO
180
6.13.4 Updating an RDO
182
6.13.5 Deleting an RDO
183
6.13.6 Querying for an RDO
184
6.14 RelativityApplication
186
6.14.1 Reading a RelativityApplication
186
6.14.2 Deleting a Relativity Application
187
6.14.3 Querying for a RelativityApplication
188
6.15 RelativityScript
189
6.15.1 Reading a RelativityScript
190
6.15.2 Querying for a RelativityScript
191
6.15.3 Executing a RelativityScript
192
6.15.4 Retrieving Input for a RelativityScript
195
6.16 Tab
196
6.16.1 Reading a Tab
196
6.16.2 Querying for a Tab
197
6.17 User
198
6.17.1 Creating a User
198
6.17.2 Utility methods used in User DTO creation
201
6.17.3 Reading a User
203
6.17.4 Updating a User
204
6.17.5 Deleting a User
206
6.17.6 Querying for a User
206
6.18 View
6.18.1 Reading a View
Relativity | Services API Guide - 7
207
208
6.18.2 Querying for a View
6.19 Workspace
209
210
6.19.1 Reading a Workspace
210
6.19.2 Querying for a Workspace
211
7 Additional Services API functionality
7.1 File transfers
212
212
7.1.1 Supported file transfer operations
212
7.1.2 File transfer error messages
213
7.1.3 Error classes
213
7.1.4 Sample error handling code
214
7.2 Mass processes
7.2.1 Mass delete operations
7.3 Querying
215
223
227
7.3.1 Using Query objects
227
7.3.2 Available Conditions for Querying
227
7.3.3 System Types supported by the Query() method
228
7.3.4 Paging
228
7.3.5 Constraints on the Query() method
229
7.3.6 SavedSearchCondition
229
7.3.7 Specialized queries with Conditions
231
7.3.8 ViewCondition
233
8 Troubleshooting the Services API
236
8.1 Common causes of Services API errors
236
8.2 Error occurs when machines in a workgroup attempt to log in
237
Relativity | Services API Guide - 8
1 Relativity Services API
The Services API supports the development of customized end-user applications that interact with Relativity.
It simplifies the development process by providing object classes and other data structures that are the
building blocks for custom applications.
2 Configuring the Services API
The Services API is installed on the Relativity web server as an additional IIS application called
Relativity.Services. When you install Relativity on your web server, the installer automatically configures the
Services API to use Net.Pipe.
Note: You don’t need to complete any additional configuration steps for the Services API unless you want
to use HTTP, HTTPS, or TCP as the scheme, or customize the client and server configuration settings. You
may also need to configure Net.Pipe on the IIS if you ran the Relativity installer before rebooting your
machine after Windows updates were installed.
Most of the configuration of Relativity.Services is determined by the settings in the web.config file of the
Relativity.Services virtual directory. A few of the configuration options are controlled in IIS. The configuration
process includes configuring settings in IIS, testing the connectivity to the Services API, and troubleshooting
the configuration settings.
2.1 Configuration prerequisites
Before you begin configuring the Services API, you will need to complete the following tasks:
n
n
Confirm that Relativity has been installed in your environment, and that the Services API has been
installed as part of the web server component of Relativity.
Determine the scheme that you want to use, such as HTTP, HTTPS, or TCP. You will also need to select
an authentication method, such as username/password or Windows credentials. The Services API can
use a different authentication scheme than other Relativity components installed on the same web
server.
Note: You don't need to complete any configuration steps if you use Net.Pipe as installed on the IIS when you
run the Relativity installer.
n
Obtain a valid SSL certificate based on these requirements:
o
o
HTTPS - If you're using this scheme, you must have a certificate.
Username/password over HTTP or username/password over Net.TCP - If you're defining the
CertificateFindValue in the web.config file on the server, you need a certificate for these
schemes. Otherwise, you don't need a certificate.
Note: Make sure that the Subject Name on the certificate is unique.
Relativity | Services API Guide - 9
2.2 SSL certificate for HTTPS
You need to obtain a SSL certificate if you are going to use HTTPS.
1. Obtain a digital certificate that meets the following requirements:
Make sure that you have a trusted certificate. You can use a certificate issued from a valid certificate authority or a self-signed certificate.
n Matches the domain where Relativity Services is installed
n Must be current (You can’t use an expired certificate.)
2. Ensure there is a properly configured HTTPS binding. See Configuring HTTP or HTTPS connectivity to IIS
on page 13.
n
2.3 SSL certificate for HTTP or Net.TCP
If you're defining the CertificateFindValue in the web.config file on the server, you need a certificate for these
authentication schemes:
n
n
Username/password over HTTP
Username/password over Net.TCP
Note: If you aren't setting CertificateFindValue in the web.config file, you don't need to complete the
following steps.
Complete the following steps to configure an SSL certificate for username/password over HTTP.
1. Create or import a certificate. Use the instructions available on the Microsoft website for one of the following methods:
n
n
Import a certificate from another source into IIS 7 (http://technet.microsoft.com/en-us/library/cc732785(v=ws.10).aspx)
Create a self-signed certificate in IIS 7 (http://technet.microsoft.com/en-us/library/cc753127
(v=ws.10).aspx)
Note: If you use another method to install the certificate, add it to the Personal store for the local
machine but not the Personal store for the current user. (.NET refers to this location as My store.) You
will need the Subject Name value on the certificate when you configure IIS.
2. Complete the following steps to configure the server to use the certificate:
a. Locate the web.config file for the Services API. The default directory is listed below:
<YourInstallationDirectory>\kCura Corporation\Relativity\Relativity.Services
b. In this file, set the value for the CertificateFindValue key to the Subject value on the certificate.
See the following example:
<kCura.CommonServiceValues.Config>
Relativity | Services API Guide - 10
<add key="CertificateFindValue" value="myServer.kcura.com"/>
</kCura.CommonServiceValues.Config>
As displayed in IIS, the value myServer.kcura.com matches the value for the Subject in the
certificate:
Note: Make sure that the Subject value (or name) is unique in your environment. When multiple
certificates with the same name exist, the Services API can’t determine the correct one to use. You can
view certificates in IIS, which displays the Subject in the Issued To column on Server Certificates pane.
c. (Optional) Override specific configuration settings in the web.config file as required for your environment. See Configuration overrides on page 19.
3. Complete the following steps to configure the client to use the certificate:
a. Ensure that the CertificateFindValue corresponds to the value for the CertificateFindValue key
specified in the web.config file on the server. (A CertificateFindValueInvalidException is thrown
when a mismatch occurs between the CertificateFindValue defined on the server and the client.)
b. Determine if you need to set the CertificateFindValue. If this value is set on either the client or
the server, then you must configure it on the other entity. (You can't configure only one of these
entities. If the CertificateFindValue on the client is set, then you must configure it on the server,
and vice versa.) See Configuration overrides on page 19.
Relativity | Services API Guide - 11
Note: The client won't validate the certificate by default. However, you can control this behavior by
updating the CertificateValidation setting.
4. Configure IIS to require SSL on the Relativity.Services virtual directory. See Configuring HTTP or HTTPS
connectivity to IIS on the next page.
5. Confirm endpoint connections. See Testing the Services API configuration on page 25.
2.4 Creating a self-signed certificate
For development purposes, you can create self-signed certificates with a utility included in the . The Self
Signed Certificate Creator is available Tools folder of your Relativity SDK installation.
Note: Don't use the certificates created with this utility in your production environment. These certificates
are for development purposes only.
1. Locate Tools folder of your Relativity SDK installation. The following path is default location:
...\Program Files\kCura Corporation\Relativity SDK\RSAPI\Tools
2. Click CertificateCreatorForm.exe to open the application.
3. Enter the following information required to create a certificate:
n
n
Friendly Name - Enter a name for the certificate that you want to use for identification purposes.
The Friendly Name is used for your convenience to make it easier to distinguish between different certificates.
Machine Name - Enter the name of the machine that will be used as the Subject field on the certificate. Use a value that is appropriate for a self-signed certificate. You can update this value, if
necessary. This value will also be displayed in the Issued To column.
Relativity | Services API Guide - 12
Note: If you are unsure about how to set the Machine Name, don't use this tool to create a certificate.
# Years Valid - Enter the number of years from the creation date that you want the certificate to
be valid.
4. Click Create Certificate. You will see your new certificate listed in the Current Certificates box. This list
includes the same set of certificates available on IIS. It is populated from information in the Local
Machine\Personal certificate store in Windows.
n
2.5 Configuring HTTP or HTTPS connectivity to IIS
You must configure IIS hosting Relativity.Services to use anonymous authentication, since the authentication
occurs within Relativity rather than on the web server itself.
1. On the web server, log on as a member of the Administers group.
2. Open IIS Manager.
3. Under the Sites node, select the Relativity.Services virtual directory.
4. Double-click on Authentication.
5. Verify that only Anonymous Authentication is enabled. The Services API requires that only Anonymous Authentication is enabled, and that all other authentication methods are disabled. However, you
can use the other authentication methods for other Relativity components.
Relativity | Services API Guide - 13
6. If you are using HTTPS with username/password or HTTPS with Windows authentication, verify that
HTTPS binding is configured on the Relativity.Services virtual directory. See Verifying HTTP and HTTPS
site bindings below.
Note: You must have an SSL certificate installed and configured for the website that is trusted by calling clients.
It must be installed at the website level.
7. If you are using HTTP with username/password authentication, complete the following steps to disable SSL on the Relativity.Services virtual directory:
a. Click the SSL Settings option for the Relativity.Services virtual directory.
b. Double-click on SSL Settings.
c. Verify that Require SSL is cleared.
8. Complete the steps in Testing the Services API configuration on page 25.
2.5.1 Verifying HTTP and HTTPS site bindings
Use these steps to verify the site bindings for the HTTP or HTTPS protocols that you have configured on your
server.
Relativity | Services API Guide - 14
1. On the web server, open IIS Manager.
2. In IIS Manager Connections pane, expand Sites.
3. Right - click on Default Web Site.
4. In the right-click menu, click Edit Bindings to display the Site Bindings dialog.
5. Verify the information for the HTTP or HTTPS protocol that you are using. For HTTPS, you will need to
ensure that the SSL certificate is valid. Click Edit to view the SSL certificate assigned to the site binding.
Relativity | Services API Guide - 15
6. Click Close.
2.6 Configuring Net.Pipe or Net.TCP connectivity
You can configure the following types of connections to IIS:
n
n
n
Net.Pipe with Windows authentication
Net.TCP with username/password authentication(If you are using Net.TCP with username/password
authentication and defining the CertificateFindValue in the web.config file, you must install an SSL certificate. See SSL certificate for HTTP or Net.TCP on page 10.)
Net.TCP with Windows Authentication
Note: When you install Relativity on your web server, the installer automatically configures the Services API
to use Net.Pipe. However, you may need to configure Net.Pipe on the IIS if you ran the Relativity installer
before rebooting your machine after Windows updates were installed.
2.6.1 Enabling non-HTTP activation for WCF
Use these steps to set the Non-HTTP Activation option in the Windows Server Manager:
1.
2.
3.
4.
On the web server, log on as a member of the Administers group.
In the Control Panel, open Windows Server Manager.
Open the Add Features Wizard.
Under WCF Activation, select Non-HTTP Activation.
Relativity | Services API Guide - 16
5. Complete the steps in Configuring the Net.Pipe or Net.TCP protocols below.
2.6.2 Configuring the Net.Pipe or Net.TCP protocols
You can configure Net.Pipe or Net.TCP protocols by using a binding configuration. For more information, see
NamedPipe Activation (http://msdn.microsoft.com/en-us/library/ms752253.aspx).
1.
2.
3.
4.
5.
On the web server, log on as a member of the Administers group.
Open IIS Manager.
Under the Sites node, expand the Default Web Site.
Right-click on the Relativity.Services virtual directory.
Point to Manage Application and click Advanced Settings.
6. Add the Net.Pipe or Net.TCP protocol to the Enabled Protocols box, if necessary.
Relativity | Services API Guide - 17
7. Click OK.
8. Complete the steps in Verifying HTTP and HTTPS site bindings on page 14.
2.6.3 Verifying Net.Pipe and Net.TCP site bindings
Use these steps to verify the site bindings for the Net.Pipe or Net.TCP protocols that you have configured on
your server.
1.
2.
3.
4.
On the web server, open IIS Manager.
In IIS Manager Connections pane, expand Sites.
Click Default Web Site.
In the Actions pane, click Bindings to display the Site Bindings dialog.
5. Verify the information for the protocol that you are using:
Net.Pipe Protocol - Only one net.pipe entry exists in the list of binding types.
Net.TCP Protocol - Only one net.tcp entry exists in the list of binding types.
6. Click Close.
7. Complete the steps in Starting the Net.Pipe or Net.TCP listener adapter service below.
n
n
2.6.4 Starting the Net.Pipe or Net.TCP listener adapter service
Use these steps to start the service:
1. On the web server, open Services from Administrative Tools.
2. Verify that the Net.Pipe Listener Adapter or the Net.Tcp Listener Adapter service is running. If not,
right-click on the service and click Start.
3. Complete the steps in Testing the Services API configuration on page 25.
2.7 Manually configuring the Services API for the Relativity platform
If you need to configure the Services API manually, use these guidelines to set up components available with
the Relativity 8.1 platform.
Agents
n
n
Services API Hosting - Self-hosted or on IIS (if available on your server)
Relativity.Services URL - Use method on Relativity API Helpers to return URL.
Relativity | Services API Guide - 18
n
n
Transport Protocol - Net.Pipe
Authentication method - We recommend Windows authentication over token authentication, which
has increased overhead.
Custom pages or event handlers (except Pre and Post Install)
n
n
n
n
Services API Hosting - Locally through IIS. The Relativity installer automatically adds the Services API to
the web server. (Pre and Post Install event handlers don’t require a connection to the Services API.)
Relativity.Services URL - Use method on Relativity API Helpers to return URL.
Transport Protocol - Net.Pipe
Authentication method – Use Windows authentication for full access as the service account or use
token authentication for an audited, secure, and user-aware context.
Pre and Post Install event handlers
n
n
n
n
Services API Hosting - Self-hosted or on IIS (The method for hosting the Services API depends on
whether an agent or Procuro runs the Pre and Post event handlers, or whether they are run from the
web server.)
Relativity.Services URL - Use method on Relativity API Helpers to return URL.
Transport Protocol - Net.Pipe
Authentication method – Use Windows authentication for full access as the service account.
Applications
Services API Hosting - Host remotely.
Note: Due to certificate issues, the Services API shouldn't be hosted remotely for agents, custom pages,
and event handlers. If you must use this configuration, use HTTPS as the transport protocol. In addition,
use Windows authentication for full access as a service, or use Active Directory authentication by calling the
LoginWithCredentials() method, and passing a username and password.
2.8 Configuration overrides
You can use configuration overrides to enter custom values for endpoint configurations. In general, you will
probably not need to override the default configuration values.
2.8.1 Setting client configuration overrides
Client configuration settings override single values. However, they don’t override all configuration values as a
custom service and endpoint configuration would. You can programmatically apply configuration overrides in
a client-side application by using the RSAPIClientSettings class.
The available client configuration overrides share the same name as server-side configuration overrides. Even
though the names are the same, these values apply only to either the server or the client. Configuration
issues may occur if a value configured on the client-side conflicts with that configured on the server-side, or
vice versa. Ensure that the configuration override values on the client and server match.
To modify configuration settings programmatically, override the properties available on the
RSAPIClientSettings class. The following code sample illustrates how to set a CertificateFindValue value:
RSAPIClientSettings settings = new RSAPIClientSettings();
Relativity | Services API Guide - 19
settings.CertificateFindValue = "myServer.myCompany.com";
The following list includes the available override settings for the client:
CertificateFindValue
n
n
Datatype - String
Description - Specifies the Subject Name value used to identify the server-side certificate. This clientside value must match the server-side value exactly. The value is case-sensitive. The default value is
String.Empty.
Note: This setting applies only to username/password over HTTP and username/password over Net.TCP
endpoint types.
CertificateValidation
n
n
Datatype - Boolean
Description - Determines whether the client validates the server certificate that the CertificateFindValue
specifies.
Note: This setting applies only to username/password over HTTP and username/password over Net.TCP
endpoint types.
2.8.2 Setting server configuration overrides
You can configure single value or service-wide overrides on the server hosting the Services API. You can use
single override values for all 4 of the services: Authentication, DataManipulation, FileTransfer, and
SetExecutor. These override values are configured in the kCura.Authentication.Config,
kCura.DataManipulation.Config, kCura.FileTransfer.Config, and kCura.SetExecutor.Config sections,
respectively. An additional configuration section called kCura.CommonServiceValues.Config contains
configuration values that apply equally to all services.
1. Navigate to the Services API web.config in the following directory on the server:
<YourInstallationDirectory>\kCura Corporation\Relativity\Relativity.Services
2. Open the web.config in a text or other editor.
3. Locate the <configSections>…</configSections> tags in the file.
4. Define the configuration override settings for each of the configuration sections between these tags.
See the following example:
<configSections>
<section name="kCura.Config" type="System.Configuration.DictionarySectionHandler,
System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="kCura.Authentication.Config"
type="System.Configuration.DictionarySectionHandler, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
Relativity | Services API Guide - 20
<section name="kCura.DataManipulation.Config"
type="System.Configuration.DictionarySectionHandler, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="kCura.FileTransfer.Config"
type="System.Configuration.DictionarySectionHandler, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="kCura.SetExecutor.Config"
type="System.Configuration.DictionarySectionHandler, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="kCura.CommonServiceValues.Config"
type="System.Configuration.DictionarySectionHandler, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="customBasicAuthentication"
type="Thinktecture.CustomBasicAuthentication.CustomBasicAuthenticationSection,
Thinktecture.CustomBasicAuthenticationModule"/>
</configSections>
<kCura.Config>
<add key="encryptedConnectionString" value="…"/>
</kCura.Config>
<kCura.CommonServiceValues.Config>
<add key="ExceptionDetailsInFaults" value="true"/>
</kCura.CommonServiceValues.Config>
<kCura.Authentication.Config>
</kCura.Authentication.Config>
<kCura.DataManipulation.Config>
</kCura.DataManipulation.Config>
<kCura.FileTransfer.Config>
</kCura.FileTransfer.Config>
<kCura.SetExecutor.Config>
</kCura.SetExecutor.Config>
5. Add override settings under configuration sections as necessary:
<add key=”OverrideName” value=”OverrideValue”/>
Replace OverrideName and OverrideValue with the appropriate override key and value as illustrated
below:
<add key=”ExceptionDetailsInFaults” value=”false”/>
Relativity | Services API Guide - 21
Note: An error will be thrown if a key exists in a section of the configuration file where it doesn't belong. For
example, ExceptionDetailsInFaults is only valid in kCura.CommonServiceValues.Config, so an error will be
thrown if it is incorrectly placed in kCura.Authentication.Config. Verify that you don't have any typographical
errors in the key. Keys are case sensitive.
2.8.3 Server-side override values
The following list includes the available override settings for each service.
CertificateFindValue
n
n
n
Datatype - String
Description - Username/password over HTTP or username/password over Net.TCP endpoint configurations requires a certificate to secure the contents of the message. The location of this certificate is
specified as the local machine, while it is the store titled My that is searched. The CertificateFindValue
specifies the value to look for in the Subject Name of the certificate. For example, if you used IIS to create a self-signed certificate on a machine residing at myMachine.domain.corp, then specify
myMachine.domain.corp as the CertificateFindValue. This value is case-insensitive. The default value is
String.Empty for both services.
Sections - kCura.CommonServiceValues.Config
Note: This setting applies only to username/password over HTTP and username/password over Net.TCP
endpoint types.
ExceptionDetailsInFaults
n
n
n
Datatype - bool
Description - Determines how to report exceptions to the client. When set to false (default), detailed
exception information isn't reported to the client. When set to true (enabled), the server sends detailed
information. The recommendation is to enable this flag only for debugging during development. The
default value is False.
Sections - kCura.CommonServiceValues.Config
FailureAuditing
n
n
n
Datatype - bool
Description - Set this value to True if you want to audit failed security events from WCF. Audited security events include transport, message, or negotiate authentication and authorization events. You can
view these events in the Windows Event Viewer, since they are written to Windows event log. The
default value is True.
Sections - kCura.CommonServiceValues.Config
MaxArrayLength
n
n
n
Datatype - Integer
Description - Determines the maximum array length created and returned at various stages of message
processing. The default value for FileTransfer is Int.MaxValue, and for all other services, it is 1000000.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxBufferSize
n
Datatype - Integer
Relativity | Services API Guide - 22
n
n
Description - Specifies the maximum buffer size (in bytes) used to store messages in memory. If more
data is received than can fit in the buffer, it remains on the underlying socket until there is enough
space. This value should match the MaxReceivedMessageSize. The default value for FileTransfer is
Int.MaxValue, and for all other services, it is 104857600.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxBufferPoolSize
n
n
n
Datatype - Long
Description - Specifies the maximum buffer pool size (in bytes) used by the BufferManager. As messages are received, buffers are required to process them as they come out of the channel. If the BufferManager has insufficient memory, additional memory must be allocated. The default value for
FileTransfer is Int.MaxValue, and for all other services, it is 104857600.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxChunkSize
n
n
n
Datatype - Long
Description - Specifies the maximum size of each chunk (in bytes) used during a file transfer operation.
Since the client requests a chunk size when starting an upload or download, MaxChunkSize sets an
upper limit. This value used as the chunk size if the client doesn't specify a size. Larger chunk sizes
require fewer messages to transfer a file. If a message must be sent again, it will take longer amount of
time as compared to a smaller message. If this value is smaller than MinChunkSize, MinChunkSize is
treated as the maximum and this value becomes the minimum. The default value is 262144.
Section - kCura.FileTransfer.Config
MinChunkSize
n
n
n
Datatype - Long
Description - Specifies the minimum size of each chunk (in bytes) used during a file transfer operation.
Since the client requests a chunk size when starting either an upload or download, MinChunkSize sets a
lower limit. Smaller chunk sizes take less time to re-send in the case of a temporary failure, and also result in the need to send more messages. If this value is larger than MaxChunkSize, MaxChunkSize
becomes the new minimum and this value becomes the maximum. The default value is 8192.
Section - kCura.FileTransfer.Config
MaxConcurrentCalls
n
n
n
Datatype - Integer
Description - Specifies the maximum number of messages allowed to be processed at any given time by
a particular ServiceHost instance. The default value is 100.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxConcurrentInstances
n
n
n
Datatype - Integer
Description - Specifies the maximum number of instances of the service. If messages arrive while this
limit is reached, the messages are held until resources are available. The default value is 200 for all services.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
Relativity | Services API Guide - 23
MaxConcurrentSessions
n
n
n
Datatype - Integer
Description - Specifies the maximum number of service sessions. This value should match MaxConcurrentInstances, and should be set to approximately 100 * # of processors on the server. The default
value is 200 for all services.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxDepth
n
n
n
Datatype - Integer
Description - Specifies the maximum node depth. The default value is 200.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxReceivedMessageSize
n
n
n
Datatype - Long
Description - Specifies the maximum size of a message (in bytes) that will be processed by the service.
This value helps limit DoS attacks, and should be large enough to accommodate larger message payloads. The default value for FileTransfer is Int.MaxValue, and for all other services, it is 104857600.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
MaxStringContentLength
n
n
n
Datatype - Integer
Description - Specifies the maximum string length returned by the XML reader. The default value for
FileTransfer is Int.MaxValue, and for all other services, it is 104857600.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
ReceiveTimeout
n
n
n
Datatype - Timespan
Description - Specifies the length of time a connection can be inactive before it is dropped.
ReceiveTimeout specifies how long a service waits from the beginning of a receiving a request until the
message is finished being processed. The default value is 10 minutes for all services.
Sections - kCura.Authentication.Config, kCura.DataManipulation.Config, kCura.FileTransfer.Config,
kCura.SetExecutor.Config
2.8.4 Override configuration references
For more information about override configuration options, review the following references:
n
IncludeExceptionDetailInFaults Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.servicebehaviorattribute.includeexceptiondetailinfaults.aspx
MaxArrayLength Property:
n
http://msdn.microsoft.com/en-us/library/system.xml.xmldictionaryreaderquotas.maxarraylength
(v=vs.100).aspx
MaxBufferSize Property:
http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpbinding.maxbuffersize.aspx
Relativity | Services API Guide - 24
n
MaxBufferPoolSize Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.basichttpbinding.maxbufferpoolsize.aspx
MaxConcurrentCalls Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.description.servicethrottlingbehavior.maxconcurrentcalls.aspx
MaxConcurrentInstances Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.description.servicethrottlingbehavior.maxconcurrentinstances.aspx
MaxConcurrentSessions Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.description.servicethrottlingbehavior.maxconcurrentsessions.aspx
MaxDepth Property:
n
http://msdn.microsoft.com/en-us/library/system.xml.xmldictionaryreaderquotas.maxdepth.aspx
MaxReceivedMessageSize Property:
n
http://msdn.microsoft.com/enus/library/system.servicemodel.wshttpbindingbase.maxreceivedmessagesize.aspx
MaxStringContentLength Property:
n
http://msdn.microsoft.com/enus/library/system.xml.xmldictionaryreaderquotas.maxstringcontentlength.aspx
ReceiveTimeout Property:
n
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.receivetimeout.aspx
SendTimeout Property:
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.sendtimeout.aspx
2.9 Testing the Services API configuration
The Relativity Services API Diagnostic Tool provides you with the ability to test the configuration of the
Services API in your environment. It displays error messages with troubleshooting information when it
detects incorrect settings for certificate values, and other endpoint configuration errors.
2.9.1 Relativity Services API Diagnostic Tool
You can use the Relativity Services API Diagnostic Tool to verify that the Services API is configured properly in
your environment. This tool tests the WSDL endpoint configuration for the RSAPIClient proxy, and tests all
services that it runs in the background. The tool displays error messages when it detects a problem. See
Viewing errors in the Services API Diagnostic Tool on page 28.
1. Navigate to the following DiagnosticTool folder in your installation directory, and click ProxyDiagnostic.exe. For example, you would use the following path if the SDK was installed on drive C:
C:\Program Files\kCura Corporation\Relativity SDK\RSAPI\Tools\DiagnosticTool\
ProxyDiagnostic.exe
2. To launch the Services API Diagnostic Tool, click the executable.
Relativity | Services API Guide - 25
3. Enter Username and Password that you are using for authentication. Leave these fields blank if you
aren't using this type of authentication.
4. Enter the name of Server where the Services API is running. (The Services API Diagnostic Tool only
requires the machine name, but you can enter the URI for the server, and it will parse the name from
this string.)
5. In the Authentication tree, select the authentication methods that you want to test. You can right-click
on this list to select or clear all the check boxes.
By default, all of the authentication methods are selected. You may initially want to test all methods to
identify, which endpoint types are available in your environment. You can then disable any endpoint
types that you don't want exposed.
6. (Optional) If a CertificateFindValue is defined in the web.config for your server, select the Auto-Detect
CertificateFindValue box. The Services API Diagnostic Tool will automatically populate the CertificateFindValue box with the current server setting. See Server-side override values on page 22.
Note: Leave the Auto-Detect CertificateFindValue box blank if you aren't setting the CertificateFindValue in
the web.config file.
7. Click Run Diagnostics. The Current EndPointType box is updated with status messages as the test proceeds. The Services API Diagnostic Tool automatically detects the CertificateFindValue for the server.
Relativity | Services API Guide - 26
8. Review the results of the endpoint tests in the Authentication tree:
Green Status - indicates the endpoint type is available and the connection succeeded.
Red Status - indicates that the attempt to connect with this endpoint failed. To obtain more
information about a failure, complete step 9.
9. (Optional) Complete the following tasks if you want to view the exception thrown when the endpoint
test failed:
n
n
a. Select only the failed endpoint in the Authentication tree.
b. Select the Display ServiceOperationFailed Events option.
c. Click Run Diagnostics to display exception details including the exception thrown and the stack
trace as in the following illustration.
Relativity | Services API Guide - 27
Note: You can also perform additional troubleshooting to resolve these errors. See Viewing errors in
the Services API Diagnostic Tool below and Troubleshooting the Services API Configuration on page 30.
d. (Optional) Click Copy to Clipboard if you want copy the error messages generated in the Current
EndpointType box.
2.9.2 Viewing errors in the Services API Diagnostic Tool
The RelativityServices API Diagnostic Tool displays error messages when it detects that the Services API isn't
configured properly. You can review the details for these error messages and then use the suggested
resolution to update the endpoint configuration for the RSAPIClient proxy. See Configuring the Services API
on page 9.
2.9.2.1 Ambiguous CertificateFindValue defined
You will receive the following error message when the CertificateFindValue needs to be more specific:
The value '<VALUE>' was specified as the server-side CertificateFindValue, but
there is more than one matching certificate. Remove certificates with
duplicate SubjectName values from the Certificate Store, or provide a more
specific SubjectName.
This error occurs when the supplied CertificateFindValue in the server-side web.config file needs to be more
specific. (See '<VALUE>' in the message.) If the name supplied for the CertificateFindValue matches multiple
certificates in IIS, you must update the CertificateFindValue to identify a unique certificate name, or remove
the duplicate certificates. See Configuration overrides on page 19.
Relativity | Services API Guide - 28
2.9.2.2 No CertificateFindValue defined
You will receive the following error message when no value was supplied as the server-side
CertificateFindValue:
Nothing was specified as the server-side CertificateFindValue. Provide the
SubjectName value of a valid certificate in the Certificate Store.
This error occurs when no value was defined for the CertificateFindValue, or an empty string ("") was used.
Add an entry similar to the following example to the kCura.CommonServiceValues.config section of the
Relativity.Services web.config file:
<add key=”CertificateFindValue” value=”myCert.subjectName.com” />
2.9.2.3 Invalid CertificateFindValue defined
You will receive the following error message when an invalid value was supplied as the server-side
CertificateFindValue:
The value '<VALUE>' was specified as the server-side CertificateFindValue, but
a matching certificate couldn't be found. Double check the name and spelling
and ensure the certificate is in the correct Certificate Store.
This error occurs when the value supplied as the CertificateFindValue doesn't match any existing certificate.
Ensure the certificate is in the appropriate store, and that the spelling is correct.
2.9.2.4 Invalid server format
You will receive the following error message when the server address supplied was in an invalid format:
The supplied server is in an invalid format. Check for any typing mistakes.
Verify that there aren't any spelling or typographical errors.
2.9.2.5 Invalid configuration keys present
You will receive the following error message when invalid keys are present in a specific section of the serverside web.config file:
The '<SECTION>' section of the web.config contains invalid keys: <KEYS>.
Ensure no typographical errors were made and that each key is in the
appropriate section.
In this message, <SECTION> represents the part of the web.config file that contains invalid keys. <KEYS> is a
comma-separated list of the offending keys. Ensure that each key is in the correct section, and that no spelling
or typographical errors exist. Also, the keys are case-sensitive.
2.9.2.6 Insufficient permissions in IIS
You will receive the following error message when the account that the Relativity.Services application pool
runs under has insufficient permissions to access a certificate:
The account that IIS is running under does not have sufficient permissions to
the private key of the certificate referred to by the server-side
CertificateFindValue. Via the 'Certificates' snap-in of the Microsoft
Management Console, give the appropriate account permissions to the private
key.
Relativity | Services API Guide - 29
Follow the instructions provided in the error message. See MSDN (http://msdn.microsoft.com/enus/default.aspx) for more information about how to modify private key permissions.
2.9.2.7 Protocol not configured properly
You will receive the following error message when a protocol hasn't been properly configured:
The protocol '<VALUE>' has not been configured correctly. Ensure that all
necessary Windows features are installed, that '<VALUE>' has been added to the
list of Enabled Protocols for the IIS application, and the site has a binding
for '<VALUE>'.
In the error message, <VALUE> indicates the protocol that requires further configuration before it is usable.
See Configuring the Services API on page 9.
2.9.2.8 Remote name unreachable
You will receive the following error message when the server address supplied can't be reached:
The supplied server '<SERVER>' could not be reached.
Verify that no spelling or typographical errors exist, and that Windows can resolve the supplied host name.
2.9.2.9 HTTP requested, but SSL is required
You will receive the following error message when the server requires SSL, but an attempt was made to
communicate using HTTP:
A connection attempt was made with HTTP, but the server requires SSL.
HTTP must be allowed in IIS if you want to use any of the endpoint configurations that involve HTTP, such as
IntegratedHTTP, or UserNamePasswordHTTP. See Configuring the Services API on page 9.
2.9.2.10 SSL trust failure
You will receive the following error message when there is an issue establishing an SSL connection:
The Certificate Authority of the server's certificate is not trusted by the
client. If the server is using a self-signed certificate, install that
certificate on the client in the Trusted Root Certification Authorities of the
Local Machine if you trust it. The specified server name does not match the
SubjectName value of the certificate of the HTTPS binding in IIS. Either use a
different certificate on the server, or use a client-side server name that
matches against the SubjectName.
To resolve this error, ensure the server’s certificate is trusted and that the client is using an appropriate
address to reach the server. The address must match the SubjectName of the certificate attached to the
HTTPS binding in IIS. See Configuring the Services API on page 9.
2.10 Troubleshooting the Services API Configuration
You can use the information in the following sections to troubleshoot the configuration of the Services API. In
addition to reviewing error messages, you can also use the Proxy Diagnostic Tool to troubleshoot connections
to the Services API. See Testing the Services API configuration on page 25.
Relativity | Services API Guide - 30
2.10.1 Logging and debugging settings in the web.config
To assist with Services API troubleshooting, enable logging and debugging in the web.config file. (They are
disabled by default.) Modify the configuration settings as necessary.
2.10.2 Production environment trace settings
To troubleshoot application activity, you can collect trace data from WCF or user-defined trace sources. Trace
levels include Warning, Information, and Verbose.
Note: Logging may result in application performance degradation. Information and Verbose levels produce
greater logging output resulting in a greater performance impact, so they may be best suited for nonproduction environments.
This table includes logging configurations recommended for production environments. You will need to
update the web.config file with these values. (If you don't anticipate performance degradation, you can set
the switchValue attribute to Information to generate additional trace data.)
Trace Source
WCF
User-defined
Source Name
System.ServiceModel
User-defined source name
switchValue Attribute
Warning
Warning,
ActivityTracing
Additional Attribute
propagateActivity="true"
Using the recommended production environment configurations, the following sample code defines trace
settings for the System.ServiceModel WCF trace source and a user-defined trace source named
myUserTraceSource:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Warning"
propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource"
switchValue="Warning, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<shareListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
Relativity | Services API Guide - 31
initializeData="C:\logs\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
2.10.3 Test environment trace settings
In your test environment, make the following updates to the web.config file:
n
n
In the initializeData attribute, set the file name and directory location to the folder where you want to
save the log output.
Add the following node to the system.servicemodel section:
<diagnostics wmiProviderEnabled="true">
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
/>
</diagnostics>
Use the recommended configuration settings for the test environment listed in the following table. For
enhanced logging, add System.ServiceModel.MessageLogging as an additional trace source. (The switchValue
attribute doesn’t affect this trace source.)
Trace Source
WCF
Source Name
System.ServiceModel
User-defined
User-defined source
name
Source Name
Information, ActivityTracing or
Verbose, ActivityTracing
Information, ActivityTracing or
Verbose, ActivityTracing
Additional Attribute
propagateActivity="true"
The following sample code defines trace settings for the System.ServiceModel WCF, and the
System.ServiceModel.MessageLogging trace sources, as well as a user-defined trace source named
myUserTraceSource. The switchValue attribute uses this Information, and ActivityTracing settings.
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
Relativity | Services API Guide - 32
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\logs\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
2.10.4 FailureAuditing Configuration Override Setting
You can also configure a FailureAuditing override setting on the server hosting the Services API. You can set
this value to True if you want to audit failed security events from WCF. Audited security events include
transport, message, or negotiate authentication and authorization events. You can view these events in the
Windows Event Viewer, since they are written to Windows event log. See Configuration overrides on page 19.
2.10.5 Attempting to access .svc file causes keyset error
You receive the following error message when accessing a .svc files that expose an EndpointType configuration
requiring a certificate, such as username and password authentication forfor HTTP, HTTPS, or Net.TCP:
Keyset does not exist.
This error occurs because the permissions on the private key of the certificate are incorrect. It occurs only
when the Services API attempts to access a certificate already added to a directory, even though it is in the
correct location. You don’t need to relocate the certificate.
To resolve this issue, you need to ensure the account running the Relativity.Services application in IIS has
access to the private key of the certificate. Complete these steps to set the permissions:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Log on to the server running the Services API.
Click Start.
In the Search programs and files box, type mmc.
Press Enter to open the Microsoft Management Console.
On the File menu, click Add/Remove Snap-in.
In the Available snap-ins column, double-click Certificates to open the Certificates snap-in dialog.
Select Computer account, and click Next.
Select Local computer option for managing snap-ins.
Open the Certificates (Local Computer) snap-in.
Browse to Personal, and then Certificates.
Locate the certificate that you have set for CertificateFindValue property in the web.config file.
Relativity | Services API Guide - 33
12. Right-click on the certificate, point to All Tasks, and click Manage Private Keys.
13. To modify the private key permissions, select Add.
14. Grant full permissions to the account running the Relativity.Services IIS application.
2.10.6 Catching EndpointType exceptions
You can obtain additional information about EndpointType errors by catching the
EndpointTypeCollectionInvalidException exception. This error message is returned when you catch this
exception:
Error constructing a proxy.
Log Info:
EndpointType UserNamePasswordNetTCPHTTP Failed:
-->Metadata contains a reference that cannot be resolved:
'http://someserver.name.domain/Relativity.Services/SetExecutorNetHTTP.svc?wsd
l'.
-->The remote name could not be resolved: 'someserver.name.domain'
EndpointType UserNamePasswordHTTP Failed:
-->Metadata contains a reference that cannot be resolved:
'http://someserver.name.domain/Relativity.Services/SetExecutorHTTP.svc?wsdl'.
-->The remote name could not be resolved: 'someserver.name.domain'
EndpointType UserNamePasswordNetTCPHTTPS Failed:
-->Metadata contains a reference that cannot be resolved:
'https://someserver.name.domain/Relativity.Services/SetExecutorNetHTTPS.svc?ws
dl'.
-->The remote name could not be resolved: 'someserver.name.domain'
EndpointType UserNamePasswordHTTPS Failed:
-->Metadata contains a reference that cannot be resolved:
'https://someserver.name.domain/Relativity.Services/SetExecutor.svc?wsdl'.
-->The remote name could not be resolved: 'someserver.name.domain'
2.10.7 Connection errors in load-balanced systems
If you have configured your environment for load balancing and HTTPS, you may receive errors if the API
connects to a different URL than the WSDL. To resolve these errors, set the binding in IIS to a certificate from
an internal CA authority or to a wildcard certificate.
2.10.8 Could not load type 'System.ServiceModel.Activation.HttpModule'
This error is displayed if you have installed .NET 4.0 features after installing .NET 4.5:
Server Error in '/Relativity.Services' Application.
Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly
'System.ServiceModel, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'.
Open a Visual Studio 64-bit console. In Admin mode, execute this command:
aspnet_regiis.exe /iru
Relativity | Services API Guide - 34
The program, aspnet_regiis.exe, is located in one of the following directories by default. The minor version
number in the directory path may vary, such as .30319 in this example.
%windir%\Microsoft.NET\Framework64\v4.0.30319
%windir%\Microsoft.NET\Framework\v4.0.30319
If the previous command didn't resolve the issue, execute this command:
servicemodelreg -r
For more information, see The DCS ServiceModelReg Utility on the Microsoft Developer Network site.
2.10.9 Erroneous calls to internal web server in load-balanced systems
When you use the client proxy to access the Services API, a second erroneous call is made to an internal web
server. The URIs in the WSDL document points to inaccessible internal websites. Microsoft has identified this
behavior as a known issue exhibited by the WCF service in load-balanced environments. The following
environmental configurations are associated with this issue:
n
n
n
Windows Communication Foundation (WCF) service in a load-balanced environment
Microsoft .NET 3.0 and 3.5
Windows Server 2003, Windows XP, Windows Vista, and Windows 2008
To resolve this issue, specify the following service behavior by adding these settings to the web.config file.
Replace <name> with the behavior name of the WCF service.
<serviceBehaviors>
<behavior name="<name>">
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="81" />
<add scheme="https" port="444" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>
For more information, see this Microsoft article (http://support.microsoft.com/kb/971842).
2.10.10 HTTP error 404.17 or 404.3
When you attempt to reach one of the service endpoints from a server hosting the Relativity.Services, you
receive an HTTP 404.17 or 404.3 errors.
Relativity | Services API Guide - 35
Use the following steps to install WCF on machines hosting the Relativity.Services:
1. Open a command prompt on a machine hosting the Relativity.Services.
2. Change to one of the following directories depending on your machine:
64-bit:cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319
32-bit:cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
3. Press Enter.
4. Type ServiceModelReg -I. Press Enter.
5. Repeat steps 1 - 4 on each machine that hosts the Relativity.Services in your environment.
n
n
Note: For more information, see http://iweb.adefwebserver.com/Default.aspx?tabid=57&EntryID=34.
2.10.11 Incorrect version of .NET enabled for application pools
Since Relativity 7.0 or above only supports .NET Framework v 4.0, you may need to register the .NET version
for your environment. Complete these steps:
1. Use the following commands to register the appropriate version of .NET (in Framework64):
aspnet_regiis -iru -enable
2. Change the application pool to the appropriate version of .NET and recycle the application pool.
Note: If the application pool fails to restart, restart IIS and then start the application pool again.
2.10.12 Missing handler mappings
Error messages don't provide detailed information for troubleshooting this issue. You will need to compare
the handler mappings on the Services API server to those of a known working server. For reference, the
Relativity | Services API Guide - 36
following path is used for the handler mapping:
%SystemRoot%\Microsoft.NET\<framework>\v2.0.50727\aspnet_isapi.dll
The <framework> represents Framework or Framework64 directory.
Note: The API on Relativity 7 includes handler mappings for .NET 4.0 as well as those for 2.0, using the
v4.0.30319 directory.
As illustrated below, these handler mappings may be missing:
n
svc-ISAPI-2.0
Relativity | Services API Guide - 37
n
svc-ISAPI-2.0-64
2.10.13 Pipe endpoint could not be found
You will receive the following error message when Net.Pipe is not configured:
System.IO.PipeException: The pipe endpoint 'net.pipe://myserver.kcura.corp/Relativity.Services/AuthenticationNetHTTP.svc' could not be
found on your local machine.
This error indicates that no endpoint was listening at Net.Pipe, which can be caused by an incorrect address or
SOAP action. You may see this error in the Relativity error log depending on where the call to the Services API
was made. To resolve this error, see Configuring Net.Pipe or Net.TCP connectivity on page 16.
2.10.14 System.ServiceModel.ExceptionDetail Error
You receive the following error message when using the Services API:
Type 'System.ServiceModel.ExceptionDetail' in Assembly 'System.ServiceModel,
Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not
marked as serializable.
For example, you may see this error message when communicating across application domains. If the
exception thrown from one domain to another isn't serializable, this error occurs.
2.10.15 Unable to access .svc file path in browser
After you install the Windows Non-HTTP Activation feature, you receive the following error when attempting
to access a .svc file path in the web browser:
Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly
‘System.ServiceModel, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089’
To resolve this issue, execute the following command line statement:
Relativity | Services API Guide - 38
aspnet_regiis.exe /iru
2.10.16 Unable to access website
You will be unable to access your website if the HTTP or HTTPS host header references your local machine
name. You can update the HTTP or HTTPS host header and reset the ISS to resolve this issue.
Note: Reset IIS during off-hours.
2.10.17 Updating the HTTP host header
If your scheme is HTTP, use the following steps to update the host header:
1.
2.
3.
4.
5.
6.
7.
8.
9.
On the web server, log on as a member of the Administers group.
Open IIS Manager.
Under the Sites node, select your website.
In the Actions pane, click Bindings to display the Site Bindings.
Select HTTP, and click Edit.
Update the Host Header on the dialog.
Reset IIS.
Try to connect.
Repeat step 1 -9 on all servers that host Relativity.Services.
3 Upgrading the Services API
Upgrading the Services API may require specific changes to your source code as well as updates to your server
and client-side configurations. As part of the upgrade process, you may want to perform endpoint
configuration tests in order to ensure clients are successfully communicating with the Services API. See Testing
the Services API configuration on page 25.
3.1 Upgrading from Relativity 8
kCura initially introduced the new RSAPIClient proxy and related function in the Relativity 8.0.291.1 patch
release - September 13, 2013. The following upgrade guidelines included information from this patch release
due to the impact of these enhancements on development with the Services API.
3.1.1 Upgrade guidelines for the Relativity 8.1
To upgrade to Relativity 8.1, use these guidelines if your environment runs Relativity 8.0.291.1 or above.
3.1.1.1 Update .dll references in your projects
To upgrade your code, run the Relativity SDK installer to obtain the new kCura.Relativity.Client.dll,
Relativity.API.dll, and other .dll files. Add references to the new .dlls to your projects. On the Relativity8.1
Developers site, obtain a copy of the Relativity SDK Installer from the Development environment guidelines
page.
Relativity | Services API Guide - 39
3.1.1.2 Upgrade your development environment to .NET 4.5
Use Microsoft .NET 4.5 framework for new development. When you update any of your current applications,
you should also target the .NET 4.5 framework.
Note: We recommend testing your existing applications for compatibility with .NET 4.5. Depending on the
results of your testing, you may need to recompile your applications for optimum performance.
3.1.2 Upgrade guidelines from the Relativity 8.0.291.1 patch release
To upgrade to Relativity 8.1, use these guidelines if your environment runs Relativity 8.0.275.3 or below. In
addition, see Upgrade guidelines for the Relativity 8.1 on the previous page.
3.1.2.1 (Optional) Update references to WCF Web Service File (.svc) files
The WCF Web Service files (.svc) have been renamed to coincide with changes made for the retrieval of
metadata over the same protocol as that used for the service connection. If you aren't using the
kCura.Relativity.Client.dll for your client development, you may need to update your code to accommodate
these changes.
Changes to .svc file names for the Authentication service
The following table lists changes to the file names for the Authentication service by EndpointType enum. A
blank entry indicates that the EndpointType enum didn't exist in previous versions.
EndpointType enums
IntegratedHTTP
IntegratedHTTPS
IntegratedNetNamedPipe
IntegratedNetNamedPipeViaHTTP
IntegratedNetNamedPipeViaHTTPS
IntegratedNetTCP
IntegratedNetTCPViaHTTP
IntegratedNetTCPViaHTTPS
UserNamePasswordHTTP
UserNamePasswordHTTPS
UserNamePasswordNetNamedPipe
UserNamePasswordNetTCP
UserNamePasswordNetTCPViaHTTP
UserNamePasswordNetTCPViaHTTPS
Relativity | Services API Guide - 40
Authentication service (.svc) in
Relativity 8
AuthenticationWinAuthHTTP.svc
AuthenticationWinAuth.svc
AuthenticationNetWinAuth.svc
AuthenticationNetWinAuth.svc
AuthenticationNetWinAuth.svc
AuthenticationNetTCPWinAuth.svc
AuthenticationNetTCPWinAuth.svc
AuthenticationNetTCPWinAuth.svc
AuthenticationForms.svc
Authentication.svc
AuthenticationNetForms.svc
AuthenticationNetTCPForms.svc
AuthenticationNetTCPForms.svc i
AuthenticationNetTCPForms.svc
Authentication service (.svc) prior
to Relativity 8
No change
No change
AuthenticationNetHTTP.svc
AuthenticationNetHTTPS.svc
AuthenticationNetHTTP.svc
AuthenticationNetHTTPS.svc
AuthenticationHTTP.svc
No change
AuthenticationHTTP.svc
AuthenticationNetHTTPSForms.svc
3.1.2.2 Use of State property on ServiceInformation class
The RSAPIClient class doesn't include a State property that was previously available on the
ArtifactManagerProxy class. In Relativity 8.1, the ArtifactManagerProxy returns only Open for the State
property on ServiceInformation object.
3.1.2.3 Use updated EndpointType enums
The UserNamePasswordNetNamedPipe endpoint type replaces deprecated endpoint types listed in the
following table. This table also includes mappings between other endpoint types deprecated during the
Relativity 8 release and their new replacements. For more information, see Upgrading the Services API in the
Relativity 8 Developers site.
Note: As a best practice, use the new endpoint types in all future applications that you develop. kCura
currently supports the deprecated endpoint types only for backwards compatibility.
Deprecated EndpointType enums
IntegratedNetNamedPipeViaHTTP
IntegratedNetNamedPipeViaHTTPS
IntegratedNetTCPViaHTTP
IntegratedNetTCPViaHTTPS
UserNamePasswordNetTCPViaHTTP
UserNamePasswordNetTCPViaHTTPS
(Deprecated in Relativity 8.0.291.1)
UserNamePasswordNetNamedPipeViaHTTP
UserNamePasswordNetNamedPipeViaHTTPS
New EndpointType enums
IntegratedNetNamedPipe
IntegratedNetTCP
UserNamePasswordNetTCP
UserNamePasswordNetNamedPipe
3.1.2.4 Client-side configuration overrides automatically set
With the introduction of the new RSAPIClient proxy, Relativity automatically sets most client-side
configuration override values available on the ProxySettings class. It copies these settings from your server to
your client-side configuration file.
These deprecated properties on the ProxySettings class are now copied from the server configuration:
n
n
n
n
n
n
n
n
MaxArrayLength
MaxBufferSize
MaxBufferPoolSize
MaxDepth
MaxReceivedMessageSize
MaxStringContentLength
SendTimeout
MaxConnectionRetries
You can optionally set the CertificateFindValue and CertificateValidation properties on the client-side as in
previous Relativity releases. See Setting client configuration overrides on page 19.
3.2 Upgrading from Relativity 7.5
Your upgrade path for Relativity 8.1 depends on the patch version currently installed in your environment:
Relativity | Services API Guide - 41
n
n
Relativity Patch 7.5.632.83 or above - review the information provided under Upgrading from Relativity 8 on page 39. You may have already completed some of these tasks as you upgraded to the latest
patches.
Relativity 7.5.632.72 or below - review Relativity Patch 7.5.632.83 Guidelines on the Relativity 7.5
Developers site and the information provided under Upgrading from Relativity 8 on page 39.
3.3 Upgrading from Relativity 7.4 and earlier
To upgrade to Relativity 8.1, make any required updates to your existing code and configuration settings.
Review the following information that describes feature changes and enhancements:
n
n
Upgrading the Services API and Relativity Patch 7.5.632.83 Guidelines on the Relativity 7.5 Developers
site
Upgrading from Relativity 8 on page 39
4 Getting started with the Services API
The Services API provides you with a set of web services for programmatically manipulating many of the
object types available in Relativity. Depending on the object type, you have the option to create, read,
update, delete, and query on it. You can use the functionality provided by the Services API to perform many
of the same tasks that you can complete through a Relativity web UI.
4.1 Prerequisites for a development environment
Complete the following tasks before you set up your development environment:
n
(Optional) Complete the configuration steps for the Services API only if you want to use HTTP, HTTPS,
or TCP as the scheme, or customize the client and server configuration settings. See Configuring the
Services API on page 9
Note: You don't need to complete any configuration steps if you use Net.Pipe as installed on the IIS when you
run the Relativity installer.
n
n
Confirm that you have .NET version 4.5 installed on your development machine.
On the Relativity 8.1 Developers site, obtain a copy of the Relativity SDK Installer, and see the Development environment guidelines.
4.2 Services API materials available in the SDK Installer
When you run the 32 or 64-bit version of the Relativity SDK Installer, its add a folder containing Services API
materials in one of the following default location:
n
n
64-bit version - installs in ...\Program Files\kCura Corporation\Relativity SDK\RSAPI\
32-bit version - installs in ...\Program Files (x86)\kCura Corporation\Relativity SDK\RSAPI
The RSAPI folder has the following subfolders with their related contents:
Relativity | Services API Guide - 42
n
n
n
n
Client - contains the kCura.Relativity.Client.dll, which must be reference by a Visual Studio project used
for development with the Services API.
Documentation - contains the Relativity - Services API.chm file with the Services API class library.
Samples - includes various subfolders with sample code. In the kCura.Relativity.Client.APISamples
folder, you will find a project containing sample class files in both VB.NET and C#.
Tools - includes the Relativity Services API Diagnostic Tool and the self-signed certificate utility. See
Relativity Services API Diagnostic Tool on page 25 and Creating a self-signed certificate on page 12.
4.3 Setting up a project in Visual Studio
1. To run the installer, double-click the kCura.Relativity.SDK.Setup.msi, and follow the instructions in the
installation wizard.
2. Create a new project in Visual Studio. (The following steps use Visual Studio 2012 as an example.)
3. Open the Solution Explorer.
4. Confirm that the Target framework is .NET Framework 4.5. (In the Solution Explorer, expand your project and right-click Properties. Click Open to display the Application tab in the left pane. Select .NET
Framework 4.5 in the Target framework box.)
Relativity | Services API Guide - 43
5. Add a reference to the kCura.Relativity.Client.dll. (In the Solution Explorer, right-click References, and
then click Add References to display the Reference Manager dialog. Click the Browse button and select
the kCura.Relativity.Client.dll.)
You can find this .dll in a Relativity web server installation, or in the RSAPI folder of the SDK installation
directory. The folder is installed at one of these locations by default:
n
n
64-bit version - installs in ...\Program Files\kCura Corporation\Relativity SDK\RSAPI\Client
32-bit version - installs in ...\Program Files (x86)\kCura Corporation\Relativity SDK\RSAPI\Client
6. Add references to the following .NET framework assemblies: System.Runtime.Serialization, and System.ServiceModel. (In the Reference Manager dialog, expand Assemblies and click Framework.)
Relativity | Services API Guide - 44
7. (Optional) Point the RelativityServices API Diagnostic Tool at your server to determine the endpoint configurations that are exposed. See Testing the Services API configuration on page 25.
4.4 Creating a simple program with the Services API
This tutorial helps you to create a simple program that uses the Services API to perform CRUD and query
operations. It illustrates how to extend the functionality provide by a sample application developed using the
Application Deployment System.
The tutorial uses a Custodian object to demonstrate how to create Relativity Dynamic Objects (RDOs) using a
typed class in the kCura.Relativity.Client.DTOs namespace. The Custodian class represents a person and its
Fields store data such as a phone number and first and last name.
4.4.1 Before you begin
To run this sample program, complete the following tasks to set up your development environment:
n
n
n
Confirm that you have the required software. See Prerequisites for a development environment on
page 42.
Create a workspace in your target Relativity instance. You don't need to add documents to the workspace.
Confirm that you have these permissions:
Relativity Administrator rights to log in to Relativity through Services API
Relativity Script Administrator rights to install an application
Download RSAPIGettingStartedTutorial.zip file on the Relativity 8.1 Developers site. This file contains
the application and source code for this sample program.
Unzip the Services API Tutorial Application, and install the RA_Tutorial_20130711213312.xml file to your
workspace. For more information, see Installing an application on the Relativity 8.1 Developers site.
Create a C# console application in Visual Studio. See Setting up a project in Visual Studio on page 43.
o
o
n
n
n
Relativity | Services API Guide - 45
Note: The code for this program references several constants that represent GUID and string values. The
TutorialConstants class provides a complete list of these constants. To view this class, open the Program.cs
file included in the RSAPIGettingStartedTutorial.zip file.
4.4.2 Adding directives for required namespaces
To your applications, add using directives referencing the namespaces that contain the classes used to create
a proxy and work with DTOs. If these Services API namespaces aren't available in your application, see Getting
started with the Services API on page 42.
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
kCura.Relativity.Client;
DTOs = kCura.Relativity.Client.DTOs;
4.4.3 Adding the Main method
The sample program has a Main() method that includes code for calls to subsequent methods for creating the
proxy, querying for Workspaces, creating an RDO, and performing other tasks.
public static void Main(string[] args)
{
// Create a client which uses Windows Authentication
// to log in to the Relativity Services on the local machine.
// Set up the current Windows user as a Relativity System
// Administrator for the purposes of this tutorial.
using (IRSAPIClient client = CreateClient())
{
// Query for a workspace and access it.
// Change the following string to the name of a workspace in your copy of
Relativity.
FindAndEnterWorkspace(client, TutorialConstants.TARGET_WORKSPACE_NAME);
// Create a Custodian RDO in the context of the workspace.
Int32 rdoID = CreateRdo(client);
// Create an Address Field on the Custodian.
Int32 fieldID = CreateField(client);
// Update the RDO with new data.
UpdateRdo(client, rdoID, fieldID);
// Read the updated RDO.
Relativity | Services API Guide - 46
ReadRdo(client, rdoID);
// Query for the ArtifactIDs of all Custodians.
QueryRdo(client);
// Delete the newly added Field from the Custodian RDO.
DeleteField(client, fieldID);
// Delete the newly created RDO.
DeleteRdo(client, rdoID);
// Log out is handled by the RSAPIClient object.
} // Exiting the using block calls the Dispose() method on the RSAPIClient,
which ensures the client is cleaned up.
PauseBeforeExit();
}
4.4.4 Creating the RSAPIClient proxy
You must be authenticated before you can manipulate objects in Relativity through the Services API. You
need to create an instance of the RSAPIClient class to hold the session data. The overloaded constructor for
the class provides you with the ability to choose the combination of endpoint type, authentication method,
and optional configuration settings appropriate for your application development goals. The proxy
automatically logs in to Relativity using the specified AuthenticationType so you don't need to call a login
method. See Creating the RSAPIClient proxy on page 61.
This code sample illustrates how to instantiate the proxy with a constructor that uses integrated Windows
authentication.
public static IRSAPIClient CreateClient()
{
// Create a new instance of RSAPIClient. The first parameter indicates the
endpoint Uri,
// which indicates the scheme to use. The second parameter indicates the
// authentication type. The RSAPIClient members page in the Services API
class library
// documents other possible constructors. The constructor also ensures a
logged in session.
string localHostFQDN = System.Net.Dns.GetHostEntry("localhost").HostName;
Uri endpointUri = new Uri(string.Format("https://{0}/relativity.services",
localHostFQDN));
IRSAPIClient rsapiClient = new RSAPIClient(endpointUri, new
IntegratedAuthCredentials());
Console.WriteLine("\tClient created and logged in.");
Relativity | Services API Guide - 47
return rsapiClient;
}
4.4.5 Querying for a Workspace
Each instance of the RSAPIClient class has an APIOptions property. Before you can use a workspace, you must
set the WorkspaceID property on APIOptions to its ArtifactID. You can perform a query on the name of the
workspace to return its ArtifactID.
The following code sample illustrates how to use the Query DTO with a TextCondition to search for a
Workspace by name and then sets its ArtifactID on the APIOptions. This code uses a Like text condition, but
you could also an EqualTo condition. Both are available in the TextConditionEnum enumeration. Since
Workspace names aren't required to be unique, the code sample calls the Any() method on the Results
object.
This Workspace provides the context for other operations.
private static void FindAndEnterWorkspace(IRSAPIClient client, string
workspaceName)
{
Console.WriteLine("\n\tFinding and entering Workspace...");
// Use the TextCondition to match workspaces with names similar to the
specified string.
var workspaceCondition = new TextCondition
(DTOs.ArtifactFieldNames.TextIdentifier,
TextConditionEnum.Like, workspaceName);
// Build a query with the workspaceCondition.
var query = new DTOs.Query<DTOs.Workspace> { Condition = workspaceCondition
};
query.Fields = DTOs.FieldValue.NoFields;
// Send the query and receive results.
DTOs.QueryResultSet<DTOs.Workspace> results =
client.Repositories.Workspace.Query(query);
if (!results.Success)
{
WriteFailedResultAndExit(results, client);
}
if (!results.Results.Any())
{
// No Workspace with the specified name exists.
Relativity | Services API Guide - 48
WriteErrorAndExit("No Workspace matching condition found.", client);
}
// To begin using this workspace, set the WorkspaceID of your instance of
APIOptions to the
// ArtifactID of the Workspace.
client.APIOptions.WorkspaceID = results.Results.First().Artifact.ArtifactID;
}
4.4.6 Creating a Relativity Dynamic Object DTO
To develop a custom application, you can create RDOs and other objects using the typed classes in the
kCura.Relativity.Client.DTOs namespace. The classes in this namespace are called DTOs. See Data Transfer
Objects (DTOs) on page 67.
This sample code shows you how to create Custodian RDO by completing the following steps that are also
common to other DTOs:
n
n
n
n
Set all required properties for a new DTO.
Call the Create() method.
Confirm that the object was created successfully.
Save or return the ArtifactID for future use.
private static Int32 CreateRdo(IRSAPIClient client)
{
Console.WriteLine("\n\tCreating RDO... ");
var rdo = new DTOs.RDO();
rdo.TextIdentifier = DateTime.Now.Ticks.ToString();
rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.FIRST_NAME_FIELD_GUID,
TutorialConstants.CUSTODIAN_FIRST_NAME_VALUE));
rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.LAST_NAME_FIELD_GUID,
TutorialConstants.CUSTODIAN_LAST_NAME_VALUE));
rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.PHONE_NUMBER_FIELD_
GUID,
TutorialConstants.CUSTODIAN_PHONE_NUMBER_VALUE));
// Set the ArtifactTypeName, ArtifactTypeID, or ArtifactTypeGuids for any
new RDO.
rdo.ArtifactTypeGuids = new List<Guid>() { TutorialConstants.CUSTODIAN_
TABLE_GUID };
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(rdo);
// Check for success of Create() method.
if (!results.Success)
{
Relativity | Services API Guide - 49
WriteFailedResultAndExit(results, client);
}
if (!results.Results.Any())
{
WriteErrorAndExit("FAILURE: RDO creation succeeded but returned no
Artifacts.", client);
}
// Get the ArtifactID of the new Custodian.
Int32 rdoID = results.Results.Single().Artifact.ArtifactID;
Console.WriteLine("\tArtifactID of new RDO: {0}", rdoID);
return rdoID;
}
4.4.7 Creating a Field on a RDO
You can create Fields on DTOs to store metadata and other information about them. To the Custodian RDO,
you add a Field with a name, which includes the word Address followed by the count of CPU ticks since
12:00:00 midnight on Jan 1, 2001. This process ensures that Field name is unique, such as Address
635133920940413625. For more information, see Field on page 113.
private static Int32 CreateField(IRSAPIClient client)
{
Console.WriteLine("\n\tCreating Field... ");
DTOs.Field field = new DTOs.Field();
field.ObjectType = new DTOs.ObjectType(TutorialConstants.CUSTODIAN_TABLE_
GUID);
field.Name = string.Format("Address {0}", DateTime.Now.Ticks);
field.FieldTypeID = FieldType.FixedLengthText;
field.Length = 255;
field.IsRequired = false;
field.IncludeInTextIndex = false;
field.Unicode = true;
field.AllowHTML = false;
field.OpenToAssociations = false;
field.Linked = false;
field.AllowSortTally = true;
field.Wrapping = true;
field.AllowGroupBy = false;
field.AllowPivot = false;
field.IgnoreWarnings = true;
field.Width = "10";
Relativity | Services API Guide - 50
DTOs.WriteResultSet<DTOs.Field> results = client.Repositories.Field.Create
(field);
if (!results.Success)
{
WriteFailedResultAndExit(results, client);
}
if (!results.Results.Any())
{
WriteErrorAndExit("FAILURE: Field creation succeeded but returned no
Artifacts.", client);
}
Int32 fieldID = results.Results.Single().Artifact.ArtifactID;
Console.WriteLine("\tArtifactID of new Field: {0}", fieldID);
return fieldID;
}
4.4.8 Updating Fields on an RDO
You can update specific Fields on a DTO. This code sample creates a new DTO with the same ArtifactID as the
one that you want to update. It illustrates how to update value of the Last Name and Text Identifier fields, and
sets the value for the newly created Address field, which is currently blank.
The ArtifactTypeGuids property indicates the object type of the RDO, which is Custodian. You can use
ArtifactGuid instead of ArtifactID, and ArtifactTypeID or ArtifactTypeName instead of ArtifactTypeGuids. We
recommend using GUIDs since they are unique across Relativity and they can't be modified. See GUIDs in
application development on page 78.
This code sample updates the Last Name and Text Identifier fields on the Custodian RDO. It also sets the
Address, which is blank.
private static void UpdateRdo(IRSAPIClient client, Int32 rdoID, Int32 fieldID)
{
Console.WriteLine("\n\tUpdating RDO... ");
// rdoID is the ArtifactID of the RDO that you want to update.
// The ArtifactTypeGuids indicates object type of the RDO, which is
Custodian.
// You can use an ArtifactGuid instead of the ArtifactID.
var updatedRdo = new DTOs.RDO(rdoID);
// You can replace the ArtifactTypeGuids with either ArtifactTypeID or
ArtifactTypeName.
// Use GUIDs because they are unique across all of Relativity and can't be
modified.
Relativity | Services API Guide - 51
updatedRdo.ArtifactTypeGuids = new List<Guid>() {
TutorialConstants.CUSTODIAN_TABLE_GUID };
// List all Fields to be updated and their new values.
// Any Fields not listed remain unchanged.
updatedRdo.Fields = new List<DTOs.FieldValue>();
updatedRdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.LAST_NAME_FIELD_
GUID,
TutorialConstants.UPDATED_CUSTODIAN_LAST_NAME_VALUE));
updatedRdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.TEXT_IDENTIFIER_
FIELD_GUID,
TutorialConstants.UPDATED_CUSTODIAN_TEXT_IDENTIFIER_VALUE));
updatedRdo.Fields.Add(new DTOs.FieldValue(fieldID,
TutorialConstants.UPDATED_CUSTODIAN_ADDRESS_VALUE, true));
// Send updated RDO and receive results.
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update
(updatedRdo);
if (!results.Success)
{
WriteFailedResultAndExit(results, client);
}
Console.WriteLine("\tLast Name, Text Identifier, and Address [...] values
updated.");
}
4.4.9 Reading an RDO
To read, call the Read() method which takes a DTO of type RDO as an argument. The following code sample
reads the ArtifactTypeName of the Custodian RDO.
private static void ReadRdo(IRSAPIClient client, Int32 rdoID)
{
Console.WriteLine("\n\tReading RDO... ");
DTOs.ResultSet<DTOs.RDO> results =
client.Repositories.RDO.Read(new DTOs.RDO(TutorialConstants.CUSTODIAN_
TABLE_GUID, rdoID));
if (!results.Success)
{
WriteFailedResultAndExit(results, client);
}
if (!results.Results.Any())
{
Relativity | Services API Guide - 52
WriteErrorAndExit("FAILURE: RDO read succeeded but returned no
Artifacts.", client);
}
// The following line prints "ArtifactTypeName of RDO is 'Custodian'."
Console.WriteLine("\tArtifactTypeName of RDO is '{0}'.",
results.Results.Single().Artifact.ArtifactTypeName);
}
4.4.10 Querying for RDOs
You can perform searches for RDOs by using the Query DTO. In addition, you can return specific Field values
on an Artifact by adding them to the query:
query.Fields.Add(new DTOs.FieldValue("Phone Number"));
You can use this sample code to query for all Custodians and then print their ArtifactIDs. If your workspace
contains only the newly added Custodian, then this code prints just its ArtifactID. For information about
available fields, see Constant Field names on page 146.
private static void QueryRdo(IRSAPIClient client)
{
Console.WriteLine("\n\tQuerying RDO... ");
var rdoQuery = new DTOs.Query<DTOs.RDO>();
rdoQuery.ArtifactTypeGuid = TutorialConstants.CUSTODIAN_TABLE_GUID;
rdoQuery.Fields = DTOs.FieldValue.NoFields;
// To obtain more details about an Artifact, add Fields to the query.
// For example, you might add: query.Fields.Add(new DTOs.FieldValue("Phone
Number"));
// Send the Query to Relativity.
DTOs.QueryResultSet<DTOs.RDO> results = client.Repositories.RDO.Query
(rdoQuery);
if (!results.Success)
{
WriteFailedResultAndExit(results, client);
}
if (!results.Results.Any())
{
WriteErrorAndExit("FAILURE: RDO query succeeded but returned no
Artifacts.", client);
Relativity | Services API Guide - 53
}
Console.WriteLine("\tArtifactID of each Custodian:");
foreach (var res in results.Results)
{
Console.WriteLine("\t {0}", res.Artifact.ArtifactID);
}
}
4.4.11 Deleting a Field on an RDO
You can remove a Field from an RDO by calling the Delete() method and passing the ArtifactID of the Field to it.
To confirm the deletion, this code sample attempts to read the Field.
private static void DeleteField(IRSAPIClient client, Int32 fieldID)
{
Console.WriteLine("\n\tDeleting Field... ");
// Delete the Custodian RDO's newly added Field.
DTOs.WriteResultSet<DTOs.Field> deleteResult =
client.Repositories.Field.Delete(new DTOs.Field(fieldID));
// Try to read the same Field.
DTOs.ResultSet<DTOs.Field> readResult = client.Repositories.Field.Read(new
DTOs.Field(fieldID));
if (!deleteResult.Success)
{
WriteFailedResultAndExit(deleteResult, client);
}
else if (readResult.Success)
{
WriteErrorAndExit("FAILURE: Reading back the deleted Field should not
have succeeded.", client);
}
}
4.4.12 Deleting an RDO
You remove a DTO from Relativity by calling the Delete() method and passing the ArtifactID of the object to it.
This code sample deletes the Custodian RDO and then attempts to perform a Read operation to confirm that
this object no longer exists.
private static void DeleteRdo(IRSAPIClient client, Int32 rdoID)
{
Relativity | Services API Guide - 54
Console.WriteLine("\n\tDeleting RDO... ");
// Delete the Custodian with ArtifactID of rdoID.
DTOs.WriteResultSet<DTOs.RDO> deleteResult =
client.Repositories.RDO.Delete(new DTOs.RDO(TutorialConstants.CUSTODIAN_
TABLE_GUID, rdoID));
// Try to read the same Custodian.
DTOs.ResultSet<DTOs.RDO> readResult =
client.Repositories.RDO.Read(new DTOs.RDO(TutorialConstants.CUSTODIAN_
TABLE_GUID, rdoID));
if (!deleteResult.Success)
{
WriteFailedResultAndExit(deleteResult, client);
}
else if (readResult.Success)
{
WriteErrorAndExit("FAILURE: Reading back the deleted Custodian should not
have succeeded.", client);
}
}
4.4.13 Exiting the program
When you finish a session, you don't need to complete any additional steps to log out or close the proxy. The
RSAPIClient automatically completes these tasks. This sample code requests a response from the user before
the program closes.
public static void PauseBeforeExit()
{
Console.WriteLine("\nPlease press enter to end the program.");
Console.ReadLine();
}
4.4.14 Writing success and failure messages
The following sample code illustrates how to write out messages that indicate the success or failure of the
program, as well as how to log out if an error occurs.
4.4.14.1 Obtaining a result message
This sample code attempts to find the first Result in ResultSets with a non-empty, non-whitespace message.
The individual Results usually contain a message indicating when a failure occurs. However, this code shows
the overall message for the ResultSet when a more specific failure message isn’t available. This code can be
used to read the most specific messaging from any ResultSet. However, this program only attempts to read
Relativity | Services API Guide - 55
messaging from failed operations, because successful operations rarely contain messaging. See Obtaining an
error message below.
private static string GetResultMostSpecificResultSetMessage<T>
(DTOs.ResultSet<T> results) where T : DTOs.Artifact
{
string resultMessage = results.Results.Any(result =>
!string.IsNullOrWhiteSpace(result.Message))
? results.Results.First().Message
: results.Message;
return resultMessage;
}
4.4.14.2 Stopping the program due to an error
This sample code writes out a message and then logs out of the proxy when an error occurs.
private static void WriteErrorAndExit(String message, IRSAPIClient client)
{
Console.WriteLine(message);
PauseBeforeExit();
Environment.Exit(1);
}
4.4.14.3 Obtaining an error message
This sample code illustrates how to obtain an error message from a ResultSet object, and how to write out the
message before terminating the program. For more information about this code, see Obtaining a result
message on the previous page.
private static void WriteFailedResultAndExit<T>(DTOs.ResultSet<T> results,
IRSAPIClient client) where T : DTOs.Artifact
{
string failureMessage = GetResultMostSpecificResultSetMessage(results);
WriteErrorAndExit(string.Format("FAILURE: {0}", failureMessage), client);
}
4.4.15 Building and running the program
You can download the complete source code for building and running the client in Visual Studio.
Relativity | Services API Guide - 56
Note: You need to install the application as well as update the username and password so the sample
program can run in your Relativity environment. See Before you begin on page 45.
After running your program, you should see results similar to that displayed here, but with different
ArtifactIDs:
Proxy created.
Logged in.
Finding and entering Workspace.
Creating RDO...
ArtifactID of new RDO: 1042640
Creating Field...
ArtifactID of new Field: 1042641
Updating RDO...
Last Name, Text Identifier, and Address […] values updated.
Reading RDO...
ArtifactTypeName of RDO is 'Custodian'
Querying RD...
ArtifactID of each Custodian: 1042640
Deleting Field…
Deleting RDO…
Please press enter to end the program.
5 Basic Services API concepts
Learn about the Services API features, architecture, deployment process, classes and methods by reviewing
these key concepts.
5.1 Services API features
The Services API enables you to write highly customized solutions on top of Relativity by providing
functionality to perform these development tasks:
n
n
n
n
Create Dynamic Objects for use in Relativity.
Create custom web pages with unique layouts that dynamically display information stored in a Relativity database.
Develop event handlers that run on pre-save, post-save, console, and other events within Relativity.
Integrate Relativity with external applications to extract, update, or add data.
Relativity | Services API Guide - 57
n
n
n
Perform mass operations such as editing, creating, or deleting a group of Relativity objects in a single
call.
Create Relativity objects using DTOs, which ensure type safety and minimize casting errors.
Create custom agents to perform background processing and long-running operations.
5.2 Services API and the Relativity Platform
The Services API is a major component of the Relativity platform, which also includes event handlers, custom
pages, and agents. It facilitates communication between each of these components and the Relativity engine
(or business layer) by providing the proxy class necessary to interact with it. When a user performs a task, a
request is sent to the Services API, which passes these calls to the Relativity engine. The code in this layer
contains the logic that controls processing of data and access to the database. The following diagram
illustrates how the Service API is used by these components of the Relativity platform.
You can leverage the functionality provide by the Services API when you develop custom code for each of
these key components:
n
n
Custom pages - You can use custom pages to create a unique user interface for interactions with Relativity through the Services API or direct database connections. With the Services API, you can perform validation and exception handling to control the interactions between your custom pages and the
Relativity engine. These programming options aren’t available through direct database connections.
When you create a custom page, reference the kCura.Relativity.Client.dll, which is the assembly used
to obtain a proxy by instantiating the RSAPIClient class.
Event Handlers - You can develop new event handlers or modify existing ones to provide custom functionality. They are called only in the Relativity web UI and they perform operations based on user
actions. Event handlers communicate with Relativity through the Services API, the ActiveArtifact class,
or direct database connections. To use the Services API, you can reference the kCura.Relativity.Client.dll in your event handler code, and use API Helpers to create an instance of the
Relativity | Services API Guide - 58
n
RSAPIClient class, which provides methods on the proxy and exception handling. For more information
see Getting Started with the Relativity API Helpers on the Relativity 8.1 Developers site.
Agents - You can also use agents to communicate with the Relativity engine through an instance of the
Services API. Agents are background processes that run jobs performing processing, indexing, or other
custom tasks. Many Relativity environments use multiple agent servers to run these background jobs.
On each server, the Windows Service is used to deploy a copy of the Services API rather than using IIS.
Since the agent server is self-hosting an instance of the Services API, the address of the proxy is always
localhost. An advantage of this configuration is reduced network traffic since the agents can use the
proxy on their local machine rather than send requests to a web server hosting it. It also eliminates the
need to install the IIS on agent servers.
5.3 Client Proxy
In the Services API, the client-side proxy enables applications to send and receive messages over a variety of
transport protocols. This proxy is created by instantiating the RSAPIClient class that lives in the
kCura.Relativity.client.dll. To use the Services API for custom development, you need to write .NET code and
reference this assembly in your project. You also have to configure endpoints that this proxy uses to
communicate with the Services API. When you call an operation on the RSAPIClient, your request is sent to
the Services API.
5.3.1 Backwards Compatibility
kCura strives to maintain backwards compatibility with each release of the Services API. Compatibility is
guaranteed at the .NET client level, which means that the public methods and classes of the client usually
don’t change in a breaking way. In contrast, the web methods exposed at the server do change between
releases. By using the RSAPIClient proxy, you are shielded from back-end changes made to the Services API. If
breaking changes are introduced to the client library, the Services API release notes clearly documents them.
Because the web methods used by the RSAPIClient can change between releases, the Services API doesn't
support the development of custom proxies that directly communicate with the WSDL definitions provided by
Relativity.Services. You shouldn't attempt to create your own .NET proxy based on the WSDLs provided by
those services.
Relativity | Services API Guide - 59
5.4 Deploying the Services API
You deploy the Services API as a web-based service hosted hosted in Internet Information Services (IIS).You
can configure your environment with all available endpoints, including HTTPS, HTTP, Net.TCP, and Net.Pipe.
The Services API supports username/password and Windows authentication methods.
5.4.1 Deploying the Services API
The Relativity Services API is a web service based on Windows Communication Foundation (WCF), and it is
hosted on IIS. The Services API has its own virtual directory and runs in its own application pool. In addition, it
can be installed with the WebAPI as part of the Relativity web server component.
The Services API is installed on the Relativity web server as an additional IIS application, called
Relativity.Services. Most of the configuration of Relativity.Services is determined by the settings in the
web.config file of the Relativity.Services virtual directory. Some configuration options are also controlled
through the Configuration table of the EDDS database.
In addition, a local version of the Services API runs on every agent server in your environment. This service
uses the same code and database connection as your other Services API servers. However, the Services API on
the agent server is self-hosted inside the agent Windows service, so you don't need to install any IIS
infrastructure on the servers. Since only the agents on these servers use the Services API, the service only
listens on the loopback interface using a named pipe and TCP port 6867. No firewall changes or other
configuration should be required in most cases.
Note: If your environment already uses the TCP port 6867 for other software, you can update value for the
port number in the ServicesAPIMetadataPortOnAgentServers setting in the Configuration table on the
EDDS database. For more information about settings used for hosting the Services API on the agent
servers, see the Configuration Table guide on the Relativity 8.1 Documentation site.
5.4.2 Transport protocols
The Services API supports the following data transport protocols:
n
n
n
n
HTTPS - All data transmissions are encrypted using Internet standard SSL technology. They are transmitted over TCP port 443 by default. HTTPS is the default transport configuration.
HTTP - While the transport isn't encrypted, the messages are encrypted. Data is transmitted over TCP
port 80 by default.
Net.TCP - Data has a binary format rather than the XML used for HTTP/HTTPS configurations, and performs better than HTTP/HTTPS configurations. Since this transport protocol uses binary formatting
that is proprietary to Microsoft and not interoperable with other SOAP stacks, it suitable only for clients written in .NET. Data is transmitted over TCP port 808 by default.
Net.Pipe - Uses a shared-memory pipe between the client and server. It is the fastest of the transport
protocol options used by the Services API, but is restricted to clients written in .NET, and to environments with clients and servers running on the same machine.
5.4.3 AuthenticationType classes supported by the RSAPIClient
When you instantiate the RSAPIClient, the constructor takes an object of AuthenticationType as an argument.
The Services API includes the following subclasses of the AuthenticationType class that you can use to specify
Relativity | Services API Guide - 60
the type of authentication used for the connection to the RSAPIClient:
n
n
n
IntegratedAuthCredentials - indicates the use of integrated Windows authentication.
TokenCredentials - indicates the use of token authentication. This authentication type requires you to
supply a token.
UsernamePasswordCredentials - indicates the use of username and password authentication. This
authentication type requires you to supply a username and password.
For code samples illustrating how to use these authentication types
5.4.4 Summary of authentication methods and endpoint types
The following table lists the combinations of transport and authentication types supported by the Services
API.
Endpoint Type
HTTPS
HTTP
Net.TCP
Net.Pipe
Username and Password
Supported
Supported
Supported
Supported
Authentication Type
Windows Authentication
Supported
Supported
Supported
Supported
5.5 Creating the RSAPIClient proxy
With the RelativityServices API, you can creating a proxy that uses transport protocols, such HTTPS, HTTP,
Net.TCP, or Net.Pipe (.NET named pipes). The RSAPIClient class simplifies this process by providing an
overloaded constructor that takes Uri and AthenticationType objects, as well as client-side override settings
specified in an RSAPIClientSettings object.
Note: For more information about the deprecated ArtifactManagerProxy class, see the Relativity 8
Developers site.
5.5.1 RSAPIClient class overview
The RSAPIClient class exposes all of the available Services API functionality by connecting to the
Authentication, DataManipulation, SetExecutor, and FileTransfer services. You can instantiate this class to
create a proxy that includes methods used to interact with DTOs and other artifacts.
5.5.1.1 Properties and methods on the RSAPIClient class
The RSAPIClient class has the following properties:
n
n
n
APIOptions - provides instance of APIOptions class associated with this proxy instance. See APIOptions
class on the next page.
AuthType - retrieves information about the authentication type used by the proxy to connect to the
Services API. It is an AuthenticationType object. See AuthenticationType classes supported by the
RSAPIClient on the previous page.
EndpointUri - indicates the URI for the Services API URI of Relativity.Services running on the IIS. For
Relativity | Services API Guide - 61
n
example, it uses the format "http://localhost/Relativity.Services".
Repositories - provides access the group of repositories that support typed data transfer objects.
This class includes a comprehensive set of methods, which you can use to log in, create Artifact requests,
query for Artifacts, and perform other tasks.
5.5.2 APIOptions class
The APIOptions class controls who makes a call for any given method, where this user is making the call to,
and how that call behaves. The members of this class include the following properties:
n
Token – represents an authenticated user. This 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 the Login(), LoginWithCredentials(), or TokenLogin() to authenticated the new user. For sample code, see Token login on page 65
.
n
n
WorkspaceID – represents the unique identifier for a workspace in Relativity. A value of -1 indicates the
master EDDS database.
StrictMode – determines the convention used when returning or supplying fields to the Create(), Read
(), Update(), Delete(), and Query() methods. When this field is True, a subset of fields (using consistent
names and datatypes) are available across the various methods. This property is False by default. For
more information, see StrictMode property and Field directives on page 73.
Note: Some Fields available in Relativity 7.4 may have different names or may be unavailable when this
behavior is enabled by setting the property to True.
5.5.3 RSAPIClientSettings class
You can programmatically set client-side configuration by passing an RSAPIClientSettings object to the
overloaded constructor for the RSAPIClient class. This RSAPIClientSettings class can be used to define the
CertificateFindValue and the CertificateValidation settings. See Setting client configuration overrides on page
19.
5.5.4 RSAPIClientServiceOperationFailed event
RSAPIClientServiceOperationFailed event is raised when the RSAPIClient throws an exception due to a failure
or operation error. See RSAPIClientServiceOperationFailed event in the Services API class libraries.
5.5.5 Best practices for proxy creation
Use these guidelines when you create the proxy:
n
Create your proxy within a using statement in your code.
n
Use an appropriate AuthenticationType object to specify the login type.
Note: If you use an AuthenticationType object, the proxy automatically logs in to the Services API so you don't
need to call a login method. See AuthenticationType classes supported by the RSAPIClient on page 60 and
Token login on page 65.
Relativity | Services API Guide - 62
n
n
n
Omit additional code for logging out or closing the session, since the RSAPIClient proxy automatically
completes these tasks.
Use the methods in the Relativity API Helpers to create the proxy in agents, custom pages, and event
handlers. See Creating the proxy in an agent, custom page, or event handler below.
To configure the Services API manually for agents, custom pages, and event handlers, use the
guidelines provided in Manually configuring the Services API for the Relativity platform on page 18.
These guidelines highlight the use of Relativity API Helpers for obtaining the Relativity.Services URL.
5.5.6 Creating the proxy in an agent, custom page, or event handler
You can use the methods available in the Relativity API Helpers to create the proxy in agents, custom pages,
or event handlers. The CreateProxy() method is available on the IServicesMgr interface in the Relativity API
namespace. In your code, you call this method on the object returned by the GetServiceManager() method,
which is available on the agent, custom page, and event handler helper classes also provided in the Relativity
API Helpers. For more information, see Getting Started with the Relativity API Helpers in the Relativity 8.1
Developers site.
On the Relativity 8.1 Developers site, see these pages for code samples that illustrate how to create the proxy
in the agents, custom pages, or event handlers that you develop:
n
n
n
Creating custom agents
Creating custom pages
Getting started with event handlers includes links to code samples for specific event handler types,
such as Pre Delete event handlers and others
5.5.7 Code samples for proxy creation in a console application
These code samples illustrate how to create the proxy using each of the supported protocols. You specify the
protocol in the string used to create the Uri object. For convenience, the code samples use
IntegratedAuthCredentials, which is integrated Windows authentication.
n
Basic proxy creation
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("http://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Relativity | Services API Guide - 63
n
Basic proxy creation with HTTPS endpoint
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("https://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
n
Basic proxy creation with HTTP endpoint
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("http://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
n
Basic proxy creation with Net.TCP endpoint
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.tcp://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Relativity | Services API Guide - 64
}
n
Basic proxy creation with a Net.Pipe endpoint
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
5.6 Token login
Within the Relativity platform, you can use tokens for establishing connections in the following ways:
n
n
Services API – To log in to the Services API, you create the proxy using the TokenCredential authentication type. You can also create a proxy and log in to the Services API by using the Relativity API Helpers. The helper classes facilitate creating the proxy and retrieving this session token from an agent,
custom page, or event handler. They use this one-time session token as a parameter in the TokenLogin
() method on the RSAPIClient class. As a best practice, use the helper classes to facilitating creating a
proxy and authenticating to the Services API. For more information, see Getting Started with the
Relativity API Helpers.
Relativity – You can use a token to log in to the Relativity interface. The RSAPIClient class has the GenerateRelativityAuthenticationToken() method that you can use to obtain an authorization token for
this purpose.
5.6.1 Creating the proxy using a token
You can perform a token login by creating the proxy with the TokenCredential authentication type. When you
specify the AuthenticationType, the proxy automatically logs in to the Services API so you don't need to call a
login method. For information about creating the proxy in an agent, custom page, or event handler, see
Getting Started with the Relativity API Helpers.
The following code sample illustrates how to use this authentication type when creating the proxy.
try
{
using (IRSAPIClient proxy =
Relativity | Services API Guide - 65
new RSAPIClient(new Uri("http://localhost/Relativity.Services"), new
TokenCredential(token)))
{
// Add your custom code.
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
5.6.2 Generating an authorization token for Relativity
You can use the GenerateRelativityAuthenticationToken() method on the RSAPIClient class to obtain a token
for logging in to the Relativity interface. This authorization token is generated from a session token obtained
from proxy. For more information, see APIOptions class on page 62.
Note: You can also appended this authorization token to an HTTP query string as authToken=<value>. For
more information, see REST API authentication.
public void GenerateRelativityAuthenticationToken()
{
try
{
// Step 1: Create a proxy, using either UsernamePasswordCredentials,
IntegratedAuthCredentials,
// or TokenCredentials.
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
// STEP 2: Generate Relativity authorization token from session token
and return it in ReadResult object.
ReadResult readResult = proxy.GenerateRelativityAuthenticationToken
(proxy.APIOptions);
// STEP 3: Pull token out of ReadResult object for use as needed.
if (readResult.Success)
{
string authToken = readResult.Artifact.getFieldByName
("AuthenticationToken").ToString();
Console.WriteLine(String.Format("Successfully generated Relativity
authorization token {0}", authToken));
}
Relativity | Services API Guide - 66
else
{
Console.WriteLine(String.Format("An error occurred generating
Relativity authorization token: {0}", readResult.Message));
}
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred generating Relativity
authorization token: {0}", ex.Message));
}
}
5.7 Data Transfer Objects (DTOs)
The Services API now includes Data Transfer Objects (DTOs) that simplify coding and minimize errors by
providing typed wrappers for system Artifacts and Fields.
Note: While the Services API continues to provide support for the untyped layer, the use of DTOs is
recommended for any new development.
5.7.1 DTO Features
DTOs provide the following features as well as offering typed wrappers for system Artifacts and Fields:
n
n
Client methods organized into typed Repositories, such as DocumentRepository, BatchRepository, and
others
Consistent field values based on the type of the Field. In conjunction with DTOs, you can set the
StrictMode property on the APIOptions class, which causes the Services API to return consistent Fields
for the Read() and Query() methods across all ArtifactTypes.
Note: Some Fields available in Relativity 7.4 may have different names or may be unavailable when this
behavior is enabled by setting the property to True. By default, StrictMode is set to False so the Services API
continues to return the same Fields as in Relativity 7.4. See StrictMode property and Field directives on page
73.
n
n
n
n
n
n
ParamArray versions of many List parameters
Automatic use of the APIOptions instance held in the RSAPIClient class, so no manual coding is
required. See Creating the RSAPIClient proxy on page 61.
Constants for system Artifact and Field names
Deep field retrieval on explicit request
Casting methods for dynamic Fields
Eliminates use of byte array for string values
This functionality is available in the kCura.Relativity.Client.DTOs and other namespaces.
Relativity | Services API Guide - 67
5.7.2 Supported DTOs
You can use the following table to locate code samples for DTOs. The table lists the Relativity version when the
support for a specific operation was first introduced. Click the version number under an operation to display a
code sample for it.
DTO
Create Read
Batch on page 82
7.5
BatchSet on page 7.5
7.5
85
Choice on page 95
7.5
Client on page 97 7.5
7.5
Document on
7.5
7.5
page 103
Error on page 112 7.5
Field on page 113 7.5
7.5
Folder on page
7.5
7.5
153
Group on page
7.5
7.5
158
Layout on page
7.5
163
MarkupSet on
7.5
7.5
page 166
ObjectType on
7.5
7.5
page 172
RDO on page 177 7.5
7.5
Relativ7.5
ityApplication on
page 186
RelativityScript on
7.5
page 189
Tab on page 196
7.5
User on page 198 7.5
7.5
View on page 207
7.5
Workspace on
7.5
page 210
Supported Operations
(listed by earliest supported version)
Update Delete Query Other
7.5
7.5
7.5
7.5
7.5
Cancel - 7.5
Purge - 7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
Download native file - 7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
Execute - 7.5
Retrieve input -7.5
7.5
7.5
7.5
7.5
The operations listed in the previous table are supported at the following levels for DTOs:
n
n
n
Master database - Workspace, Client, User, and Group
Master database and Workspace - RelativityScript and Choice
Workspace - all other ArtifactTypes
Relativity | Services API Guide - 68
Note: For Error, the Create() method is supported at the master database and Workspace levels. However,
all Errors are written to the master database, and the Workspace where the Error occurred is inferred from
the WorkspaceID value set in the APIOptions instance.
5.8 Untyped base Artifacts
The RSAPIClient supports a limited set of operations on untyped base Artifacts, and Fields. The use of untyped
Artifacts and Fields was required by Services API in Relativity 7.4 or below.
Note: While the Services API continues to support the untyped layer, use DTOs to simplify development by
eliminate the need for casting. Implement any new development with DTOs. See Data Transfer Objects
(DTOs) on page 67.
5.8.1 RSAPIClient support for ArtifactTypes
The following table lists the ArtifactTypes and operations supported in the untyped layer.
ArtifactTypes
Create
Batch on page 79
BatchSet on page 79
Choice on page 79
Client on page 79
Document on page 80
Error on page 80
Field on page 80
Folder on page 80
Group on page 80
Layout on page 80
MarkupSet on page 80
ObjectType on page 80
RelativityApplication on page
80
Relativity Dynamic Object
(RDO) on page 80
RelativityScript on page 80
Tab on page 80
User on page 80
View on page 80
Workspace on page 81
Yes
Yes
Yes
Yes
Limited support for
Create() on
Fields on the
next page
Yes
Yes
Yes
Yes
Read
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Query
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Relativity | Services API Guide - 69
Supported Operations
Update
Delete
Yes
Yes
Yes
Yes
Yes
Yes
5.8.2 Limited support for Create() on Fields
The Services API supports the Query() method and a limited version of the Create() method on the Field
system type. The Create() method doesn't currently support the creation of the Decimal and Currency fields
through the API.
Allow Group By
Allow HTML
Allow Pivot
Allow Sort/Tally
Associative Object Type
Available In Field Tree
Available In Viewer
Field Type
Friendly Name
Properties Supported for Create() on Field
Identifier
Open to Associations
Import Behavior
Order
Include in Text Index
Pane Icon
Keywords
Relational
Length
Required
Linked
Unicode
Name
Width
Notes
Wrapping
Object Type Artifact Type ID
Yes/No Field Display Values
When a Field is created through the Services API, the unsupported properties are set to their default values.
Properties Set to Default Values
Field Tree View
Popup Picker View
Filter Type
Propagate to
Formatting
Relativity Applications
Keyboard Shortcut
5.8.3 Field (untyped)
Relativity uses fields to store document and other metadata, as well as coding selections made by a reviewer.
It provides multiple Field types to support this functionality, which are also available through the Services API.
5.8.3.1 System type fields
System type fields are properties on the base Artifact class. In the untyped layer, the base Artifact has the
following properties:
ArtifactID
ArtifactGuids
ArtifactTypeID
Base Artifact Properties in the Untyped Layer
ArtifactTypeName
ArtifactTypeGuids
ParentArtifactID
Since system type Fields don't have IDs, you must request them by name. Certain Fields have both a display
name used in the Relativity web UI, and an SQL column name used to reference the Field in the database. For
example, Field has a property with the display name Created By that contains a username as a String, and an
SQL column name of CreatedByName. Another property has no display name, but an SQL column name of
CreatedBy, which returns the user’s ID.
You can use either name when requesting Fields during a read or query operation. The Services API returns
the Field using the name referenced in your request. If you don't specify any Fields in a request, the API will
Relativity | Services API Guide - 70
return all Fields using the display names when they exist and the SQL names when no display names are
available.
You can also set the StrictMode to maintain consistency on the Fields returned by the Services API, and field
directives to indicate when you want all or no Fields returned.
5.8.3.2 Using Field types in the untyped layer
Field types are handled differently depending on whether you work with them through the DTO or untyped
layer. While the Services API continues to support the untyped layer, the use of DTOs is recommended for any
new development.
FixedLengthText and LongText Fields
In Relativity, a long text field is larger than 4,999 characters, while a fixed length fields is less than or equal to
this number of characters. In the untyped layer, all strings are encoded as byte arrays. The .NET client is
provided with the GetString() method, which converts a byte array into a String.
These FixedLengthText and LongText fields are handled in this way because the Services API is exposed as a set
of SOAP Web Services. The content of all fields is serialized as XML while being transported from the server to
the client. XML enforces restrictions on the characters that may be used in strings. Consequently, the Services
API doesn't use the XML string data type since fields within Relativity may contain text extracted from
documents, containing characters prohibited by XML.
SingleChoice Fields
In Relativity, a single choice field has a predetermined set of values called choices. A user can only select one of
these choices for coding or other purposes. Use these guidelines for SingleChoice fields:
n
Create or update SingleChoice fields on documents or RDOs. You can set the values on these Fields to
an ArtifactID or GUID, but not to a text representation of a Choice. For example, you can set the value
of the Field Single Choice Field on a Document or Dynamic Object to a Choice using its ArtifactID (such
as 100456) or its GUID. The following sample code illustrates how to set a SingleChoice in the untyped
layer:
artifactRequest.Fields.Add(new Field("Single Choice Field", 100456));
n
Retrieve a list of valid Choices for a SingleChoice field as follows:
n
Perform a read operation using the ArtifactID for Single Choice Field and the ArtifactTypeName
of Field (or ArtifactTypeID = 14).
o Request that the Choices field is returned. A List of kCura.Relativity.Client.Choice objects is
returned.
Read operations on a SingleChoice field return the following data:
o
o
o
o
o
Type of the Value property is kCura.Relativity.Client.Choice
Text value of the Choice set on the Field is the Name property of the Choice object
ArtifactID property of the Choice object is the ArtifactID of the Choice definition within the Workspace
ArtifactGuids property will be a List of GUIDs assigned to Choice definition
Relativity | Services API Guide - 71
MultiChoice Fields
In Relativity, a multiple choice field has a predetermined set of values called choices. A user can select several
choices for coding or other purposes. Use these guidelines for MultiChoice fields:
n
n
Set the values of a MultiChoice Field by defining a MultiChoiceUpdateValue that includes in its Value
property a List of Integers, which are the ArtifactIDs of the individual Choices in the MultiChoice Field.
Alternatively, provide the ValueAsGuid property, which is a List containing a List of GUIDs that represent the ArtifactIDs of the individual Choices. The value is updated based upon the MultiChoiceUpdateValue.Method property. It is replaced with new values or merged with existing ones. See
MultiChoiceUpdateValue in the Services API Class Library.
Read operations for a MultiChoice Field on a Document or Dynamic Object return the selected values
as a .NET generic list (that is List<Choice>).
SingleObject Fields
Relativity uses a SingleObject field to define a one-to-many relationship between two objects. Use these
guidelines for SingleObject fields:
n
n
Set a a SingleObject field in the untyped layer by passing the Integer value of the ArtifactID as the field
value.
Read or query operation return a SingleObject field as an Int32. The value of this field is the ArtifactID of
the Object.
MultipleObject Fields
Relativity uses a multiple object field to define a many-to-many relationship between two objects. Use these
guidelines for MultiObject fields:
n
n
Set a MultipleObject field by passing a List of Int32 values for the Artifact IDs.
Read or query operations return a MultipleObject field as an Int32. The values for this field are the ArtifactIDs of the objects.
User Fields
In Relativity, a user field contains Relativity users with rights to the current workspace. Use these guidelines
for User fields:
n
n
Create and update operations require you to set the User field to an ArtifactID.
On read and query operations, the Value property of the field has the type kCura.Relativity.Client.User,
which provides both the Name and the ArtifactID of the user.
5.8.3.3 Querying for Fields associated with an ArtifactType
You can use the Query() method to retrieve ArtifactIDs and the Names of all Fields associated with a specific
ArtifactType. The search returns only Fields that the logged in user has permissions to view. The Field Type
field supports only TextCondition.
//STEP 1: Create a Query to describe the search you want to run.
Query q = new Query();
Relativity | Services API Guide - 72
//STEP 2: Use an ArtifactType enum to set the ArtifactTypeID based on the type
of item that you want to query on. Set the ArtifactTypeName to the name of the
item type.
q.ArtifactTypeID = (int) ArtifactType.Field;
q.ArtifactTypeName = "Field";
//STEP 3: Create a Fields list to indicate which fields you want returned.
q.Fields.Add(new Field("Name"));
q.Fields.Add(new Field("Artifact ID"));
q.Condition = null;
q.RelationalField = null;
q.Condition = new TextCondition("Object Type", TextConditionEnum.EqualTo,
"Document");
5.9 StrictMode property and Field directives
In the Services API, you can use the StrictMode property and Field directives to control how the Fields
collection on an Artifact is handled when it is returned.
5.9.1 StrictMode property for DTOs
The StrictMode property is used to provide consistency in the Fields returned across all ArtifactTypes. When
you enable StrictMode, Fields have the following behavior through the Services API:
n
n
n
n
n
n
n
Consistent population and naming of system type fields, including System Created By, System Created
On, System Last Modified By, System Last Modified On, and Relativity Text Identifier.
Text fields returned as Strings.
ArtifactID is available on the base Artifact.
Read() and Query() methods return the same Fields collection.
Create() and Update() methods use the same Field names as those returned by Read and Query.
User fields are always returned as a User object with an ArtifactID and Full Name.
Choice fields are always returned as a Choice object with an ArtifactID and Name.
StrictMode is a Boolean property on the APIOptions object:
proxy.APIOptions.StrictMode = True
5.9.2 Field directives for DTOs
The Services API provides the AllFields and NoFields directives to ensure that the Fields collection on an
Artifact is handled consistently when returned across supported operations:
n
n
AllFields – Use this directive to return all of the Fields on an Artifact.
NoFields – Use this directive when you don't want to return any of the Fields on an Artifact. Only the
base Artifact is populated.
You can use the AllFields and NoFields directives on the read and query operations for DTOs.
Read operation using AllFields:
Relativity | Services API Guide - 73
DTOs.RDO dto = new DTOs.RDO(1036225);
dto.Fields = FieldValue.AllFields;
Query operation using NoFields:
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.Fields = FieldValue.NoFields;
The SelectedFields directive is available for use with a SavedSearchCondition or ViewCondition on a query. For
more information, see SavedSearchCondition on page 229 or ViewCondition on page 233.
5.9.3 StrictMode and the TextIdentifer property (untyped layer)
The Services API provides a TextIdentifier property that displays the Identifier field of an object. For example,
TextIdentifier equals the Name field on instances of Dynamic Objects. You can use it in place of the Name
property on Dynamic Objects. If you set both the TextIdentifier and Name properties during object creation,
their values must be equal or you will receive an error message.
In the untyped layer, when StrictMode is set to True, the ArtifactRequest and query operations return a field
called Relativity Text Identifier. These operations don't consistently return the TextIdentifier property when
StrictMode is False.
Use the constant kCura.Relativity.Client.Constants.RELATIVITY_TEXT_IDENTIFIER to reference the Relativity
Text Identifier field.
5.9.4 Field directives (untyped layer)
The Services API provides the AllFields and NoFields directives to ensure that the Fields collection on an
Artifact is handled consistently when returned across supported operations:
n
n
AllFields – Use this directive to return all of the Fields on an Artifact.
NoFields – Use this directive when you don't want to return any of the Fields on an Artifact. Only the
base Artifact is populated.
Note: The SelectedFields directive is available for use with a SavedSearchCondition or ViewCondition on a
query.
You can use the AllFields and NoFields directives on the read and query operations for the untyped layer.
Read operation with AllFields:
ArtifactRequest artifactRequest = new ArtifactRequest();
artifactRequest.Fields = Field.AllFields;
Query operation with NoFields:
Relativity | Services API Guide - 74
Query query = new Query();
query.Fields = Field.NoFields;
5.10 Best practices for the Services API
Use these guidelines to optimize your application development with the Services API.
5.10.1 Use DTOs whenever possible
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 Data Transfer Objects (DTOs) on page 67.
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.
5.10.2 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. See Field directives for DTOs on page 73.
5.10.3 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 bulkload 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 the Import API on the Relativity 8.1
Developers site.
5.10.4 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 configuration values.
5.10.5 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,
Relativity | Services API Guide - 75
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.
You can find the GUIDs in the custom application XML that you export from Relativity. 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.
See GUIDs in application development on page 78.
5.10.6 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. See Application Deployment System guide.
5.10.7 Use of 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.
5.10.8 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.
Relativity | Services API Guide - 76
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.
5.10.9 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 on page 146
You can also use the AllFields directive while in the development phase to discover available Fields:
FieldValue.AllFields.
5.10.10 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.
Relativity | Services API Guide - 77
5.11 GUIDs in application development
You can use a Globally Unique Identifiers (GUIDs) to provide a unique reference numbers for Artifacts. For
example, you can use GUIDs to identify the Relativity Dynamic Objects (RDOs) that you create for your custom
applications. When you add RDOs to an application, Relativity automatically generates and assigns GUIDs and
ArtifactIDs to them.
5.11.1 Using GUIDs as best practice
As a best practice, you should use GUIDs in your application development. They offer the following
advantages:
n
n
n
Consistency - They provide consistent references across Relativity workspaces and environments. They
avoid the confusion that may occur when Field names or ArtifactIDs may change across workspaces.
Enhanced portability - Since you can install custom applications in multiple workspaces, GUIDs ensure
that the RDOs retain the same unique identifier across workspaces, while ArtifactIDs vary by workspace.
Easier application management - Field names can be modified after an application is installed in a workspace. By referencing GUIDs, you have the ability to manipulate these fields even though their names
may vary across workspaces.
5.11.2 Using GUIDs in read, update, and delete operations
After you install a custom application, you can use GUIDs to perform read, update, and delete operations on
Choice, Field, ObjectType and RDOs as follows:
n
n
ArtifactGuid can be substituted for ArtifactID.
ArtifactTypeGuid can be substituted for ArtifactTypeID.
You can also use GUIDs for operations on instances of RDOs:
n
n
Create - ArtifactTypeGuid can be substituted for ArtifactTypeID or ArtifactTypeName.
Read, update, and delete - ArtifactGuid can be substituted for ArtifactID.
For code samples, see RDO on page 177.
5.11.3 Viewing GUIDs for your application components
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 Development environment guidelines on the Relativity 8.1
Developers site.
5.12 Asynchronous framework
The asynchronous framework is used to monitor long-running operations by returning status updates as
events. Not only does the asynchronous framework provide you with ability to monitor these operations, but
you can also use it to cancel them. The asynchronous framework supports the following processes:
n
n
Creating BatchSets using the CreateBatchesforBatchSet() method
Purging BatchSets using the PurgeBatchesOfBatchSet() method
Relativity | Services API Guide - 78
After the asynchronous version of these operations starts a process and succeeds, it returns a unique
identifier for that operation. The property is empty when the operation fails. Each of these operations
(CreateBatchesforBatchSet() and PurgeBatchesOfBatchSet() methods) has two versions: one that registers by
default and one that takes a flag. Depending on the version of the operation, the proxy is registered to
monitor the state of the process, and to raise events as its status changes. You can call the
MonitorProcessState() method to explicitly register the proxy to monitor and raise status events for a running
process. For code samples, see BatchSet on page 85.
The asynchronous framework will raise events for status updates automatically. However, you can also
retrieve the process status explicitly by calling the GetProcessState() method on the proxy. This method
returns a ProcessInformation object that contains data about the internal state of the process.
You can cancel an asynchronous process or allow it to run until it completes or fails. To perform this action,
call the FlagForCancellation() method, which flags the process for cancellation when the current batch
completes.
5.13 Terminology
The following table lists terms that are frequently used to refer to features and functionality available in the
Services API and the Relativity web UI.
Term
APIOptions
ArtifactID
ArtifactManagerProxy
ArtifactRequest
Artifact
ArtifactType
ArtifactTypeID
Batch
BatchSet
Choice
Client
CRUD
Description
An object containing a login token representing a session as well as the current WorkspaceID. Used as a parameter for most methods on the proxy.
A 32-bit integer that uniquely identifies items in a workspace.
(Deprecated - See RSAPIClient class overview on page 61.)
The client-side proxy that lives in the kCura.Realtivity.client.dll. Used to communicate with the Services API by calling methods on it.
A request for an operation to be performed on an Artifact in a workspace. It
can hold information about documents or Dynamic Objects. Used in CRUD
operations.
Objects representing a content item in Relativity, such as a document. It has
a unique identifier called an ArtifactID.
An enumeration that assigns a value to various Artifacts in Relativity.
An integer used to identify the type of an Artifact in a workspace. For
example, Documents have an ArtifactTypeID of 10.
A collection of documents assigned to a single user for review.
A collection of multiple batches originating from the same data source.
A predetermined value assigned to a single or multiple-choice field.
An organization associated with users, matters, and workspaces.
Represents the following database operations: create, read, update, and
delete.
Relativity | Services API Guide - 79
Term
DescriptorArtifactTypeID
Document
Error
Field
Folder
Group
Layout
MarkupSet
ObjectRules
ObjectType
ParentArtifactID
Query
QueryResult
RelativityApplication
Relativity Dynamic Object
(RDO)
RelativityScript
RSAPIClient
SavedSearch
System Types
Tab
User
View
Description
The name of the property on the ObjectType DTO, which represents the
effective ArtifactTypeID. If an ArtifactTypeID is required in the code, that ID
can simultaneously be thought of as the DescriptorArtifactTypeID of some
ObjectType.
An object in Relativity with properties such as native files, extracted text,
images, and other metadata.
Provides information about an error that occurred in Relativity.
An object used to store metadata about another object. Similar to columns
in a database.
A parent container for documents displayed in the Folder browser on Documents tab.
A collection of one or more users, often assigned a specific set of permissions.
A web-based coding form that allows a user to edit the data stored in the
fields of an object.
A set of annotations and redactions used during a review.
Provides a list of rules that control the specific behavior of a Dynamic Object.
A Dynamic Object type added to a workspace. Synonymous with ArtifactType
(as in ArtifactTypeID).
A unique identifier for a parent of an Artifact.
A query or search of a Workspace. It is passed to the Query() method.
Data returned by the Query() or SubQuery() methods.
A collection of object types, fields, choices, views, layouts, tabs, event handlers, object rules, Relativity scripts, and custom pages designed to provide
custom functionality when deployed in a workspace.
An object created by a Relativity administrator. Each type of Dynamic Object
has a unique ArtifactTypeID in the workspace where it was created.
A script defined through the Scripts tab in Relativity that allows the execution
of custom SQL scripts.
Refers to the RelativityServices API Client (RSAPIClient) for .NET. The clientside proxy that lives in the kCura.Realtivity.client.dll. Used to communicate
with the Services API by calling methods on it. See RSAPIClient class overview
on page 61.
A search that is defined and stored in Relativity for repeated use.
Refers to the properties on the base Artifact, which contains Artifact ID, System Created By, System Created On, System Last Modified By, and System
Last Modified On.
A tab in the Relativity web UI.
Individuals with access to Relativity. A user must be a member of group to
access a workspace.
Defines a set of criteria to control the contents, fields, and sort order of items
displayed on list pages in Relativity.
Relativity | Services API Guide - 80
Term
Workspace
Description
A secure data repository for documents. It also contains views, layouts,
fields, choices, and other objects. Dynamic Objects and applications may be
added to workspaces.
6 DTO reference and code samples
DTOs are typed wrappers for Artifacts supported by the Services API. For more information, see Data Transfer
Objects (DTOs) on page 67.
You can use the following table to locate code samples for DTOs. The table lists the Relativity version when the
support for a specific operation was first introduced. Click the version number under an operation to display a
code sample for it.
DTO
Create Read
Batch on the next
7.5
page
BatchSet on page 7.5
7.5
85
Choice on page 95
7.5
Client on page 97 7.5
7.5
Document on
7.5
7.5
page 103
Error on page 112 7.5
Field on page 113 7.5
7.5
Folder on page
7.5
7.5
153
Group on page
7.5
7.5
158
Layout on page
7.5
163
MarkupSet on
7.5
7.5
page 166
ObjectType on
7.5
7.5
page 172
RDO on page 177 7.5
7.5
Relativ7.5
ityApplication on
page 186
RelativityScript on
7.5
page 189
Tab on page 196
7.5
Relativity | Services API Guide - 81
Supported Operations
(listed by earliest supported version)
Update Delete Query Other
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
Cancel - 7.5
Purge - 7.5
Download native file - 7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
Execute - 7.5
Retrieve input -7.5
DTO
Create Read
User on page 198 7.5
7.5
View on page 207
7.5
Workspace on
7.5
page 210
Supported Operations
(listed by earliest supported version)
Update Delete Query Other
7.5
7.5
7.5
7.5
7.5
6.1 Batch
In Relativity, an administrator creates a batch by splitting a static set of documents into multiple sets based
on the criteria for a review. For more information, see Batches in the Relativity 8.1 Documentation site.
The Services API supports read, update, delete, and query operations on the Batch DTO.
6.1.1 Updating and reading a Batch
When you update a Batch object, you can modify only the AssignedTo and BatchStatus properties. This code
samples illustrates how to modify these properties using the Update() method on the Batch repository.
public static bool Batch_Update_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create an object specifying the Artifact ID
// and the fields that you want returned.
DTOs.Batch batch1 = new DTOs.Batch(1036607);
batch1.Fields = FieldValue.AllFields;
// STEP 2: Read current values.
ResultSet<DTOs.Batch> results = new ResultSet<DTOs.Batch>();
try
{
results = proxy.Repositories.Batch.Read(batch1);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
// STEP 3: Get the Artifact from the read results.
DTOs.Batch batch2 = results.Results.FirstOrDefault().Artifact;
Relativity | Services API Guide - 82
Console.WriteLine("Batch Artifact ID: " + batch2.ArtifactID.ToString());
Console.WriteLine("Batch Text Identifier: " + batch2.TextIdentifier);
Console.WriteLine("Batch Status ID: " + batch2.BatchStatus.Name + ", ID: "
+ batch2.BatchStatus.ArtifactID.ToString());
Console.WriteLine("Batch Assigned To: " + batch2.AssignedTo.FullName + ",
ID: " + batch2.AssignedTo.ArtifactID.ToString());
// STEP 4: Modify properties of the Batch.
// For a Batch, you can only modify the AssignedTo and BatchStatus
properties.
batch2.BatchStatus = new DTOs.Choice(1035249);
batch2.AssignedTo = new DTOs.User(1016508);
// STEP 5: Call the Update() method on the Batch repository.
WriteResultSet<DTOs.Batch> writeResultSet = null;
try
{
writeResultSet = proxy.Repositories.Batch.Update(new List<DTOs.Batch> {
batch2 });
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (writeResultSet.Success)
{
Console.WriteLine("Batch updated successfully");
batch2 = results.Results.FirstOrDefault().Artifact;
Console.WriteLine("Batch Artifact ID: " + batch2.ArtifactID.ToString());
Console.WriteLine("Batch Text Identifier: " + batch2.TextIdentifier);
Console.WriteLine("Batch Status ID: " +
batch2.BatchStatus.ArtifactID.ToString());
Console.WriteLine("Batch Assigned To ID: " +
batch2.AssignedTo.ArtifactID.ToString());
}
else
{
string message = writeResultSet.Message;
if (message == null && writeResultSet.Results.Count > 0 &&
!writeResultSet.Results[0].Success)
message = writeResultSet.Results[0].Message;
Console.WriteLine("Error: " + message);
return false;
}
Relativity | Services API Guide - 83
// STEP 6: Read back the updated Artifact.
try
{
results = proxy.Repositories.Batch.Read(batch2);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
// STEP 7: Get the updated property values from the read results.
DTOs.Batch batch3 = results.Results.FirstOrDefault().Artifact;
Console.WriteLine("Batch Artifact ID: " + batch3.ArtifactID.ToString());
Console.WriteLine("Batch Text Identifier: " + batch3.TextIdentifier);
Console.WriteLine("Batch Status: " + batch3.BatchStatus.Name + ", ID: " +
batch3.BatchStatus.ArtifactID.ToString());
Console.WriteLine("Batch Assigned To: " + batch3.AssignedTo.FullName + ",
ID: " + batch3.AssignedTo.ArtifactID.ToString());
return true;
}
6.1.2 Querying for a Batch
To query for a Batch, you can use the fields listed in the following table. For more information, see Querying
on page 227.
ArtifactID
Assigned To
Batch
Batch Set
Fields for Batch queries
Batch Size
Batch Status
Batch Unit
Reviewed
This code sample illustrates how to set query conditions, call the Query() method on the Batch repository,
and iterate through the result set.
public static bool Batch_Query_By_BatchSet_Using_Repository(IRSAPIClient proxy)
{
Relativity | Services API Guide - 84
// STEP 1: Create criteria that identifies a BatchSet object.
WholeNumberCondition criteria = new WholeNumberCondition
(BatchFieldNames.BatchSet, NumericConditionEnum.EqualTo, 1036606);
// STEP 2: Create a query that uses your criteria.
DTOs.Query<DTOs.Batch> query = new DTOs.Query<DTOs.Batch>();
query.Condition = criteria;
query.Fields = FieldValue.AllFields;
// STEP 3: Call the Query() method on the Batch repository.
QueryResultSet<DTOs.Batch> result = null;
try
{
result = proxy.Repositories.Batch.Query(query);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
Console.WriteLine(string.Format("Number of batches returned: {0}",
result.Results.Count));
// STEP 3: Iterate through returned the results.
foreach (DTOs.Result<DTOs.Batch> batchResult in result.Results)
{
DTOs.Batch batch = batchResult.Artifact;
Console.WriteLine("Batch Name: " + batch.Name);
Console.WriteLine("Batch Artifact ID: " + batch.ArtifactID);
}
return true;
}
6.2 BatchSet
In Relativity, a batch set represents a group of batches, which are sets of documents. For more information,
see Batches in the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on the BatchSet DTO.
6.2.1 Creating, updating, and querying BatchSet objects
After you create a BatchSet DTO, you can update its properties by calling the Update() method on the
BatchSet repository. This code sample illustrates how to create a BatchSet, read its fields from the database,
update the fields, and then query for the BatchSet.
Relativity | Services API Guide - 85
public static bool Create_then_Update_A_BatchSet_Using_Repositories
(IRSAPIClient proxy)
{
// STEP 1: Create a BatchSet DTO and set its properties.
kCura.Relativity.Client.DTOs.BatchSet newBatchSet = new
kCura.Relativity.Client.DTOs.BatchSet();
newBatchSet.Name = "My Batch Set";
newBatchSet.BatchPrefix = "Batch";
newBatchSet.MaximumBatchSize = 5;
newBatchSet.AutoBatch = true;
newBatchSet.MinimumBatchSize = 1;
newBatchSet.AutoCreateRateMinutes = 30;
newBatchSet.BatchDataSource = new kCura.Relativity.Client.DTOs.Artifact
(1036604);
// STEP 2: Call the Services API to create the BatchSet.
WriteResultSet<kCura.Relativity.Client.DTOs.BatchSet> createResults = null;
try
{
createResults = proxy.Repositories.BatchSet.Create(newBatchSet);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred creating the batch
set: {0}", ex.Message));
return false;
}
if (!createResults.Success)
{
Console.WriteLine(string.Format("An error occurred creating the batch
set: {0}", createResults.Message));
return false;
}
Int32 newID = createResults.Results[0].Artifact.ArtifactID;
Console.WriteLine("ID of the new Batch Set: " + newID.ToString());
// STEP 3: Read the batch to get all the fields from the database.
ResultSet<kCura.Relativity.Client.DTOs.BatchSet> readResults = null;
kCura.Relativity.Client.DTOs.BatchSet batchSetRead = new BatchSet(newID);
batchSetRead.Fields = FieldValue.AllFields;
try
{
readResults = proxy.Repositories.BatchSet.Read(batchSetRead);
Relativity | Services API Guide - 86
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred reading the batch set:
{0}", ex.Message));
return false;
}
if (!readResults.Success)
{
Console.WriteLine(string.Format("An error occurred reading the batch set:
{0}", readResults.Message));
return false;
}
kCura.Relativity.Client.DTOs.BatchSet readBatchSet = readResults.Results
[0].Artifact;
Console.WriteLine("Initial value of Name: " + readBatchSet.Name);
Console.WriteLine("Initial value of AutoCreateRate: " +
readBatchSet.AutoCreateRateMinutes.ToString());
// STEP 4: Modify properties of the BatchSet. The Name and TextIdentifier
both have the
// same value which is the Batch Set Name. Since they have the same value,
// you can update the BatchSet using the TextIdentifier.
kCura.Relativity.Client.DTOs.BatchSet batchSet = readResults.Results
[0].Artifact;
batchSet.TextIdentifier = "Better Batchset";
batchSet.AutoCreateRateMinutes = 45;
// MaximumBatchSize must be set for the update.
batchSet.MaximumBatchSize = readBatchSet.MaximumBatchSize;
WriteResultSet<kCura.Relativity.Client.DTOs.BatchSet> updateResults = null;
// STEP 5: Call the Services API to update the BatchSet just created.
try
{
updateResults = proxy.Repositories.BatchSet.Update(batchSet);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred updating the batch
set: {0}", ex.Message));
return false;
}
Relativity | Services API Guide - 87
if (!updateResults.Success)
{
Console.WriteLine(string.Format("An error occurred updating the batch
set: {0}", updateResults.Message));
return false;
}
// STEP 6: Verify that update worked by querying the BatchSet.
Query<kCura.Relativity.Client.DTOs.BatchSet> batchSetQuery =
new Query<kCura.Relativity.Client.DTOs.BatchSet>();
batchSetQuery.Fields = FieldValue.AllFields;
batchSetQuery.Condition =
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, newID);
QueryResultSet<kCura.Relativity.Client.DTOs.BatchSet> queryResultSet = null;
try
{
queryResultSet = proxy.Repositories.BatchSet.Query(batchSetQuery);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred reading the batch set
after updating: {0}", ex.Message));
return false;
}
kCura.Relativity.Client.DTOs.BatchSet readBatchSet2 = queryResultSet.Results
[0].Artifact;
Console.WriteLine("Updated value of Name: " + readBatchSet2.Name);
Console.WriteLine("Updated value of AutoCreateRate: " +
readBatchSet2.AutoCreateRateMinutes);
return true;
}
6.2.2 Creating and deleting a BatchSet
This code sample illustrates how to call the Create() and Delete() methods on a BatchSet repository.
public static bool Create_then_Delete_A_BatchSet_Using_Repositories
(IRSAPIClient proxy)
{
// STEP 1: Create a BatchSet DTO and set its properties.
DTOs.BatchSet newBatchSet = new DTOs.BatchSet();
newBatchSet.Name = "My Batch Set";
Relativity | Services API Guide - 88
newBatchSet.BatchPrefix = "Batch";
newBatchSet.MaximumBatchSize = 5;
newBatchSet.BatchDataSource = new DTOs.Artifact(1036604);
// STEP 2: Declare a variable to hold the returned values.
WriteResultSet<DTOs.BatchSet> results =
new WriteResultSet<DTOs.BatchSet>();
Int32 newID = new Int32();
// STEP 3: Call the Services API to create the BatchSet.
try
{
results = proxy.Repositories.BatchSet.Create(newBatchSet);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (results.Success)
{
newID = results.Results[0].Artifact.ArtifactID;
Console.WriteLine(string.Format("ID of the new Batch Set: {0}", newID));
// STEP 4: Instantiate BatchSet with the ID of the BatchSet that you want
to delete.
DTOs.BatchSet batchSetToDelete = new DTOs.BatchSet(newID);
// STEP 5: Call the Services API to delete the BatchSet just created.
try
{
results = proxy.Repositories.BatchSet.Delete(batchSetToDelete);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}",
ex.Message));
return false;
}
Console.WriteLine(string.Format("Overall Status of Deleting a Batch Set:
{0}", results.Success));
}
return true;
}
Relativity | Services API Guide - 89
6.2.3 Creating Batches for a BatchSet
You can use the CreateBatchesAsync() method to add Batch objects to a BatchSet as illustrated in this code
sample. For more information about this method, see Asynchronous framework on page 78.
public static Boolean Create_Batches_For_BatchSet(IRSAPIClient proxy)
{
// STEP 1: Create a new BatchSet object.
DTOs.BatchSet batchSet = new DTOs.BatchSet();
batchSet.Name = "My Batch Set";
batchSet.MaximumBatchSize = 5;
batchSet.BatchPrefix = "APISAMPLES-";
batchSet.BatchDataSource = new DTOs.Artifact(1036604);
// STEP 2: Call the Services API to create the BatchSet.
WriteResultSet<DTOs.BatchSet> createResults;
try
{
createResults = proxy.Repositories.BatchSet.Create(batchSet);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!createResults.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
createResults.Message));
return false;
}
// STEP 3: Add Handlers for events that may occur while creating Batches.
proxy.ProcessProgress += HandleProcessProgressEvent;
proxy.ProcessComplete += HandleProcessCompleteEvent;
proxy.ProcessFailure += HandleProcessFailureEvent;
proxy.ProcessCancelled += HandleProcessCancelEvent;
// STEP 4: Create Batches for the Batch Set. While the server is executing
this call,
// your event handlers are called with progress and completion events.
Int32 batchSetArtifactID = createResults.Results[0].Artifact.ArtifactID;
ProcessOperationResult processResult;
try
Relativity | Services API Guide - 90
{
processResult = proxy.Repositories.BatchSet.CreateBatchesAsync(new
DTOs.BatchSet(batchSetArtifactID));
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!processResult.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
processResult.Message));
return false;
}
return true;
}
6.2.4 Querying for a Batch Set
To query for a BatchSet, you can use the fields listed in the following table. For more information, see
Querying on page 227 and Creating, updating, and querying BatchSet objects on page 85.
Artifact ID
Artifact ID
Auto Create Rate (minutes)
Batch Data Source
Batch Prefix
Created By
Created On
Documents to be Batched
Family Field
Last Error Reported
Fields for BatchSet queries
Last Modified By
Last Modified On
Last Successful Run
Maximum Batch Size
Minimum Batch Size
Name
Reviewed
Security
Status
6.2.5 Canceling the creation of a BatchSet
When you cancel the creation of a BatchSet, Relativity stops creating new Batches but it doesn't delete those
that were already created. This code sample illustrates how to use the FlagProcessForCancellationAsync() to
cancel Batch creation. For more information about this method, see Asynchronous framework on page 78.
public static Boolean Cancel_Batch_Creation(IRSAPIClient proxy)
{
Relativity | Services API Guide - 91
// STEP 1: Create a new BatchSet object.
DTOs.BatchSet batchSet = new DTOs.BatchSet();
batchSet.Name = "My Batch Set";
batchSet.MaximumBatchSize = 5;
batchSet.BatchPrefix = "APISAMPLES-";
batchSet.BatchDataSource = new DTOs.Artifact(1036604);
// STEP 2: Call the Services API to create the BatchSet.
WriteResultSet<DTOs.BatchSet> createResults;
try
{
createResults = proxy.Repositories.BatchSet.Create(batchSet);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!createResults.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
createResults.Message));
return false;
}
// STEP 3: Add Handlers for events that may occur while creating batches.
proxy.ProcessProgress += HandleProcessProgressEvent;
proxy.ProcessComplete += HandleProcessCompleteEvent;
proxy.ProcessFailure += HandleProcessFailureEvent;
proxy.ProcessCancelled += HandleProcessCancelEvent;
// STEP 4: Create batches for the Batch Set. While the server is executing
this call,
// your event handlers will be called with progress and completion events.
Int32 batchSetArtifactID = createResults.Results[0].Artifact.ArtifactID;
ProcessOperationResult processResult;
try
{
processResult = proxy.Repositories.BatchSet.CreateBatchesAsync(new
DTOs.BatchSet(batchSetArtifactID));
}
catch (Exception ex)
{
Relativity | Services API Guide - 92
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!processResult.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
processResult.Message));
return false;
}
// STEP 5: Cancel batch creation. After executing this call, the Relativity
server
// stops creating Batches, but it doesn't delete the Batches that were
already created.
System.Guid processID = processResult.ProcessID;
try
{
processResult = proxy.FlagProcessForCancellationAsync(proxy.APIOptions,
processID);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred cancelling batch set
creation: {0}", ex.Message));
return false;
}
if (!processResult.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
processResult.Message));
return false;
}
return true;
}
6.2.6 Purging Batches for a BatchSet
You can use the PurgeBatchesAsync() method to delete the Batch objects associated with a BatchSet object as
illustrated in this code sample. For more information about this method, see Asynchronous framework on
page 78.
public static Boolean Purge_Batches_For_BatchSet(IRSAPIClient proxy)
Relativity | Services API Guide - 93
{
// STEP 1: Add Handlers for events that may occur while creating batches.
proxy.ProcessProgress += HandleProcessProgressEvent;
proxy.ProcessComplete += HandleProcessCompleteEvent;
proxy.ProcessFailure += HandleProcessFailureEvent;
proxy.ProcessCancelled += HandleProcessCancelEvent;
// STEP 2: Call the server method to delete the existing batches for a
particular batch set.
Int32 batchSetArtifactID = 1036606;
ProcessOperationResult processResult;
try
{
processResult = proxy.Repositories.BatchSet.PurgeBatchesAsync(new
DTOs.BatchSet(batchSetArtifactID));
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!processResult.Success)
{
Console.WriteLine(String.Format("An error occurred: {0}",
processResult.Message));
return false;
}
return true;
}
6.2.7 Event handlers used in code samples
These event handlers are referenced in the previous code samples:
n
Used for progress notification while executing an asynchronous method.
public static void HandleProcessProgressEvent(Object sender,
ProcessProgressEventArgs eventArgs)
{
ProcessInformation processInformation = eventArgs.ProcessInformation;
Console.WriteLine("For the Batch Set operation, the number of operations
completed is " + processInformation.OperationsCompleted.ToString());
}
Relativity | Services API Guide - 94
n
Used for notification when an asynchronous method successfully finishes.
public static void HandleProcessCompleteEvent(Object sender,
ProcessCompleteEventArgs eventArgs)
{
ProcessInformation processInformation = eventArgs.ProcessInformation;
Console.WriteLine("The Batch Set operation completed");
}
n
Used for notification when an asynchronous method finishes with an error.
public static void HandleProcessFailureEvent(Object sender, ProcessFailureEventArgs
eventArgs)
{
ProcessInformation processInformation = eventArgs.ProcessInformation;
if (processInformation.Success == false)
Console.WriteLine("There was a problem retrieving the
process information, the message is " + processInformation.Message);
else
Console.WriteLine("The Batch Set operation failed, the process state is "
+ processInformation.State.ToString());
}
n
Used for notification when an asynchronous method stops due to a cancellation request.
public static void HandleProcessCancelEvent(Object sender, ProcessCancelEventArgs
eventArgs)
{
Console.WriteLine("The Batch Set operation was canceled");
}
6.3 Choice
In Relativity, choices are the predetermined values that you apply to single and multi-choice list fields. For
more information, see Choices in the Relativity 8.1 Documentation site.
The Services API supports read and query operations on a Choice DTO.
6.3.1 Reading a Choice
To read Field values on a Choice, you can use the Read() method on the Choice repository as illustrated in this
code sample.
public static bool Read_Choices(IRSAPIClient proxy)
{
Relativity | Services API Guide - 95
// STEP 1: Create DTO with criteria for the read.
DTOs.Choice choiceToRead = new DTOs.Choice(1016577);
choiceToRead.Fields = FieldValue.AllFields;
// STEP 2: Create ResultSet which contain Results from the read operation.
ResultSet<DTOs.Choice> results = new ResultSet<DTOs.Choice>();
// STEP 3: Perform the read operation.
try
{
results = proxy.Repositories.Choice.Read(choiceToRead);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// Check for success.
if (!results.Success)
{
Console.WriteLine("The Read operation was not successful.{0}{1}
",Environment.NewLine, results.Message);
return false;
}
Result<DTOs.Choice> choiceDtoArtifact = results.Results[0];
// Output the results.
SampleHelpers.APIHelpers.Print_All_Properties(choiceDtoArtifact.Artifact);
return true;
}
6.3.2 Querying on a Choice
This code sample illustrates how to query for Choice DTOs created at the administrator level in Relativity.
public static bool Query_for_Admin_Choices(IRSAPIClient proxy)
{
// STEP 1: Setup your query criteria.
WholeNumberCondition criteria =
new WholeNumberCondition("Choice Type ID", NumericConditionEnum.EqualTo,
1000036);
Query<DTOs.Choice> query = new DTOs.Query<DTOs.Choice> { Condition =
criteria };
Relativity | Services API Guide - 96
query.Fields = FieldValue.AllFields;
// STEP 2: Create QueryResultSet to collect query results.
QueryResultSet<DTOs.Choice> result = new QueryResultSet<DTOs.Choice>();
// STEP 3: Perform the query.
try
{
result = proxy.Repositories.Choice.Query(query, 0);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// Check for success.
if (!result.Success)
{
Console.WriteLine("The Query operation was not successful.{0}{1}
",Environment.NewLine, result.Message);
return false;
}
Console.WriteLine("Number of Choices returned: {0}", result.Results.Count);
// Output the results.
foreach (DTOs.Result<DTOs.Choice> choiceResult in result.Results)
{
Console.WriteLine("{0}Name:{1}", Environment.NewLine,
choiceResult.Artifact.Name);
Console.WriteLine("ArtifactID:{0}", choiceResult.Artifact.ArtifactID);
}
return true;
}
6.4 Client
In Relativity, clients are companies or other organizations associated with users and matters. For more
information, see Clients in the the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on a Client DTO.
6.4.1 Creating a Client
To create a Client, you must set the properties on the DTO and call the Create() method on the Client
repository as illustrate in this code sample.
Relativity | Services API Guide - 97
public static bool Create_Client(IRSAPIClient proxy)
{
//STEP 1: Create a DTO by setting the necessary properties.
DTOs.Client client = new DTOs.Client();
client.Name = "Sample Client";
client.ClientNumber = "Four more than Three";
client.Status = new DTOs.Choice(669);
//STEP 2: Create a WriteResultSet. It provides details after the create
operation.
WriteResultSet<DTOs.Client> resultSet = new WriteResultSet<DTOs.Client>();
//STEP 3: Perform the create operation.
try
{
resultSet = proxy.Repositories.Client.Create(client);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Create operation failed.{0}{1}
",Environment.NewLine, resultSet.Message);
return false;
}
//Output the results.
Console.WriteLine("The Create succeeded.");
DTOs.Client createdClient = resultSet.Results[0].Artifact;
Console.WriteLine("{0}The Artifact of the New Client is: {1}",
Environment.NewLine,
createdClient.ArtifactID);
return true;
}
6.4.2 Reading a Client
To read Field values on a Client, you can use the Read() method on the Client repository as illustrated in this
code sample.
Relativity | Services API Guide - 98
public static bool Read_Client(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
//STEP 1: Create the Client DTO to read.
kCura.Relativity.Client.DTOs.Client client = new
kCura.Relativity.Client.DTOs.Client(1015461);
client.Fields.Add(new FieldValue(ClientFieldNames.Name));
//STEP 2: Create ResultSet to collect information about the Read.
ResultSet<kCura.Relativity.Client.DTOs.Client> resultSet =
new ResultSet<kCura.Relativity.Client.DTOs.Client>();
//STEP 3: Perform the Read.
try
{
resultSet = proxy.Repositories.Client.Read(client);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine("Number of clients returned: {0}",
resultSet.Results.Count);
foreach (Result<kCura.Relativity.Client.DTOs.Client> clientResult in
resultSet.Results)
{
Console.WriteLine("{0}Name:{1}", Environment.NewLine,
clientResult.Artifact.Name);
Console.WriteLine("ArtifactID:{0}", clientResult.Artifact.ArtifactID);
}
return true;
}
Relativity | Services API Guide - 99
6.4.3 Updating a Client
To modify a Field on a Client, you can use the Update() method on the Client repository as illustrated in this
code sample.
public static bool Update_Client(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
//STEP 1: Create the Client Artifact that you want to read.
kCura.Relativity.Client.DTOs.Client client = new
kCura.Relativity.Client.DTOs.Client(1015461);
client.Fields.Add(new FieldValue(ClientFieldNames.Name));
//STEP 2: Create ResultSet to collect information about the Read.
ResultSet<kCura.Relativity.Client.DTOs.Client> resultSet =
new ResultSet<kCura.Relativity.Client.DTOs.Client>();
//STEP 3: Perform the Read.
try
{
resultSet = proxy.Repositories.Client.Read(client);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
//STEP 4: Get the Client Artifact and set the fields to be updated.
kCura.Relativity.Client.DTOs.Client clientResult =
resultSet.Results.FirstOrDefault().Artifact;
clientResult.Name = "Updated Sample Client";
WriteResultSet<kCura.Relativity.Client.DTOs.Client> writeResultSet;
//STEP 5: Update the Client Artifact.
try
Relativity | Services API Guide - 100
{
writeResultSet = proxy.Repositories.Client.Update(clientResult);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//Check for success.
if (!writeResultSet.Success)
{
Console.WriteLine("The Update operation failed.{0}{1}",
Environment.NewLine, writeResultSet.Message);
return false;
}
return true;
}
6.4.4 Deleting a Client
You can delete a Client object by calling the Delete() method on the Client repository as illustrated in this code
sample.
public static bool Delete_Client(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
//STEP 1: Create the Client artifact to delete.
kCura.Relativity.Client.DTOs.Client client = new
kCura.Relativity.Client.DTOs.Client(1015461);
//STEP 2: Create ResultSet to collect information about the Delete.
ResultSet<kCura.Relativity.Client.DTOs.Client> resultSet =
new ResultSet<kCura.Relativity.Client.DTOs.Client>();
//STEP 3: Perform the Delete.
try
{
resultSet = proxy.Repositories.Client.Delete(client);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
Relativity | Services API Guide - 101
}
//Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
return true;
}
6.4.5 Querying for a Client
This code sample illustrates how to set query conditions, call the Query() method on the Client repository,
and iterate through the result set. For more information, see Querying on page 227.
public static bool Query_Client(IRSAPIClient proxy)
{
//STEP 1: Create Query and ObjectsCondition(s), it will provide details
after the Query Operation.
WholeNumberCondition clientCondition =
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, 1016204);
Query<DTOs.Client> query = new Query<DTOs.Client> { Condition =
clientCondition };
query.Fields = FieldValue.AllFields;
//STEP 2: Create QueryResultSet to collect information about the DTO after
Query.
QueryResultSet<DTOs.Client> resultSet = new QueryResultSet<DTOs.Client>();
//STEP 3: Perform the Query.
try
{
resultSet = proxy.Repositories.Client.Query(query, 0);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//Check for success.
Relativity | Services API Guide - 102
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine("Number of clients returned: {0}",
resultSet.Results.Count);
foreach (Result<DTOs.Client> clientResult in resultSet.Results)
{
Console.WriteLine("{0}Name:{1}", Environment.NewLine,
clientResult.Artifact.Name);
Console.WriteLine("ArtifactID:{0}", clientResult.Artifact.ArtifactID);
}
return true;
}
6.5 Document
In Relativity, documents consist of the content for a review or other tasks, and they are stored in workspaces.
For more information, see the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on a Document DTO.
6.5.1 Fields on a Document DTO
The Document DTO supports fields available on documents through the Relativity web UI as well as the
following specialized fields:
n
n
n
n
FolderName - represents the name of the folder in the Relativity, where the Document is located.
HasImages - indicates whether images of the Document exist.
HasNative - indicates whether a native file exists for the Document.
RelativityImageCount - provides the number of images associated with a Document.
6.5.2 Creating a Document
When you call the Create() method on a Document DTO, you can set only these properties:
n
n
n
RelativityNativeFileLocation – specifies the local path for the document native uploaded to Relativity,
such as c:\myFolder\myDocument.docx. It is a required property that is used only by the Create()
method.
TextIdentifier – specifies the name of the document. It is a required property for the Create() method.
See TextIdentifer property on DTOs on page 114.
ParentArtifact – indicates the folder where the document is added. It is an optional property.
Relativity | Services API Guide - 103
Only these fields are supported on the Create() method for Document. The values of any other fields won't be
updated if you attempt to set them during a create operation. After the Create() method completes, you can
use the Update() method to populate other fields on the Document object.
Note: You can't update the native file through the Services API unless you delete and then recreate the
document. However, you can use the Import API to update the native file. See Import API on the Relativity
8.1 Developers site.
6.5.2.1 Sample Code
public static int Create_Document(IRSAPIClient proxy)
{
//STEP 1: Create the Document object, specifying an optional Parent Folder.
The name of
//the identifier field will change depending on the workspace, so use the
TextIdentifier
// property.
DTOs.Document document = new DTOs.Document();
document.RelativityNativeFileLocation =
"C:\\SourceCode\\Mainline\\EDDS\\kCura.Relativity.Client.APISamples
\\SampleFiles\\LoremIpsum.docx";
document.TextIdentifier = "My New Document 001";
//STEP 2: The Parent Folder is specified by setting Parent Artifact ID.
Int32 folderId = 1003697;
//This step is optional.
document.ParentArtifact = new DTOs.Artifact(folderId);
WriteResultSet<DTOs.Document> createResults = new
WriteResultSet<DTOs.Document>();
//STEP 3: Attempt to create the document.
try
{
createResults = proxy.Repositories.Document.Create(document);
}
catch (Exception ex)
{
// If an error occurs while trying to create the document, write an error
message.
Console.WriteLine("Error: " + ex.Message);
return -1;
}
//Check for success.
if (createResults.Success)
{
Relativity | Services API Guide - 104
Console.WriteLine("Created a new document with ArtifactId =
{0}", createResults.Results.First().Artifact.ArtifactID);
return createResults.Results.First().Artifact.ArtifactID;
}
else
{
Console.WriteLine("Error creating the document: {0}",
createResults.Message);
return -1;
}
}
6.5.3 Reading a Document
The Read() method doesn't return a native file for a document. You must use the Download() method if you
want the original native file. However, you can retrieve extracted text with the Read() method.
public static bool Read_Document(IRSAPIClient proxy)
{
// STEP 1: Create an object specifying the Artifact ID
// and which fields to return.
DTOs.Document document = new DTOs.Document(1035472);
document.Fields = FieldValue.AllFields;
// STEP 2: Call the read method on the Document Repository.
ResultSet<DTOs.Document> results = new ResultSet<DTOs.Document>();
try
{
results = proxy.Repositories.Document.Read(document);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
// STEP 3: Get the Document artifact from the read results.
DTOs.Document documentArtifact = results.Results.FirstOrDefault().Artifact;
Relativity | Services API Guide - 105
Console.WriteLine("Document Control Number: " +
documentArtifact.TextIdentifier);
Console.WriteLine("Document Last Modified: " +
documentArtifact.SystemLastModifiedOn);
Console.WriteLine("Document Artifact ID: " + documentArtifact.ArtifactID);
return true;
}
6.5.4 Updating a Document
You can modify properties of the Document by calling the Update() method as illustrated in this code sample.
public static bool Update_Document(IRSAPIClient proxy)
{
// STEP 1: Create an object specifying the Artifact ID
// and which fields to return.
DTOs.Document document = new DTOs.Document(1035472);
document.Fields = FieldValue.AllFields;
// STEP 2: Read current values.
ResultSet<DTOs.Document> results = new ResultSet<DTOs.Document>();
try
{
results = proxy.Repositories.Document.Read(document);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
// STEP 3: Get the Artifact from the read results.
DTOs.Document docArtifact = results.Results[0].Artifact;
Console.WriteLine("Document Artifact ID: " + docArtifact.ArtifactID);
Console.WriteLine("Document Text Identifier: " +
docArtifact.TextIdentifier);
Relativity | Services API Guide - 106
DTOs.Artifact singleObject1 = (DTOs.Artifact)(docArtifact["Single
Object"].Value);
Console.WriteLine("Document Single Object: " +
singleObject1.ArtifactID.ToString());
// STEP 4: Modify properties of the document.
// Specify a new value for Text Identifier, a property of the Artifact.
docArtifact.TextIdentifier = "John552";
// Specify a new value for Single Object, a custom field in Relativity.
// Custom fields must be accessed using the Fields collection.
// For a Single Object, we specify the ArtifactID.
docArtifact["Single Object"].Value = 1036035;
// STEP 5: Call the Update method on the Document Respository.
WriteResultSet<DTOs.Document> writeResultSet = null;
try
{
writeResultSet =
proxy.Repositories.Document.Update(new List<DTOs.Document> {
docArtifact });
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (writeResultSet.Success)
{
Console.WriteLine("Document updated successfully");
docArtifact = results.Results[0].Artifact;
Console.WriteLine("Document Artifact ID: " + docArtifact.ArtifactID);
Console.WriteLine("Document Text Identifier: " +
docArtifact.TextIdentifier);
int singleObjectID = (int)(docArtifact["Single Object"].Value);
Console.WriteLine("Document Single Object: " + singleObjectID.ToString
());
}
else
{
string message = writeResultSet.Message;
Relativity | Services API Guide - 107
if (message == null && writeResultSet.Results.Count > 0 &&
!writeResultSet.Results[0].Success)
message = writeResultSet.Results[0].Message;
Console.WriteLine("Error: " + message);
return false;
}
// STEP 6: Read back the updated Artifact.
try
{
results = proxy.Repositories.Document.Read(document);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
// STEP 7: Get the updated property values from the read results.
docArtifact = results.Results[0].Artifact;
Console.WriteLine("Document Artifact ID: " + docArtifact.ArtifactID);
Console.WriteLine("Document Text Identifier: " +
docArtifact.TextIdentifier);
DTOs.Artifact singleObject2 = (DTOs.Artifact)(docArtifact["Single
Object"].Value);
Console.WriteLine("Document Single Object: " +
singleObject2.ArtifactID.ToString());
return true;
}
6.5.5 Deleting a Document
This code sample illustrates how to remove a document from Relativity by calling the Delete() method on the
Document repository.
public static bool Delete_Document(IRSAPIClient proxy)
{
Relativity | Services API Guide - 108
DTOs.Document doc = new DTOs.Document(1035605);
WriteResultSet<DTOs.Document> writeResultSet = new
WriteResultSet<DTOs.Document>();
try
{
writeResultSet = proxy.Repositories.Document.Delete(doc);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!writeResultSet.Success)
{
string message = writeResultSet.Message;
if (message == null && writeResultSet.Results.Count > 0 &&
!writeResultSet.Results[0].Success)
message = writeResultSet.Results[0].Message;
Console.WriteLine("Error: " + message);
return false;
}
else
{
Console.WriteLine("Document updated successfully");
}
return true;
}
6.5.6 Querying for a Document
The Services API doesn't support query conditions for the following fields on the Document DTO:
n
n
n
Batch_AssignedTo
Batch_BatchSet
Batch_Status
Note: The Services API returns query results for the Batch_AssignedTo, Batch_BatchSet, and Batch_Status
fields.
n
RelativityNativeFileLocation (Set only during a create operation.)
Relativity | Services API Guide - 109
6.5.6.1 Sample Code
This code sample illustrates how to set query conditions, call the Query() method on the Document
repository, and iterate through the result set.
public static bool Query_Document_by_Control_Number(IRSAPIClient proxy)
{
// STEP 1: Setup your query criteria.
TextCondition criteria = new TextCondition("Control Number",
TextConditionEnum.EqualTo, "AS000005");
Query<DTOs.Document> query = new Query<DTOs.Document>
{
Condition = criteria,
RelationalField = new FieldValue("Group Identifier"),
Fields = new List<FieldValue> { new FieldValue("Control Number") }
};
// STEP 2: Call the Query() method in the Document repository.
QueryResultSet<DTOs.Document> result = null;
try
{
result = proxy.Repositories.Document.Query(query, 0);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
Console.WriteLine(string.Format("Number of documents returned: {0}",
result.TotalCount));
Console.WriteLine(string.Format("Additional Pages of Query Results
Available?: {0}", !string.IsNullOrEmpty(result.QueryToken)));
// STEP 3: Iterate the returned Document result.
foreach (DTOs.Result<DTOs.Document> docResult in result.Results)
{
DTOs.Document doc = docResult.Artifact;
Console.WriteLine("Document Control Number: " + doc.TextIdentifier);
Console.WriteLine("Document Artifact ID: " + doc.ArtifactID);
}
return true;
}
Relativity | Services API Guide - 110
6.5.7 Downloading a native file
You can use the Download() method on the repository for the Document DTO to download a native file. You
can download a native file from Relativity as Stream object, or specify an output path on disk.
Note: Use the Download() method on the Document Repository class rather than this method on the
FileTransferProxy class. This approach is recommended for downloading native files. See File field on page
135.
6.5.7.1 Sample Code
public static Stream Download_Document_Native(IRSAPIClient proxy)
{
//STEP 1: Define the ArtifactID of the document which has a native file.
DTOs.Document doc = new DTOs.Document(1035607);
//STEP 2: Listen to the Failure event to get exceptions.
proxy.Failure += FileTransferFailureHandler;
//STEP 3: Call the DownloadNative() method.
KeyValuePair<DownloadResponse, Stream> documentNativeResponse;
try
{
documentNativeResponse = proxy.Repositories.Document.DownloadNative
(doc);
}
catch (Exception ex)
{
//If an error occurs while trying to download the document, write an
error message.
Console.WriteLine("Error: " + ex.Message);
return null;
}
//STEP 4: A 'null' Key and Value from the response indicates failure.
if (documentNativeResponse.Key != null && documentNativeResponse.Value !=
null)
{
Console.WriteLine("Download succeeded: {0} bytes",
documentNativeResponse.Value.Length);
return documentNativeResponse.Value;
}
else
{
return null;
}
}
Relativity | Services API Guide - 111
private static void FileTransferFailureHandler(FailureEventArgs eventArgs)
{
Console.WriteLine("The following error occurred during the download for
the document with ArtifactId {0}:
{1}", eventArgs.TargetField.ObjectArtifactId, eventArgs.Exception);
}
6.6 Error
The Services API provides an Error DTO, which represents an exception thrown in Relativity. The Services API
supports only the create operation on an Error DTO. For more information, see Troubleshooting the Services
API on page 236.
6.6.1 Writing to the error log
You can write an entry to the Relativity error log using the Create() method on the RSAPIClient proxy. This
method takes an ArtifactRequest parameter with the ArtifactTypeName set to Error or the ArtifactTypeID set
to 18. The Fields collection provides the field values to set on the newly created Error object. The Message or
Full Error field is required.
When you call the Create() method, the value set in the Workspace on the APIOptions object affects the
information added to the error log :
n
n
n
If Workspace is set to -1, the error log creates an error but not associate it with a specific workspace.
If Workspace is set to valid ID for a workspace, the error log automatically creates an error associated
with that workspace.
If you pass a new field named Workspace with a valid ID for a workspace (overriding the field in the
APIOptions object), the error log creates an error associated with the workspace specified by this field.
The following sample code illustrates how to write errors to the Relativity error log.
public static bool Create_Error_Message(IRSAPIClient proxy)
{
// STEP 1: Create an Error DTO.
DTOs.Error errorToCreate = new DTOs.Error();
// STEP 2: Create a unexpected condition which throws an exception.
try
{
throw new Exception("Invalid Data");
}
catch (Exception ex)
{
errorToCreate.FullError = ex.StackTrace;
errorToCreate.Message = ex.Message;
}
Relativity | Services API Guide - 112
// Set additional fields. The Workspace can be inferred from the APIOptions
instance.
errorToCreate.SendNotification = false;
errorToCreate.Server = Environment.MachineName;
errorToCreate.Source = "3rd Party Application";
errorToCreate.URL = "https://url/to/relativity/page.aspx";
errorToCreate.Workspace = new DTOs.Workspace(1016204);
//STEP 3: Attempt to create the error.
DTOs.WriteResultSet<DTOs.Error> resultSet = null;
try
{
resultSet = proxy.Repositories.Error.Create(errorToCreate);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//STEP 4: Check for success.
if (resultSet.Success)
{
Console.WriteLine("Error Message successfully written to Relativity Error
Log");
}
else
{
Console.WriteLine("Error Message not written to Relativity Error Log");
return false;
}
return true;
}
6.7 Field
Relativity uses Fields to store document and other metadata, as well as coding selections made by a reviewer.
It provides multiple Field types to support this functionality, which are also available through the Services API.
6.7.1 System type fields
System type fields are properties on the base Artifact class. Each DTO type has the following consistent set of
base properties returned on the Artifact:
Relativity | Services API Guide - 113
Base Artifact Properties in the DTO Layer
ArtifactID
ArtifactTypeID
ArtifactTypeName
SystemCreatedBy
SystemCreatedOn
ArtifactTypeGuids
SystemLastModifiedOn
SystemLastModifiedBy
Guids
ParentArtifact
6.7.1.1 TextIdentifer property on DTOs
Except for the Error DTO, all other DTOs have a TextIdentifier property that displays the Identifier field of an
object. For example, TextIdentifier equals the Name field on instances of Relativity Dynamic Objects RDOs.
You can use it in place of the Name property on RDOs. If you set both the TextIdentifier and Name properties
during object creation, their values must be equal or you receive an error message.
Use the constant kCura.Relativity.Client.Constants.RELATIVITY_TEXT_IDENTIFIER to reference the Relativity
Text Identifier field.
6.7.1.2 Using system type fields
Since system type Fields don't have IDs, you must request them by name. Certain Fields have both a display
name used in the Relativity web UI, and an SQL column name used to reference the Field in the database. For
example, Field has a property with the display name Created By that contains a username as a String, and an
SQL column name of CreatedByName. Another property on Field has no display name, but an SQL column
name of CreatedBy, which returns the user’s ID.
You can use either name when requesting Fields during a read or query operation. The Services API returns
the Field using the name referenced in your request. If you don't specify any Fields in a request, the API
returns all Fields using the display names when they exist and the SQL names when no display names are
available.
You can also set the StrictMode to maintain consistency on the Fields returned by the Services API, and field
directives to indicate when you want all or no Fields returned. See StrictMode property and Field directives on
page 73.
6.7.2 Field types
The Services API supports several Field types that you can use on DTOs, including fixed-length text, single and
multiple choice, single and multiple object, and others.
6.7.2.1 FixedLengthText and LongText Fields
In Relativity, a FixedLengthText field is larger than 4,999 characters, while a fixed length fields is less than or
equal to this number of characters. For DTOs, text fields are set and returned as Strings.
View the code for creating an RDO and setting the value of a FixedLengthText field
DTOs.RDO obj = new DTOs.RDO();
Relativity | Services API Guide - 114
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.FIXED_LENGTH_FIELD, "Field Value"));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View the code for reading a FixedLengthText field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.FIXED_LENGTH_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
string fieldValue = resultsObject[GUIDS.FIXED_LENGTH_
FIELD].ValueAsFixedLengthText;
View the code for updating a FixedLengthText field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.FIXED_LENGTH_FIELD, "Updated Field
Value"));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View the code for querying on RDOs with a value in their FixedLengthText fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new TextCondition(GUIDS.FIXED_LENGTH_FIELD,
TextConditionEnum.EqualTo, "Field Value");
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.2 SingleChoice Fields
In Relativity, a SingleChoice field has a predetermined set of values called choices. A user can only select one of
these choices for coding or other purposes. Use these guidelines for SingleChoice fields:
n
Create or update SingleChoice fields on documents or RDOs. Set the FieldValue to a Choice DTO instantiated with the Artifact ID or Artifact GUID. You can't set the values on SingleChoice fields to a text
Relativity | Services API Guide - 115
n
representation of a Choice. For example, you can set the value of the Field Single Choice Field on a
Document or RDO to a Choice using its ArtifactID (such as 100456) or its GUID.
Retrieve a list of valid Choices for a SingleChoice field as follows:
o
o
Perform a read operation using the Artifact ID or GUID for Single Choice Field and the ArtifactTypeName of Field (or ArtifactTypeID = 14).
Request that the Choices field is returned. A List of kCura.Relativity.Client.DTOs.Choice is
returned as illustrated in the following code.
DTOs.Field choiceFieldToRead = new DTOs.Field(1038781);
choiceFieldToRead.Fields.Add(new DTOs.FieldValue
(DTOs.FieldFieldNames.Choices));
var readResults = proxy.Repositories.Field.Read(choiceFieldToRead);
DTOs.MultiChoiceFieldValueList choices = readResults.Results[0].Artifact
[DTOs.FieldFieldNames.Choices].ValueAsMultipleChoice;
n
Read operations on a SingleChoice field return the following data:
o
o
o
o
Type of the Value returned using the ValueAsSingleChoice is kCura.Relativity.Choice.DTOs
Text value of the Choice set on the Field is the Name property of the Choice object
ArtifactID property of the Choice object is the ArtifactID of the Choice definition within the Workspace.
ArtifactGuids property is a List of GUIDs assigned to Choice definition.
View sample code for creating an RDO and setting the value of a SingleChoice field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.Choice choice = new DTOs.Choice(GUIDS.SINGLE_CHOICE_1);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_CHOICE_FIELD, choice));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a SingleChoice field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_CHOICE_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DTOs.Choice choiceValue = resultsObject[GUIDS.SINGLE_CHOICE_
FIELD].ValueAsSingleChoice;
Relativity | Services API Guide - 116
View sample code for updating a SingleChoice field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.Choice choice = new DTOs.Choice(GUIDS.SINGLE_CHOICE_1);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_CHOICE_FIELD, choice));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying for RDOs with a value in their SingleChoice fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new SingleChoiceCondition(GUIDS.SINGLE_CHOICE_FIELD,
SingleChoiceConditionEnum.AnyOfThese, new Int32[] { ARTIFACTID.SINGLE_
CHOICE_1 });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.3 File Fields
You use a File type field to upload a file for a non-document object. When you add a File field, Relativity
automatically creates other fields containing file metadata, such as File Size, File Icon, and Text fields. For more
information and code samples, see File field on page 135.
6.7.2.4 MultiChoice Fields
In Relativity, a MultiChoice field has a predetermined set of values called choices. A user can select several
choices for coding or other purposes. Use these guidelines for MultiChoice fields:
n
n
Create and update operations require you to set the values of a MultiChoice Field by defining a
MultiChoiceFieldValueList, which is used to set and return MultiChoice Fields on DTOs. When you have
a .NET List of Choice DTOs (FieldValueList<DTOs.Choice>), the UpdateBehavior property indicates how
the IDs in the FieldValueList are applied to the field (Replace or Merge). The default behavior is Replace,
when no value is specified.
If necessary, you can modified this list directly and pass it back in an update operation. You can
populate this list from a read operation, or manually set it using a constructor that takes a
List<DTOs.Choice> or parameter array of DTOs.Choice.
Read or query operations return a MultiChoice value as a FieldValueList<DTOs.Choice> using the
ValueAsMultipleChoice property.
View sample code for creating an RDO and setting the value of a MultiChoice field
DTOs.RDO obj = new DTOs.RDO();
Relativity | Services API Guide - 117
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.MultiChoiceFieldValueList choices = new DTOs.MultiChoiceFieldValueList();
choices.Add(new DTOs.Choice(GUIDS.MULTI_CHOICE_1));
choices.Add(new DTOs.Choice(GUIDS.MULTI_CHOICE_2));
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_CHOICE_FIELD, choices));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a MultiChoice field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_CHOICE_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DTOs.FieldValueList<DTOs.Choice> fieldValue =
(DTOs.FieldValueList<DTOs.Choice>) resultsObject[GUIDS.MULTI_CHOICE_
FIELD].ValueAsMultipleChoice;
View sample code for updating a MultiChoice field on an RDO
This sample also illustrates how to set the behavior of the MultiChoice Update to Replace, which modifies the
existing value.
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.MultiChoiceFieldValueList choices = new DTOs.MultiChoiceFieldValueList();
choices.Add(new DTOs.Choice(GUIDS.MULTI_CHOICE_1));
choices.Add(new DTOs.Choice(GUIDS.MULTI_CHOICE_2));
choices.UpdateBehavior = MultiChoiceUpdateBehavior.Replace;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_CHOICE_FIELD, choices));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying for RDOs with values in their MultiChoice fields
Relativity | Services API Guide - 118
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new MultiChoiceCondition(GUIDS.MULTI_CHOICE_FIELD,
MultiChoiceConditionEnum.AnyOfThese,
new Int32[] { ARTIFACTID.MULTI_CHOICE_1, ARTIFACTID.MULTI_CHOICE_2 });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.5 SingleObject Fields
In Relativity, a SingleObject field defines a one-to-many relationship between two objects. Use these
guidelines for SingleObject fields:
n
n
Create and update operations on a SingleObject field require you to pass DTO with the ArtifactID property set.
On read and query operations, the ValueAsSingleObject property returns a SingleObject as a DTO with
the type of the object that you specified in the operation. On these DTOs, only the ArtifactID on the
base Artifact is populated, while the Fields collections is empty.
Note: If the DTO layer doesn't support the requested object type, then Artifact is used as the return type.
View sample code for creating an RDO and setting the value of a SingleObject field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.Artifact fieldObj = new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_1);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_OBJECT_FIELD, fieldObj));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a SingleObject field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_OBJECT_FIELD));
DTOs.ResultSet<DTOs.RDO> results = new DTOs.ResultSet<DTOs.RDO>();
results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DTOs.Artifact artifactValue = resultsObject[GUIDS.SINGLE_OBJECT_
FIELD].ValueAsSingleObject;
Relativity | Services API Guide - 119
View sample code for updating a SingleObject field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.Artifact fieldObj = new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_1);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.SINGLE_OBJECT_FIELD, fieldObj));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their SingleObject fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new ObjectCondition(GUIDS.SINGLE_OBJECT_FIELD,
ObjectConditionEnum.AnyOfThese, new Int32[] { ARTIFACTID.FAKE_OBJECT_1 });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.6 MultiObject Fields
In Relativity, MultiObject fields define a many-to-many relationship between two objects. Use these
guidelines for MultiObject fields:
n
n
Create and update operations on MultiObject fields require you to pass a FieldValueList containing DTO
objects with their ArtifactID property set.
Read and query operations return a FieldValueList of the DTO for the object, using the
GetValueAsMultipleObject<T>() method, where T is the type of Object. On these DTOs, only the
ArtifactID on the base Artifact is populated, while the Fields collections is empty.
Note: If the DTO layer doesn't support the requested object type, then Artifact is used as the return type.
View sample code for creating an RDO and setting the value of a MultiObject field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.FieldValueList<DTOs.Artifact> objects = new DTOs.FieldValueList<DTOs.Artifact>();
objects.Add(new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_1));
objects.Add(new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_2));
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_OBJECT_FIELD, objects));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a MultiObject field on an RDO
Relativity | Services API Guide - 120
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_OBJECT_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DTOs.FieldValueList<DTOs.Artifact> fieldValue =
resultsObject[GUIDS.MULTI_OBJECT_FIELD].GetValueAsMultipleObject<DTOs.Artifact>();
View sample code for updating a MultiObject field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.FieldValueList<DTOs.Artifact> objects = new DTOs.FieldValueList<DTOs.Artifact>();
objects.Add(new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_1));
objects.Add(new DTOs.Artifact(ARTIFACTID.FAKE_OBJECT_2));
obj.Fields.Add(new DTOs.FieldValue(GUIDS.MULTI_OBJECT_FIELD, objects));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their MultiObject fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new ObjectsCondition(GUIDS.MULTI_OBJECT_FIELD,
ObjectsConditionEnum.AnyOfThese,
new Int32[] { ARTIFACTID.FAKE_OBJECT_1, ARTIFACTID.FAKE_OBJECT_2 });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.7 User Fields
In Relativity, a User field contains the rights that a user has to the current workspace. Use these guidelines for
User fields:
n
n
Create and update operations require you to set the User field to a User DTO with the ArtifactID property populated.
On read and query operations, the ValueAsUser property returns the Value property of the User field as
a type kCura.Relativity.Client.DTOs.User, which is populated with the ArtifactID and Name properties.
View sample code for creating an RDO and setting the value of a User field
Relativity | Services API Guide - 121
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.User user = new DTOs.User(ARTIFACTID.USER);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.USER_FIELD, user));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a User field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.USER_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DTOs.User userValue = resultsObject[GUIDS.USER_FIELD].ValueAsUser;
View sample code for updating a User field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
DTOs.User user = new DTOs.User(ARTIFACTID.USER);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.USER_FIELD, user));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their User fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new UserCondition(GUIDS.USER_FIELD,
UserConditionEnum.EqualTo, "User Name");
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.8 WholeNumber Fields
Relativity uses WholeNumber fields to store any natural numbers. Use these guidelines for WholeNumber
fields
Relativity | Services API Guide - 122
n
n
Create and update operations require you to set the WholeNumber field to a whole number value.
Read and query operations on a WholeNumber field return the Value property as an integer using the
ValueAsWholeNumber property.
View sample code for creating an RDO and setting the value of a WholeNumber field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
int wholeNumber = 100;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.WHOLE_NUMBER_FIELD, wholeNumber));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a WholeNumber field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.WHOLE_NUMBER_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
int? fieldValue = resultsObject[GUIDS.WHOLE_NUMBER_FIELD].ValueAsWholeNumber;
View sample code for updating a WholeNumber field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
int wholeNumber = 5;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.WHOLE_NUMBER_FIELD, wholeNumber));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their WholeNumber fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
int queryWholeNumber = 250;
query.Condition = new WholeNumberCondition(GUIDS.WHOLE_NUMBER_FIELD,
NumericConditionEnum.GreaterThan, queryWholeNumber);
Relativity | Services API Guide - 123
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.9 Decimal Fields
In Relativity, Decimal fields store numeric values that may include decimals. Use these guidelines for Decimal
fields:
n
n
Create and update operations require you to set the Decimal field to a decimal value.
Read and query operations on a Decimal field return the Value property of the field as a decimal using
the ValueAsDecimal property.
View sample code for creating an RDO and setting the value of a Decimal field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
var decimalNumber = 100.25;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DECIMAL_FIELD, decimalNumber));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a Decimal field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DECIMAL_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
decimal? fieldValue = resultsObject[GUIDS.DECIMAL_FIELD].ValueAsDecimal;
View sample code for updating a Decimal field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
decimal decimalNumber = 5.0M;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DECIMAL_FIELD, decimalNumber));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their Decimal fields
Relativity | Services API Guide - 124
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
decimal queryDecimal = 50.0M;
query.Condition = new DecimalCondition(GUIDS.DECIMAL_FIELD,
NumericConditionEnum.GreaterThan, new Decimal[] { queryDecimal });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.10 Currency Fields
Relativity uses Currency fields to store numeric values in a currency format. Use these guidelines for Currency
fields:
n
n
Create and update operations require you to set the Currency field to a decimal value.
Read and query operations on a Currency field return the Value property of the field decimal using the
ValueAsCurrency property.
View sample code for creating an RDO and setting the value of a Currency field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
var currencyValue = 100.00M;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.CURRENCY_FIELD, currencyValue));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a Currency field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.CURRENCY_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
decimal? fieldValue = resultsObject[GUIDS.CURRENCY_FIELD].ValueAsCurrency;
View sample code for updating a Currency field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
Relativity | Services API Guide - 125
var currencyValue = 5.00;
obj.Fields.Add(new DTOs.FieldValue(GUIDS.CURRENCY_FIELD, currencyValue));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their Currency fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
decimal currencyValue = 100.00M;
query.Condition = new DecimalCondition(GUIDS.CURRENCY_FIELD,
NumericConditionEnum.GreaterThan, new Decimal[] { currencyValue });
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.11 Date Fields
Relativity uses Date fields to store the date or date and time. Use these guidelines for Date fields:
n
n
Create and update operations require you to set the Date field to a .NET DateTime value.
Read and query operations on a Date field return the Value property of the field as a .NET DateTime
using the ValueAsDate property.
View sample code for creating an RDO and setting the value of a Date field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DATE_FIELD, DateTime.Now));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a Date field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DATE_FIELD, DateTime.Now));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
DateTime? fieldValue = resultsObject[GUIDS.DATE_FIELD].ValueAsDate;
View sample code for updating a Date field on an RDO
Relativity | Services API Guide - 126
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.DATE_FIELD, DateTime.Now));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their Date fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new DateTimeCondition(GUIDS.DATE_FIELD,
DateTimeConditionEnum.GreaterThan, DateTime.Now);
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.2.12 Yes/No Fields
In Relativity, a Yes/No field stores a Boolean value. Use these guidelines for Yes/No fields:
n
n
Create and update operations require you to set the Yes/No field to a .NET Boolean value.
Read and query operations on Yes/No field return the Value property of the field as a .NET Boolean
using the ValueAsYesNo Property.
View sample code for creating an RDO and setting the value of a Yes/No field
DTOs.RDO obj = new DTOs.RDO();
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.YES_NO_FIELD, true));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(obj);
View sample code for reading a Yes/No field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.YES_NO_FIELD));
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Read(obj);
DTOs.RDO resultsObject = results.Results[0].Artifact;
bool? fieldValue = resultsObject[GUIDS.YES_NO_FIELD].ValueAsYesNo;
Relativity | Services API Guide - 127
View sample code for updating a Yes/No field on an RDO
DTOs.RDO obj = new DTOs.RDO(artifactId);
obj.ArtifactTypeGuids.Add(GUIDS.OBJECT_ARTIFACT_TYPE_GUID);
obj.Fields.Add(new DTOs.FieldValue(GUIDS.YES_NO_FIELD, false));
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(obj);
View sample code for querying on RDOs with values in their Yes/No fields
DTOs.Query<DTOs.RDO> query = new DTOs.Query<DTOs.RDO>();
query.ArtifactTypeGuid = GUIDS.OBJECT_ARTIFACT_TYPE_GUID;
query.Fields = DTOs.FieldValue.AllFields;
query.Condition = new BooleanCondition(GUIDS.YES_NO_FIELD,
BooleanConditionEnum.EqualTo, true);
DTOs.ResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(query);
6.7.3 Supported operations for Field types
The following operations are supported for Field types on DTOs:
Operation
Create a Field on a DTO
Read Field metadata
Delete a Field (except system Field) from a DTO
Query on Field metadata
Supported for Fields on DTOs
RDO and Document DTOs
All DTOs
All DTOs
All DTOs
Note: For information about updating DTOs, see DTO reference and code samples on page 81. When you
update Documents and RDOs, the value of each Field on an object in the Fields collection is overwritten
with a new value, except for MultiChoice Fields. See MultiChoice Fields on page 117.
6.7.4 Field code samples
Relativity uses fields to store object information, document metadata, and coding choices. For more
information, see Fields in the Relativity 8.1 Documentation site.
The Services API supports create, read, delete, and query operations on a Field DTO.
6.7.4.1 Creating a Field
You can use the Create() on the Field repository to add a new field to Relativity. The ObjectType indicates the
object associated with this Field, such as Document as illustrated in this sample code.
Relativity | Services API Guide - 128
public static bool Create_Field_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Create a Field DTO and populate the Fields.
DTOs.Field dto = new DTOs.Field();
dto.Name = "This is a Single Choice field by GUID11";
dto.ObjectType = new DTOs.ObjectType() { DescriptorArtifactTypeID = (int)
ArtifactType.Document };
// The ObjectType DTO can also be instantiated with the GUID of the
// ObjectType instead of setting the DescriptorArtifactTypeID.
// dto.ObjectType = new DTOs.ObjectType(new Guid("4D3BA67C-9F88-4D29-8E6C6DECB6A682D1"));
dto.FieldTypeID = kCura.Relativity.Client.FieldType.SingleChoice;
dto.IsRequired = false;
dto.Unicode = false;
dto.AvailableInFieldTree = false;
dto.OpenToAssociations = false;
dto.Linked = false;
dto.AllowSortTally = true;
dto.Wrapping = true;
dto.AllowGroupBy = false;
dto.AllowPivot = false;
dto.IgnoreWarnings = true;
dto.Width = "";
// STEP 2: Call the Create method on the repository and pass the DTO.
WriteResultSet<DTOs.Field> resultSet;
try {
resultSet = proxy.Repositories.Field.Create(dto);
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!resultSet.Success) {
Console.WriteLine("Error: " + resultSet.Message);
foreach (Result<DTOs.Field> result in resultSet.Results) {
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
Console.WriteLine("Overall status of creating a Field: " +
resultSet.Success);
Relativity | Services API Guide - 129
Console.WriteLine("New Artifact ID: " + resultSet.Results.FirstOrDefault
().Artifact.ArtifactID);
return true;
}
6.7.4.2 Creating a Relational Field
In Relativity, a relational field is used to identify a group of related documents. You can upload your own icon
for a relational field, which is displayed in the Related Items pane of the reviewer interface. For more
information, see PaneIcon property on page 144.
This code sample illustrates how to create a relational Field and set its pane icon.
public void Create_RelationalField()
{
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
var fieldDTO = new kCura.Relativity.Client.DTOs.Field();
fieldDTO.Name = "Relational Field 1";
fieldDTO.FieldTypeID = (Int32)FieldType.FixedLengthText;
fieldDTO.ObjectType = new kCura.Relativity.Client.DTOs.ObjectType() {
DescriptorArtifactTypeID = (Int32)ArtifactType.Document };
fieldDTO.Length = 100;
fieldDTO.IsRequired = false;
fieldDTO.IncludeInTextIndex = false;
fieldDTO.Unicode = false;
fieldDTO.AllowHTML = false;
fieldDTO.OpenToAssociations = false;
fieldDTO.Linked = false;
fieldDTO.AllowSortTally = false;
fieldDTO.Width = "100";
fieldDTO.Wrapping = false;
fieldDTO.AllowPivot = false;
fieldDTO.AllowGroupBy = false;
// Set IsRelational to true.
fieldDTO.IsRelational = true;
// After IsRelational is set to true, add other required fields.
fieldDTO.FriendlyName = "New Relational Field Friendly Name";
Relativity | Services API Guide - 130
fieldDTO.Order = 100;
fieldDTO.ImportBehavior = ImportBehavior.LeaveBlankValuesUnchanged;
fieldDTO.RelationalView = null; //Null is the default "All Items"
view.
// The field "PaneIcon" takes a RelationalFieldIcon object that
contains a path and a byte array
// for the icon that represents the field at the bottom of the
document review page.
string path = "c:\\icon.png";
System.IO.FileStream ifStream = System.IO.File.OpenRead(path);
Int32 len = (Int32)ifStream.Length;
System.IO.BinaryReader reader = new System.IO.BinaryReader(ifStream);
byte[] byteArr = new byte[len];
reader.Read(byteArr, 0, len);
fieldDTO.PaneIcon = new RelationalFieldIcon(path, byteArr);
WriteResultSet<kCura.Relativity.Client.DTOs.Field> writeResults =
proxy.Repositories.Field.Create(fieldDTO);
if (writeResults.Success)
{
Console.WriteLine(string.Format("Field with name {0} was created
with Artifact ID {1}.", fieldDTO.Name, writeResults.Results
[0].Artifact.ArtifactID));
}
else
{
Console.WriteLine(string.Format("An error occurred creating field:
{0}", writeResults.Message));
for (Int32 i = 0; i <= writeResults.Results.Count - 1; i++)
{
if (!writeResults.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in create request {0}: {1}", i, writeResults.Results
[i].Message));
foreach (string warning in writeResults.Results[0].WarningMessages)
{
Console.WriteLine("Warning: {0}", warning);
}
}
Relativity | Services API Guide - 131
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
}
6.7.4.3 Reading a Field
To read values on a Field, you can use the Read() method on the Field repository as illustrated in this code
sample.
public static bool Read_Field_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Call the Read() method on the Field repository, passing a Field
DTO.
ResultSet<DTOs.Field> results;
try {
results = proxy.Repositories.Field.Read(new DTOs.Field(1035984) { Fields
= FieldValue.AllFields });
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!results.Success) {
Console.WriteLine("Error: " + results.Message);
foreach (Result<DTOs.Field> result in results.Results) {
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
// STEP 2: Get the Field artifact from the read results.
DTOs.Field fieldArtifact = results.Results.FirstOrDefault().Artifact;
Console.WriteLine("Field Name: " + fieldArtifact.Name);
Console.WriteLine("Field Type: " + fieldArtifact.FieldTypeID);
Console.WriteLine("Object Type: " +
fieldArtifact.ObjectType.DescriptorArtifactTypeID);
Relativity | Services API Guide - 132
foreach (DTOs.Choice choice in fieldArtifact.Choices)
Console.WriteLine("Valid Choice for Field = " + choice.Name + ":" +
choice.ArtifactID );
return true;
}
6.7.4.4 Deleting a Field
You can use the Delete() method on the Field repository to remove fields as illustrated in this code sample.
public static bool Delete_Field_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Define the Field to delete.
kCura.Relativity.Client.DTOs.Field dto = new
kCura.Relativity.Client.DTOs.Field(1039140);
ResultSet<kCura.Relativity.Client.DTOs.Field> results;
// STEP 2: Delete the Field.
try
{
results = proxy.Repositories.Field.Delete(dto);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
foreach (Result<kCura.Relativity.Client.DTOs.Field> result in
results.Results)
{
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
return true;
}
Relativity | Services API Guide - 133
6.7.4.5 Querying for a Field
This code sample illustrates how to set query conditions, call the Query() method on the Field repository, and
iterate through the result set. For more information, see Querying on page 227.
public static bool Query_Field_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Define the query.
Query<kCura.Relativity.Client.DTOs.Field> query = new
Query<kCura.Relativity.Client.DTOs.Field>();
query.Fields = FieldValue.AllFields;
query.Condition =
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, 1039140);
ResultSet<kCura.Relativity.Client.DTOs.Field> results;
// STEP 2: Query for the Field.
try
{
results = proxy.Repositories.Field.Query(query);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
foreach (Result<kCura.Relativity.Client.DTOs.Field> result in
results.Results)
{
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
// STEP 3: Get the Field artifact from the read results.
kCura.Relativity.Client.DTOs.Field fieldArtifact =
results.Results.FirstOrDefault().Artifact;
Console.WriteLine("Field Name: " + fieldArtifact.Name);
Console.WriteLine("Field Type: " + fieldArtifact.FieldTypeID);
Relativity | Services API Guide - 134
Console.WriteLine("Object Type: " +
fieldArtifact.ObjectType.DescriptorArtifactTypeID);
foreach (kCura.Relativity.Client.DTOs.Choice choice in
fieldArtifact.Choices)
Console.WriteLine("Valid Choice for Field = " + choice.Name + ":" +
choice.ArtifactID);
return true;
}
6.7.5 File field
A File type field is used to upload a file for a non-document object. When you add a File field, Relativity
automatically creates other fields containing file metadata, such as File Size, File Icon, and Text fields.
Note: The following sample code uses the variable called proxy to reference an instance of the RSAPIClient
class that already has the APIOptions property set. For simplicity, this sample code doesn't check on
completed operations or provide error handling.
6.7.5.1 Creating a File field on an RDO
You can create a dynamic object and then add a File field on it. The following sections describe this two part
process.
Creating a Dynamic ObjectType
Create a Dynamic ObjectType that will be referenced in other code samples illustrating File field usage. This
Dynamic ObjectType will be called Our File Container.
Create an ObjectType instance as follows:
var objectType = new ObjectType();
Set the values for the appropriate fields:
objectType.CopyInstancesOnWorkspaceCreation = false;
objectType.Name = “Our File Container”;
objectType.ParentArtifactTypeID = (int)ArtifactType.Case;
objectType.Pivot = false;
objectType.RelativityApplications = new FieldValueList<RelativityApplication>
();
objectType.SnapshotAuditingEnabledOnDelete = true;
Using the DTO layer, call the Create() method of the ObjectType repository:
Relativity | Services API Guide - 135
var createResults = proxy.Repositories.ObjectType.Create(objectType);
Save the value of the ArtifactID property for later use in file uploading:
var ourFileContainerInstanceArtifactId = createResults.Results
[0].Artifact.ArtifactID;
To create an instance of the Dynamic ObjectType, you need to determine the DescriptorArtifactTypeID, which
is a unique identifier for the newly created Dynamic Object type. Create a Query instance as follows:
var query = new Query<ObjectType>();
Set the values for the appropriate fields. In general, you request only the fields that you need, rather than use
the AllFields directive.
query.Condition = new TextCondition(“Name”, TextConditionEnum.EqualTo, “Our
File Container”);
query.Fields = FieldValue.AllFields;
Call the Query() method of the ObjectType repository:
var queryResults = proxy.Repositories.ObjectType.Query(query);
Save the value of the DescriptorArtifactTypeID property for later use in field creation. You might also want to
confirm that the query executed successfully.
var descriptorArtifactTypeId = queryResults.Results
[0].Artifact.DescriptorArtifactTypeID;
Creating a File field
You can create a new File field on a Dynamic ObjectType. In the following sample code, the variable
descriptorArtifactTypeId refers to the value retrieved from Creating a File field on an RDO on the previous
page.
Create a Field instance:
var field = new kCura.Relativity.Client.DTOs.Field();
Set the values for the appropriate fields:
Relativity | Services API Guide - 136
field.AllowGroupBy = false;
field.AllowPivot = false;
field.AllowSortTally = false;
field.FieldTypeID = FieldType.File;
field.IgnoreWarnings = true;
field.IsRequired = false;
field.Linked = false;
field.Name = “File Field For Our File Container”;
This ObjectType was added in Creating a File field on an RDO on page 135:
field.ObjectType = new ObjectType { DescriptorArtifactTypeID =
descriptorArtifactTypeId };
field.OpenToAssociations = false;
field.Width = String.Empty;
field.Wrapping = false;
Call the Create() method of the Field repository:
var createResults = proxy.Repositories.Field.Create(field);
Save the value of the ArtifactID property for use in file uploading later:
var fileFieldArtifactId = createResults.Results[0].Artifact.ArtifactID;
6.7.5.2 Uploading to a File field
You can upload a file to a File field. You need to obtain the following identifiers to upload the file:
n
n
ArtifactID of the File field associated with the object type
ArtifactID of the object instance with a File field that needs to be populated
Use this variable for the newly created File field:
fileFieldArtifactId
Use this variable for the newly created instance of our Dynamic Object type (Our File Container):
ourFileContainerInstanceArtifactId
Create an UploadRequest instance:
var uploadRequest = new UploadRequest(proxy.APIOptions);
Relativity | Services API Guide - 137
Set the values for the appropriate fields:
uploadRequest.Metadata.FileName = @”C:\path\to\my\file.docx”;
uploadRequest.Metadata.FileSize = new FileInfo
(uploadRequest.Metadata.FileName).Length;
This optional property indicates that the current contents in the File field will be overwritten:
uploadRequest.Overwrite = true;
uploadRequest.Target.FieldId = fileFieldArtifactId;
uploadRequest.Target.ObjectArtifactId = ourFileContainerInstanceArtifactId;
(Optional) Register an event handler for the UploadComplete event:
proxy.UploadComplete += UploadCompleteHandler;
Call the Upload() method on the RSAPIClient:
proxy.Upload(uploadRequest);
6.7.5.3 Downloading from a File field
You can download a file from a File field. The Services API provides an overloaded Download() method for this
purpose:
n
n
DownloadResponse Download(FileRequest fileRequest, string outputPath) - Downloads the file to
the location specified by outputPath.
KeyValuePair<DownloadResponse, Stream> Download(FileRequest fileRequest) - Downloads the file
to the Stream of the KeyValuePair.
In addition, you need to obtain the following identifiers to upload the file:
n
n
ArtifactID of the File field associated with the object type
ArtifactID of the object instance with a file that needs to be downloaded
Use this variable for the ArtifactID of the newly created File field:
fileFieldArtifactId
Use this variable for the newly created instance of our Dynamic Object type (Our File Container):
ourFileContainerInstanceArtifactId
Create a FileRequest instance as follows:
Relativity | Services API Guide - 138
var fileRequest = new FileRequest(proxy.APIOptions);
fileRequest.Target.FieldId = fileFieldArtifactId;
fileRequest.Target.ObjectArtifactId = ourFileContainerInstanceArtifactId;
Register an event handler for the DownloadComplete event:
proxy.DownloadComplete += DownloadCompleteHandler;
Call one of the overload Download() methods on the RSAPIClient:
proxy.Download(fileRequest, @”C:\path\to\downloaded\file.docx”);
6.7.5.4 Getting a download URL for a File field
You can retrieve a URL from the File field on a Dynamic Object and then use the URL to download the
associated file. The following code sample illustrates how to call the GetFileFieldDownloadURL() method on
the proxy and download the required file.
public static bool GetFileFieldDownloadURL(IRSAPIClient proxy)
{
// STEP 1: Set APIOptions and instantiate a new DownloadURLRequest with the
APIOptions.
proxy.APIOptions.WorkspaceID = 1015926;
var downloadUrlRequest = new DownloadURLRequest(proxy.APIOptions);
// STEP 2: Set properties in the DownloadURLRequest.
downloadUrlRequest.BaseURI = new Uri("http://localhost");
// Set the ObjectArtifactID or ObjectArtifactGuid that identifies the
instance of the RDO.
downloadUrlRequest.Target.ObjectArtifactGuid = new Guid("B5FD94BB-0226-4CA5B227-5F3F7BEE4D8A");
// Set the FieldID, FieldName, or FieldGuid of the File File.
downloadUrlRequest.Target.FieldId = 1042467;
// STEP 3: Call the GetFileFieldDownloadURL method on the proxy.
DownloadURLResponse response;
try {
response = proxy.Repositories.RDO.GetFileFieldDownloadURL
(downloadUrlRequest);
}
catch (Exception ex) {
Relativity | Services API Guide - 139
Console.WriteLine("An error occurred calling GetFileFieldDownloadURL: {0}
", ex.Message);
return false;
}
if (response.Success) {
Console.WriteLine("File Field Download URL: {0}", response.URL);
}
else {
Console.WriteLine("An error occurred calling GetFileFieldDownloadURL: {0}
", response.Message);
return false;
}
// STEP 4: Download the File using the URL.
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost/");
HttpResponseMessage httpResponse = httpClient.GetAsync(response.URL).Result;
if (httpResponse.IsSuccessStatusCode) {
try {
// Read the file.
Stream resultStream = httpResponse.Content.ReadAsStreamAsync().Result;
var contentDisposition =
httpResponse.Content.Headers.ContentDisposition;
string fileName = contentDisposition.FileName;
using (var fileStream = File.Create("C:\\path" + fileName)) {
resultStream.CopyTo(fileStream);
}
Console.WriteLine("Received file: {0}", fileName);
}
catch (Exception ex) {
// An exception occurred when attempting to read and save the file
locally.
// Handle the exception.
Console.WriteLine("Error saving File locally: {0}", ex.Message);
return false;
}
}
else {
Console.WriteLine("HTTP response not successful: {0}",
httpResponse.StatusCode);
return false;
Relativity | Services API Guide - 140
}
return true;
}
6.7.5.5 Clearing a File field
You can clear a File field through the Services API. You need to obtain the following identifiers to clear the field:
n
n
ArtifactID of the File field associated with the object type
ArtifactID of the object instance with a File fields that needs to be cleared
Use this variable for the ArtifactID of the newly created File field:
fileFieldArtifactId
Use this variable for the newly created instance of our Dynamic Object type:
ourFileContainerInstanceArtifactId
Create a FileRequest instance as follows:
var fileRequest = new FileRequest(proxy.APIOptions);
fileRequest.Target.FieldId = fileFieldArtifactId;
fileRequest.Target.ObjectArtifactId = ourFileContainerInstanceArtifactId;
Call the Clear() method on the RSAPIClient:
proxy.Clear(fileRequest);
6.7.6 Fields used by Field type, User, and Group
Field, User, and Group objects use special fields that aren't used by other system types.
6.7.6.1 Fields used by the Field objects
The Field system type uses specialized properties including IgnoreWarnings and the PaneIcon. In addition, the
Result object available when a Field is create contains the specialized properties WarningMessage and
IsWarning.
WarningMessage and IsWarning properties
The Create function can return warning messages when a Field object is created. If there are warnings, these
messages are set on the WarningMessage property of the Result object, and IsWarning property is set to
True. Since the WarningMessage property has a List datatype, multiple warning messages can be returned if
necessary.
Relativity | Services API Guide - 141
IgnoreWarnings property
The Field DTO contains an IgnoreWarnings Boolean property, which you can use to control how warning
messages are handled. When the IgnoreWarnings property is set to False and warnings are returned, the
Create call will fail. When IgnoreWarnings property is set to True and warnings are returned, the Create call will
succeed.
In most cases, the code calling the API handles messages returned when the IgnoreWarnings property is set
to False, and a Create call returns warnings. Depending on the programming logic, the IgnoreWarnings
property could be set to True, and the Create call could be repeated when the warnings should be ignored.
When Fields are created, the Message property of a Result object can return multiple errors. Each error will be
prefixed with the string API_Field_Validation_Error. This functionality contrasts with other areas in the API,
which return only a single error message.
View sample code illustrating how to use IgnoreWarnings property on a Field
public void Create_Field_With_IgnoreWarnings()
{
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
var fieldDTO = new kCura.Relativity.Client.DTOs.Field();
fieldDTO.Name = "Test Field with Warning 1";
fieldDTO.FieldTypeID = (Int32)FieldType.FixedLengthText;
fieldDTO.ObjectType = new kCura.Relativity.Client.DTOs.ObjectType() {
DescriptorArtifactTypeID = (Int32)ArtifactType.Document };
fieldDTO.Length = 100;
fieldDTO.IsRequired = false;
fieldDTO.IncludeInTextIndex = false;
fieldDTO.Unicode = false;
fieldDTO.AllowHTML = false;
fieldDTO.OpenToAssociations = false;
fieldDTO.Linked = false;
fieldDTO.AllowSortTally = false;
fieldDTO.Width = "100";
fieldDTO.Wrapping = false;
fieldDTO.AllowPivot = false;
fieldDTO.IsRelational = false;
// Set AllowGroupBy to true, which should trigger the warning message:
// "Setting Allow Group By on a text field containing a large number
can
// of values can negatively impact system performance."
Relativity | Services API Guide - 142
// When Ignore Warnings
Create call fails.
// When Ignore Warnings
Create call succeeds.
fieldDTO.AllowGroupBy =
fieldDTO.IgnoreWarnings
is set to false and warnings are returned, the
is set to true and warnings are returned, the
true;
= false;
WriteResultSet<kCura.Relativity.Client.DTOs.Field> writeResults =
proxy.Repositories.Field.Create(fieldDTO);
if (writeResults.Success)
{
Console.WriteLine(string.Format("Field with name {0} was created
with ArtifacT ID {1}.",
fieldDTO.Name, writeResults.Results[0].Artifact.ArtifactID));
}
else
{
Console.WriteLine(string.Format("An error occurred creating field:
{0}",
writeResults.Message));
for (Int32 i = 0; i <= writeResults.Results.Count - 1; i++)
{
if (!writeResults.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in create request {0}: {1}", i,
writeResults.Results[i].Message));
foreach (string warning in writeResults.Results[0].WarningMessages)
{
Console.WriteLine("Warning: {0}", warning);
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
Relativity | Services API Guide - 143
}
PaneIcon property
When you create a Relational Field, you must set a property for the pane icon that is displayed in the
Relativity viewer. This icon should be a PNG of 16 x 16 pixels. On DTOs, the pane icon uses the
RelationalFieldIcon object, which contains the same Data and Path properties as the FileValue object. You
must set the Path and Data properties on the PaneIcon when creating a Relational Field. The Field DTO has a
property called PaneIcon that takes a RelationalFieldIcon object as its value. On query and read operations,
only the Path value is returned.
This code sample illustrates how to create a Relational Field with a PaneIcon. It uses the RelationalFieldIcon.
var fieldDTO = new DTOs.Field();
string path = "c:\\path\\icon.png";
System.IO.FileStream ifStream = System.IO.File.OpenRead(path);
Int32 len = (Int32)ifStream.Length;
System.IO.BinaryReader reader = new System.IO.BinaryReader(ifStream);
byte[] byteArr = new byte[len];
reader.Read(byteArr, 0, len);
fieldDTO.PaneIcon = new RelationalFieldIcon(path, byteArr);
/// Set additional fields on the Field DTO.
DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.Field.Create
(fieldDTO);
This code sample illustrates how to read a PaneIcon field on a Field.
DTOs.Field dto = new DTOs.Field(1038285);
dto.Fields.Add(new DTOs.FieldValue(DTOs.FieldFieldNames.PaneIcon));
var readResults = proxy.Repositories.Field.Read(dto);
DTOs.RelationalFieldIcon paneIcon =
readResults.Results[0].Artifact
[DTOs.FieldFieldNames.PaneIcon].ValueAsRelationalFieldIcon;
6.7.6.2 Fields used by Group and User objects
Groups and Users require several special fields that aren't used by other system types. These fields include
Password, User, and Group.
Password fields
To create a User, the Password, User Must Change Password on Next Login, and Send New Password To
fields are required password settings. Use these general guidelines when working with password fields:
Relativity | Services API Guide - 144
n
n
When working with Users, query for the values needed and save their Choice IDs in variables or a cache
as you would for other Single Choice fields. Single Choice fields accept Choice IDs rather than Choice
names.
The general guidelines for creating a User also apply on update, except that the Password field can be
set to the Choice called Use Current Password. In this case, no other password fields are required,
except for User Must Change Password On Next Login. This setting indicates that the password
shouldn't be altered.
Note: These Fields exist as properties on the User DTO.
Password
Password is a Single Choice field. Use the following guidelines when working with this field:
n
n
n
n
n
Set this Field to one of these Choice values: Auto-generate Password or Manually set password.
Retrieve the Choice IDs for this Field by calling the Query method and passing in a Query object with a
TextCondition on the field named Choice Type with Password as the text.
When the Password field is set to Auto-generate Password, a valid password is automatically generated for the user.
When the Password field is set to Manually set password, a Field named New Password is required.
This Field is used to provide the new password when a User is being created.
Make sure that the password meets the following requirements:
o
o
o
o
Limited to between 8 and 50 characters in length.
Contains at least one uppercase letter, one lower case letter, one numeral, and one special character.
Doesn't contain the special characters backslash (\), quotation mark ("), greater than (>), or less
than (<).
Can't be one of the previous X passwords, where X is the value in the EDDS Configuration Table
named MaxPasswordHistory.
User Must Change Password on Next Login
User Must Change Password on Next Login is a Yes/No field.
Send New Password To
Send New Password To field is a Single Choice Field. Use the following guidelines when working with this field:
n
Set the Send New Password To field to one of these Choice ID values:
Me (email) - Sends the password to the user logged in to the Services API.
This user (email) - Sends the password to the user being created or edited.
o Return - Create or Update call returns the password in a field named Password in the
MetaDataArtifact property of a Result object.
Retrieve the Choice IDs for the Send New Password To field by calling the Query() method and passing
in a Query object with a TextCondition on the field named Choice Type with Send new password to as
the text.
Configuration settings for sending email messages are stored in the EDDS Configuration Table.
o
o
n
n
Groups field
When creating or updating a User, you can include the Groups field to set or modify the groups that include
the user as a member. A Groups property also exists on the Group DTO. Follow these guidelines when working
Relativity | Services API Guide - 145
with the Groups field:
n
n
n
n
On create, the value of the Groups field is a list of ArtifactIDs, which indicate the groups that will include
the user as a member.
On create, don't include the Everyone group in the list of ArtifactIDs. The user is automatically added to
the Everyone group.
If an error while adding a user to a group, the user will still be created.
On update, the value of the Groups field is a MultiUpdateValue object, which contains the Value and
Behavior properties. The Value property is a list of ArtifactIDs, and Behavior property specifies how the
Artifact IDs are applied to the user.
Note: You can only use the MultiUpdateValue class as a parameter when you update User and Group objects.
This class has a Behavior property, which is a MultiUpdateBehavior enum. This enumeration is also available
only for use with User and Group objects.
n
n
When using DTOs, the Groups property takes a FieldValueList containing a List of Group DTOs.
If the behavior is set to Update, you must include the Everyone group in the list of ArtifactIDs.
Users field
You can include the User field when you want to set or modify users assigned to the Group that you are
updating or creating. Follow these guidelines when working with the Users field:
n
n
On create, the value of the Users field is a list of ArtifactIDs that indicate the users that you want
included in a group.
On update, the value of the Users field is MultiUpdateValue object, which contains the Value and
Behavior properties. The Value property is a list of ArtifactIDs, and Behavior property specifies how the
ArtifactIDs should be applied to the user.
Note: You can only use the MultiUpdateValue class as a parameter when you update User and Group objects.
This class has a Behavior property, which is a MultiUpdateBehavior enum. This enumeration is also available
only for use with User and Group objects.
n
When using the DTOs, the Users property takes a MultiUserFieldValueList. When you have a .NET List
of User DTOs (FieldValueList<DTOs.Choice>), the UpdateBehavior property indicates how the IDs in the
FieldValueList are applied to the field (Replace, Add, or Remove). The default behavior is Replace, when
no value is specified.
6.7.7 Constant Field names
The Services API supports constant strings for Field names on multiple Relativity objects. Most of these
classes extend the base class ArtifactFieldNames. You may also want to consider using enumerations or
constants instead of strings in your code. The Services API uses these constant Field names when you enable
the StrictMode property or use DTOs. See the following resources:
n
n
n
Data Transfer Objects (DTOs) on page 67
StrictMode property and Field directives on page 73
Best practices for the Services API on page 75
ArtifactFieldNames (base class)
Relativity | Services API Guide - 146
Property
SystemCreatedBy
SystemCreatedOn
SystemLastModifiedBy
SystemLastModifiedOn
TextIdentifier
Field Name
"System Created By"
"System Created On"
"System Last Modified By"
"System Last Modified On"
"Relativity Text Identifier"
ArtifactQueryFieldNames (doesn't extend ArtifactFieldNames)
Property
ArtifactID
ArtifactGUID
ParentArtifactID
Field Name
"Artifact ID"
"Artifact GUID"
"Parent Artifact ID"
BatchFieldNames
Property
AssignedTo
BatchNumber
BatchSet
BatchSize
BatchStatus
BatchUnit
Name
Reviewed
Field Name
"Assigned To"
"Batch Number"
"Batch Set"
"Batch Size"
"Batch Status"
"Batch Unit"
"Name"
"Reviewed"
BatchSetFieldNames
Property
AutoBatch
AutoCreateRateMinutes
BatchDataSource
BatchPrefix
BatchUnitField
DocumentsToBeBatched
FamilyField
LastErrorReported
LastSuccessfulRun
MaximumBatchSize
MinimumBatchSize
Name
ReviewedField
Status
ClientFieldNames
Relativity | Services API Guide - 147
Field Name
"Auto Batch"
"Auto Create Rate(minutes)"
"Batch Data Source"
"Batch Prefix"
"Batch Unit Field"
"Documents to be Batched"
"Family Field"
"Last Error Reported"
"Last Successful Run"
"Maximum Batch Size"
"Minimum Batch Size"
"Name"
"Reviewed Field"
"Status"
Property
ClientNumber
Name
Status
Field Name
"Client Number"
"Name"
"Status"
ChoiceFieldNames
Property
ChoiceTypeID
HighlightStyleID
Name
ObjectTypeName
Order
RelativityApplications
Field Name
"Choice Type ID"
"Highlight Style ID"
"Name"
"Object Type Name"
"Order"
"Relativity Applications"
DocumentFieldNames
Property
Batch
Batch_AssignedTo
Batch_BatchSet
Batch_Status
FileIcon
FolderName
HasImages
HasInlineTags
HasNative
RelativityImageCount
RelativityNativeFileLocation
RelativityNativeTimeZoneOffset
RelativityNativeType
SupportedByViewer
TimeZoneField
Field Name
"Batch"
"Batch::Assigned To"
"Batch::Batch Set"
"Batch::Status"
"File Icon"
"Folder Name"
"Has Images"
"Has Inline Tags"
"Has Native"
"Relativity Image Count"
"Relativity Native File Location"
"Relativity Native Time Zone Offset"
"Relativity Native Type"
"Supported By Viewer"
"Time Zone Field"
ErrorFieldNames
Property
FullError
Message
SendNotification
Server
Source
URL
Workspace
FieldFieldNames
Relativity | Services API Guide - 148
Field Name
"Full Error"
"Message"
"Send Notification"
"Server"
"Source"
"URL"
"Workspace"
Property
AllowGroupBy
AllowHTML
AllowPivot
AllowSortTally
AssociativeObjectType
AutoAddChoices
AvailableInFieldTree
AvailableInViewer
Choices
FieldTreeView
FieldTypeID
FilterType
Formatting
FriendlyName
IgnoreWarnings
ImportBehavior
IncludeInTextIndex
IsIdentifier
IsRelational
IsRequired
KeyboardShortcut
Length
Linked
Name
NoValue
ObjectType
OpenToAssociations
Order
PaneIcon
PopupPickerView
PropagateTo
RelationalView
RelativityApplications
Unicode
Width
Wrapping
YesValue
Field Name
"Allow Group By"
"Allow HTML"
"Allow Pivot"
"Allow Sort/Tally"
"Associative Object Type"
"Auto Add Choices"
"Available In Field Tree"
"Available In Viewer"
"Choices"
"Field Tree View"
"Field Type ID"
"Filter Type"
"Formatting"
"Friendly Name"
"Ignore Warnings"
"Import Behavior"
"Include in Text Index"
"Is Identifier"
"Is Relational"
"Is Required"
"Keyboard Shortcut"
"Length"
"Linked"
"Name"
"No Value"
"Object Type"
"Open to Associations"
"Pane Order"
"Pane Icon"
"Popup Picker View"
"Propagate To"
"Relational View"
"Relativity Applications"
"Unicode"
"Width"
"Wrapping"
"Yes Value"
FolderFieldNames
Property
Name
Relativity | Services API Guide - 149
Field Name
"Name"
GroupFieldNames
Property
GroupType
Name
Users
WorkspaceGroupIDs
Workspaces
Field Name
"Group Type"
"Name"
"Users"
"Workspace Group IDs"
"Workspaces"
LayoutFieldNames
Property
Name
ObjectType
Order
OverwriteProtection
RelativityApplications
Field Name
"Name"
"Object Type"
"Order"
"Overwrite Protection"
"Relativity Applications"
MarkupSetFieldNames
Property
Name
Order
RedactionText
Field Name
"Name"
"Order"
"Redaction Text"
ObjectTypeFieldNames
Property
CopyInstancesOnWorkspaceCreation
DescriptorArtifactTypeID
Dynamic
Name
ParentArtifactTypeID
Pivot
RelativityApplications
SnapshotAuditingEnabledOnDelete
ViewEnabled
Field Name
"Copy Instances On Workspace Creation"
"Descriptor Artifact Type ID"
"Dynamic"
"Name"
"Parent ArtifactTypeID"
"Pivot"
"Relativity Applications"
"Snapshot Auditing Enabled On Delete"
"View Enabled"
RDOFieldNames (doesn't extend ArtifactFieldNames)
Property
Name
Field Name
"Name"
RelativityApplicationFieldNames
Property
AgentTypes
ApplicationFields
ApplicationInstallationStatus
Relativity | Services API Guide - 150
Field Name
"Agent Types"
"Fields"
"Application Installation Status"
Property
ApplicationIsDirty
Choices
CustomPages
EventHandlers
LastExported
Layouts
Locked
Name
ObjectRules
ObjectTypes
OriginSignature
RelativityScripts
TabDisplay
Tabs
Version
Views
Field Name
"Application Is Dirty"
"Choices"
"Custom Pages"
"Event Handlers"
"Last Exported"
"Layouts"
"Locked"
"Name"
"Object Rules"
"Object Types"
"Origin Signature"
"Relativity Scripts"
"Tab Display"
"Tabs"
"Version"
"Views"
RelativityScriptFieldNames
Property
Body
Category
Description
Key
Name
RelativityApplications
Version
Field Name
"Body"
"Category"
"Description"
"Key"
"Name"
"Relativity Applications"
"Version"
TabFieldNames
Property
ExternalLink
IsDefault
IsVisible
LinkType
Name
ObjectType
Order
RelativityApplications
TabDisplay
UserFieldNames
Relativity | Services API Guide - 151
Field Name
"External Link"
"Is Default"
"Is Visible"
"Link Type"
"Name"
"Object Type"
"Order"
"Relativity Applications"
"Tab Display"
Property
AdvancedSearchPublicByDefault
AuthenticationData
BetaUser
ChangePassword
ChangePasswordNextLogin
ChangeSettings
Client
DataFocus
DefaultSelectedFileType
DocumentSkip
EmailAddress
EnforceViewerCompatibility
FirstName
FullName
Groups
InvalidLoginAttempts
ItemListPageLength
KeyboardShortcuts
LastName
MaximumPasswordAge
NativeViewerCacheAhead
Password
PasswordAction
PasswordLastResetOn
RelativityAccess
SendPasswordTo
ShowFilters
SkipDefaultPreference
TrustedIPs
Type
Workspaces
WorkspaceUserIDs
Field Name
"Advanced Search Public By Default"
"Authentication Data"
"Beta User"
"Change Password"
"Change Password Next Login"
"Change Settings"
"Client"
"Data Focus"
"Default Selected File Type"
"Document Skip"
"Email Address"
"Enforce Viewer Compatibility"
"First Name"
"Full Name"
"Groups"
"Invalid Login Attempts"
"Item List Page Length"
"Keyboard Shortcuts"
"Last Name"
"Maximum Password Age"
"Native Viewer Cache Ahead"
"Password"
"Password Action"
"Password Last Reset On"
"Relativity Access"
"Send Password To"
"Show Filters"
"Skip Default Preference"
"Trusted IPs"
"Type"
"Workspaces"
"Workspace User IDs"
ViewFieldNames
Property
DisplayField
GroupDefinitionField
IndentationDefinitionField
IsVisible
Name
ObjectType
Relativity | Services API Guide - 152
Field Name
"Display Field"
"Group Definition Field"
"Indentation Definition Field"
"Is Visible"
"Name"
"Object Type"
Property
Order
RelativityApplications
RenderLinks
VisibleInDropdown
VisualizationType
Field Name
"Order"
"Relativity Applications"
"Render Links"
"Visible In Dropdown"
"Visualization Type"
WorkspaceFieldNames
Property
Accessible
Client
DatabaseLocation
DefaultFileLocation
DownloadHandlerApplicationPath
MatterID
Name
ResourcePoolID
RootFolderID
ServerID
SQLFullTextLanguageCodeID
Status
Field Name
"Accessible"
"Client"
"Database Location"
"Default File Location"
"Download Handler Application Path"
"Matter ID"
"Name"
"Resource Pool ID"
"Root Folder ID"
"Server ID"
"SQL Full Text Language Code ID"
"Status"
6.8 Folder
Within a Relativity workspace, you can use folders to organize content. For more information, see the
Relativity 8.1 Documentation site.
The Services API supports perform create,read, delete, and query operations on a Folder DTO.
6.8.1 Creating a Folder
You can use the Create() method on the Folder repository to add a new folder to Relativity as illustrated in this
code sample.
public static bool Create_Folder_Using_Repository(IRSAPIClient proxy)
{
//STEP 1: Create a Folder object.
DTOs.Folder folder = new DTOs.Folder { ParentArtifact = new DTOs.Artifact
(1003697), Name = "My New Folder" };
//STEP 2: Set Folder properties.
//STEP 3: Create the Folder.
DTOs.WriteResultSet<DTOs.Folder> results;
try
Relativity | Services API Guide - 153
{
results = proxy.Repositories.Folder.Create(folder);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//STEP 4: Check for success.
if (!results.Success)
{
Console.WriteLine("Error: " + results.Message);
return false;
}
else
{
Console.Write("Folder created successfully.");
}
return true;
}
6.8.2 Reading a Folder
To read Field values on a Folder, you can use the Read() method on the Folder repository as illustrated in this
code sample.
public static bool Read_Folder_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Read current values.
Folder requestArtifact = new Folder(1003697);
requestArtifact.Fields.Add(new FieldValue(FolderFieldNames.Name));
ResultSet<Folder> readResult1;
try
{
readResult1 = proxy.Repositories.Folder.Read(requestArtifact);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred while reading the
folder: {0}", ex.Message));
return false;
}
Relativity | Services API Guide - 154
if (!readResult1.Success)
{
Console.WriteLine("Error reading the folder: " + readResult1.Message);
return false;
}
// STEP 2: Get the folder from the read results.
Folder readArtifact = readResult1.Results.FirstOrDefault().Artifact;
if (readArtifact == null)
{
Console.WriteLine("There is no folder with ArtifactID 1038603");
return false;
}
else
{
Console.WriteLine(String.Format("ArtifactID:{0} ParentArtifactID:{1} {2}", readArtifact.ArtifactID,
readArtifact.ParentArtifact.ArtifactID, readArtifact.Name));
}
return true;
}
6.8.3 Deleting a Folder
You can use the Delete() method on a Folder repository to remove it as illustrated in this code sample.
public static bool Delete_Folder_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Read current values.
DTOs.Folder requestArtifact = new Folder(1036275);
ResultSet<DTOs.Folder> readResult1;
try
{
readResult1 = proxy.Repositories.Folder.Read(requestArtifact);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred while reading the
folder: {0}", ex.Message));
return false;
}
Relativity | Services API Guide - 155
if (!readResult1.Success)
{
Console.WriteLine("Error reading the folder: " + readResult1.Message);
return false;
}
// STEP 2: Get the folder from the read results.
DTOs.Folder readArtifact = readResult1.Results.FirstOrDefault().Artifact;
if (readArtifact == null)
{
Console.WriteLine("There is no folder with ArtifactID 1037993");
return false;
}
// STEP 3: Delete the folder.
WriteResultSet<DTOs.Folder> deleteResult;
try
{
deleteResult = proxy.Repositories.Folder.Delete(requestArtifact);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred deleting the folder: {0}",
ex.Message);
return false;
}
if (!deleteResult.Success)
{
Console.WriteLine("Error deleting the folder: " + deleteResult.Message);
return false;
}
// STEP 4: To confirm the deletion, try to find the folder again.
// Since the folder doesn't exist, the read operation fails.
(ResultSet.Success is set to false).
// You can query for the folder's ArtifactID. The result is Success with 0
results.
WholeNumberCondition artifactIDCondition =
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, 1037993);
DTOs.Query<DTOs.Folder> query = new DTOs.Query<DTOs.Folder>
{
Condition = artifactIDCondition
};
Relativity | Services API Guide - 156
QueryResultSet<DTOs.Folder> queryResult;
try
{
queryResult = proxy.Repositories.Folder.Query(query);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying the folder after it was
deleted: {0}", ex.Message);
return false;
}
if (queryResult.Success)
{
if (queryResult.Results.Count == 0)
Console.WriteLine("Delete succeeded, the folder has been deleted");
}
else
{
Console.WriteLine("Error querying the folder after deletion: " +
queryResult.Message);
return false;
}
return true;
}
6.8.4 Querying for a Folder
To query for a Folder, you can use the fields listed in the following table. For more information, see Querying
on page 227.
Artifact ID
Name
Parent Artifact ID
Parent Artifact Name
Fields for Folder queries
System Created By
System Created On
System Last Modified By
System Last Modified On
The following sample code illustrates how to query for Folder DTOs using a repository.
public static bool Query_Folder_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the query.
Query<Folder> query = new Query<kCura.Relativity.Client.DTOs.Folder>();
query.Fields.Add(new FieldValue(FolderFieldNames.Name));
Relativity | Services API Guide - 157
ResultSet<Folder> readResult1;
// STEP 2: Query for the folders.
try
{
readResult1 = proxy.Repositories.Folder.Query(query);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred while querying for the
folder: {0}", ex.Message));
return false;
}
if (!readResult1.Success)
{
Console.WriteLine("Error reading the folder: " + readResult1.Message);
return false;
}
// STEP 3: Use the results.
foreach (Result<Folder> folder in readResult1.Results)
{
Console.WriteLine(String.Format("ArtifactID:{0} ParentArtifactID:{1} {2}",
folder.Artifact.ArtifactID, folder.Artifact.ParentArtifact.ArtifactID,
folder.Artifact.Name));
}
return true;
}
6.9 Group
Within Relativity, you can use groups to organize users. You can then assign a specific set of permissions to
each group. For more information, see Groups in the Relativity 8.1 Documentation site.
The Services API supports create, read, delete, and query operations on a Group DTO.
6.9.1 Creating a Group
You can add a Group to Relativity by calling the Create() method on the Group repository as illustrated in this
code sample. See Fields used by Group and User objects on page 144.
public static bool Create_Group(IRSAPIClient proxy)
{
// STEP 1: Create a DTO and set its properties.
Relativity | Services API Guide - 158
DTOs.Group newGroup = new DTOs.Group();
newGroup.Name = "Sample Group";
// STEP 2: Create a WriteResultSet. It provide details after the create
operation completes.
WriteResultSet<DTOs.Group> resultSet = new WriteResultSet<DTOs.Group>();
// STEP 3: Create the new Group.
try
{
resultSet = proxy.Repositories.Group.Create(newGroup);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Create operation failed.{0}{1}
",Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine("The Create succeeded.");
DTOs.Group createdGroup = resultSet.Results[0].Artifact;
Console.WriteLine("{0}The Artifact of the New Group is: {1}",
Environment.NewLine, createdGroup.ArtifactID);
// Console.WriteLine("The name of the Group is: {0}",
createdGroup.GroupName);
return true;
}
6.9.2 Reading a Group
To read Field values, you can use the Read() method on the Group repository as illustrated in this code
sample.
public static bool Read_Group(IRSAPIClient proxy)
{
Relativity | Services API Guide - 159
// STEP 1: Create a DTO with criteria you want to read.
DTOs.Group groupToRead = new DTOs.Group(1016219);
groupToRead.Fields = FieldValue.AllFields;
// STEP 2: Create ResultSet to store Results.
ResultSet<DTOs.Group> resultSet = new ResultSet<DTOs.Group>();
// STEP 3: Perform the read operation.
try
{
resultSet = proxy.Repositories.Group.Read(groupToRead);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Read operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine("Read completed successfully.");
DTOs.Group readGroup = resultSet.Results[0].Artifact;
SampleHelpers.APIHelpers.Print_All_Properties(readGroup);
return true;
}
6.9.3 Updating a Group
You can use the Update() on the Group repository to modify its properties as illustrated in this code sample.
See Fields used by Group and User objects on page 144.
public static bool Update_Group(IRSAPIClient proxy)
{
// STEP 1: Create DTO, and set its properties.
DTOs.Group newGroup = new DTOs.Group(1016219);
newGroup.Name = "Sample Group";
Relativity | Services API Guide - 160
// STEP 2: Create a WriteResultSet. It provides details after the update
operation.
WriteResultSet<DTOs.Group> resultSet = new WriteResultSet<DTOs.Group>();
// STEP 3: Perform the update operation.
try
{
resultSet = proxy.Repositories.Group.Update(newGroup);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Update operation failed.{0}{1}
",Environment.NewLine, resultSet.Message);
return false;
}
Console.WriteLine("Updated completed successfully.");
DTOs.Group updatedGroup = resultSet.Results[0].Artifact;
// Console.WriteLine("The updated name of the Group is: {0}",
updatedGroup.GroupName);
return true;
}
6.9.4 Deleting a Group
You can remove a Group from Relativity by calling the Delete() method on the Group repository as illustrated
in this code sample.
public static bool Delete_Group(IRSAPIClient proxy)
{
// STEP 1: Create a DTO populated with criteria for a DTO you want to
delete.
DTOs.Group groupToDelete = new DTOs.Group(1016219);
// STEP 2: Create a WriteResultSet. It provides details after the delete
operation completes.
WriteResultSet<DTOs.Group> resultSet = new WriteResultSet<DTOs.Group>();
Relativity | Services API Guide - 161
// STEP 3: Perform the delete operation.
try
{
resultSet = proxy.Repositories.Group.Delete(groupToDelete);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Delete operation failed.{0}{1}
",Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine("Delete completed successfully.");
DTOs.Group deletedGroup = resultSet.Results.ElementAt(0).Artifact;
Console.WriteLine("The Artifact ID of the deleted Group is: {0}",
deletedGroup.ArtifactID);
return true;
}
6.9.5 Querying for a Group
This code sample illustrates how to set query conditions, call the Query() method on the Group repository,
and iterate through the result set.
public static bool Query_Group(IRSAPIClient proxy)
{
// STEP 1: Create a Query and ObjectsCondition. It provides details after
the query operation.
ObjectsCondition workspaceCondition =
new ObjectsCondition("Workspaces", ObjectsConditionEnum.AnyOfThese, new
Int32[] { 1016204 });
Query<DTOs.Group> query = new DTOs.Query<DTOs.Group> { Condition =
workspaceCondition };
query.Fields = FieldValue.AllFields;
Relativity | Services API Guide - 162
// STEP 2: Create QueryResultSet to collect information about the DTO after
the query completes.
QueryResultSet<DTOs.Group> resultSet = new QueryResultSet<DTOs.Group>();
// STEP 3: Perform the query.
try
{
resultSet = proxy.Repositories.Group.Query(query, 0);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
// Output the results.
Console.WriteLine(string.Format("Number of Groups returned: {0}",
resultSet.Results.Count));
foreach (DTOs.Result<DTOs.Group> groupResult in resultSet.Results)
{
Console.WriteLine(string.Format("{0}Name:{1}", Environment.NewLine,
groupResult.Artifact.Name));
Console.WriteLine(string.Format("ArtifactID:{0}",
groupResult.Artifact.ArtifactID));
}
return true;
}
6.10 Layout
In Relativity, layouts are web-based coding forms that enable users to view and edit document fields. For
more information, see Layouts in the Relativity 8.1 Documentation site.
The Services API supports read and query operations on a Layout DTO.
Relativity | Services API Guide - 163
6.10.1 Reading a Layout
To read Field values on a Layout, you can use the Read() method on the Layout repository as illustrated in this
code sample.
public static bool Read_Layout_Using_Repository(IRSAPIClient proxy)
{
//STEP 1: Create a Layout DTO for the Layout to be read.
DTOs.Layout layoutDTO = new DTOs.Layout(1036682);
layoutDTO.Fields = FieldValue.AllFields;
ResultSet<DTOs.Layout> layoutReadResults = new ResultSet<DTOs.Layout>();
//STEP 2: Try to read the Layout.
try
{
layoutReadResults = proxy.Repositories.Layout.Read(layoutDTO);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred reading the layout: {0}",
ex.Message);
return false;
}
//STEP 3: Check for success.
if (!layoutReadResults.Success)
{
Console.WriteLine("An error occurred reading the layout: {0}",
layoutReadResults.Message);
foreach (Result<DTOs.Layout> readResult in layoutReadResults.Results)
{
if (!readResult.Success)
{
Console.WriteLine(" An error occurred in read request: {0}",
readResult.Message);
}
}
return false;
}
//STEP 4: Output the name.
Console.WriteLine("Successfully read the layout '{0}'!",
layoutReadResults.Results[0].Artifact.Name);
return true;
}
Relativity | Services API Guide - 164
6.10.2 Querying for a Layout
To query for a Layout, you can use the fields listed in the following table. For more information, see Querying
on page 227.
ArtifactID
Created By
Created By
Keywords
Last Modified By
Last Modified On
Name
Fields for Layout queries
Notes
Object Type
Order in Dropdown
Overwrite Protection
Owners
Relativity Applications
Security
This code sample illustrates how to set query conditions, call the Query() method on the Layout repository,
and iterate through the result set.
public static bool Query_Layout_Using_Repository(IRSAPIClient proxy)
{
//STEP 1: Create the query criteria.
ObjectsCondition relAppCondition =
new ObjectsCondition("Relativity Applications",
ObjectsConditionEnum.AllOfThese, new int[] { 1035699 });
Query<DTOs.Layout> layoutQuery = new Query<DTOs.Layout>
{
Condition = relAppCondition,
Fields = FieldValue.AllFields
};
//STEP 2: Try to query for the Layout.
QueryResultSet<DTOs.Layout> layoutQueryResults = null;
try
{
layoutQueryResults = proxy.Repositories.Layout.Query(layoutQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for layouts: {0}",
ex.Message);
return false;
}
//STEP 3: Check for success.
if (!layoutQueryResults.Success)
Relativity | Services API Guide - 165
{
Console.WriteLine("An error occurred querying for layouts: {0}",
layoutQueryResults.Message);
return false;
}
//STEP 4: Display the results.
Console.WriteLine("Number of layouts returned: {0}",
layoutQueryResults.Results.Count);
foreach (Result<DTOs.Layout> layoutResult in layoutQueryResults.Results)
{
DTOs.Layout curLayout = layoutResult.Artifact;
Console.WriteLine("Layout Name: {0}", curLayout.TextIdentifier);
Console.WriteLine("Layout ArtifactID: {0}", curLayout.ArtifactID);
}
return true;
}
6.11 MarkupSet
In Relativity, markup sets are securable highlights and redactions available to reviewers. For more
information, see Markup sets in the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on a MarkupSet DTO.
6.11.1 Creating a MarkupSet
You can add a MarkupSet to Relativity by calling the Create() method on the MarkupSet repository as
illustrated in this code sample.
public static bool Create_MarkupSet_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create a MarkupSet DTO and populate the fields.
DTOs.MarkupSet markupSetDTO = new DTOs.MarkupSet();
markupSetDTO.Name = "New Markup Set";
markupSetDTO.Order = 10;
markupSetDTO.RedactionText =
new List<String>(new string[] {"Each", "string", "here", "is", "on", "a",
"new", "line."});
// STEP 2: Call the Create() method on the repository and pass in the DTO.
DTOs.WriteResultSet<DTOs.MarkupSet> createResults;
try
{
createResults = proxy.Repositories.MarkupSet.Create(markupSetDTO);
Relativity | Services API Guide - 166
}
catch (Exception ex)
{
Console.WriteLine("An error occurred creating the Markup Set: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!createResults.Success)
{
Console.WriteLine("An error occurred creating the Markup Set: {0}",
createResults.Results[0].Message);
return false;
}
else
{
Console.WriteLine("Successfully created Markup Set '{0}'!",
markupSetDTO.Name);
}
return true;
}
6.11.2 Reading a MarkupSet
To read Field values, you can use the Read() method on the MarkupSet repository as illustrated in this code
sample.
public static bool Read_MarkupSet_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the MarkupSet DTO.
kCura.Relativity.Client.DTOs.MarkupSet markupSet = new
kCura.Relativity.Client.DTOs.MarkupSet(1039144);
markupSet.Fields = kCura.Relativity.Client.DTOs.FieldValue.AllFields;
// STEP 2: Read the MarkupSet DTO from the repository.
kCura.Relativity.Client.DTOs.ResultSet<kCura.Relativity.Client.DTOs.MarkupS
et> resultSet;
try
{
resultSet = proxy.Repositories.MarkupSet.Read(markupSet);
}
catch (Exception ex)
Relativity | Services API Guide - 167
{
Console.WriteLine("An error occurred reading the MarkupSet: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!resultSet.Success)
{
Console.WriteLine("An error occurred reading the MarkupSet: {0}",
resultSet.Message);
return false;
}
kCura.Relativity.Client.DTOs.MarkupSet markupSetResult =
resultSet.Results.FirstOrDefault().Artifact;
Console.WriteLine("MarkupSet Name: {0}", markupSetResult.Name);
return true;
}
6.11.3 Updating a MarkupSet
You can use the Update() on the MarkupSet repository to modify its properties as illustrated in this code
sample.
public static bool Update_MarkupSet_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the MarkupSet DTO.
kCura.Relativity.Client.DTOs.MarkupSet markupSet = new
kCura.Relativity.Client.DTOs.MarkupSet(1039144);
markupSet.Fields = kCura.Relativity.Client.DTOs.FieldValue.AllFields;
// STEP 2: Read the MarkupSet DTO from the repository.
kCura.Relativity.Client.DTOs.ResultSet<kCura.Relativity.Client.DTOs.MarkupS
et> resultSet;
try
{
resultSet = proxy.Repositories.MarkupSet.Read(markupSet);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred reading the MarkupSet: {0}",
ex.Message);
return false;
Relativity | Services API Guide - 168
}
// STEP 3: Check for success.
if (!resultSet.Success)
{
Console.WriteLine("An error occurred reading the MarkupSet: {0}",
resultSet.Message);
return false;
}
kCura.Relativity.Client.DTOs.MarkupSet markupSetResult =
resultSet.Results.FirstOrDefault().Artifact;
Console.WriteLine("MarkupSet Name: {0}", markupSetResult.Name);
// STEP 4: Update the DTO in the repository.
markupSetResult.Name = "Updated Markup Set";
markupSetResult.Order = 20;
markupSetResult.RedactionText.Add("New Markup Text");
kCura.Relativity.Client.DTOs.ResultSet<kCura.Relativity.Client.DTOs.MarkupS
et> updatedResultSet;
try
{
updatedResultSet = proxy.Repositories.MarkupSet.Update(markupSetResult);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred Updating the MarkupSet: {0}",
ex.Message);
return false;
}
// STEP 5: Check for success.
if (!updatedResultSet.Success)
{
Console.WriteLine("An error occurred Updating the MarkupSet: {0}",
updatedResultSet.Message);
return false;
}
return true;
}
6.11.4 Deleting a MarkupSet
You can remove a MarkupSet from Relativity by calling the Delete() method on the MarkupSet repository as
illustrated in this code sample.
Relativity | Services API Guide - 169
public static bool Delete_MarkupSet_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the MarkupSet DTO.
kCura.Relativity.Client.DTOs.MarkupSet markupSet = new
kCura.Relativity.Client.DTOs.MarkupSet(1039144);
// STEP 2: Delete the MarkupSet from the repository.
kCura.Relativity.Client.DTOs.ResultSet<kCura.Relativity.Client.DTOs.MarkupS
et> resultSet;
try
{
resultSet = proxy.Repositories.MarkupSet.Delete(markupSet);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred deleting the MarkupSet: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!resultSet.Success)
{
Console.WriteLine("An error occurred deleting the MarkupSet: {0}",
resultSet.Message);
return false;
}
return true;
}
6.11.5 Querying for a MarkupSet
To query for a MarkupSet, you can use the fields listed in the following table. For more information, see
Querying on page 227.
Artifact ID
Created By
Created On
Name
Keywords
Last Modified By
Fields for MarkupSet queries
Last Modified On
Notes
Order
Redaction Text – returned as List<string> to accommodate multiple
values.
Security
This code sample illustrates how to set query conditions, call the Query() method on the MarkupSet
repository, and iterate through the result set.
Relativity | Services API Guide - 170
public static bool Query_MarkupSet_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the query criteria.
DTOs.Query<DTOs.MarkupSet> markupSetQuery = new DTOs.Query<DTOs.MarkupSet>
();
List<String> desiredRedactionText =
new List<string>(new string[] { "Each", "string", "here", "is", "on",
"a", "new", "line." });
markupSetQuery.Condition = new MultiLineStringCondition
(DTOs.MarkupSetFieldNames.RedactionText, TextConditionEnum.EqualTo,
desiredRedactionText);
markupSetQuery.Fields = DTOs.FieldValue.AllFields;
// STEP 2: Call the Query() method on the repository.
DTOs.QueryResultSet<DTOs.MarkupSet> queryResults;
try
{
queryResults = proxy.Repositories.MarkupSet.Query(markupSetQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for the MarkupSet: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!queryResults.Success)
{
Console.WriteLine("An error occurred querying for the MarkupSet: {0}",
queryResults.Message);
return false;
}
else
{
Console.WriteLine("Query returned {0} MarkupSets!",
queryResults.Results.Count);
foreach (DTOs.Result<DTOs.MarkupSet> markupSetResult in
queryResults.Results)
{
Console.WriteLine("MarkupSet Name: {0}",
markupSetResult.Artifact.Name);
Relativity | Services API Guide - 171
}
}
return true;
}
6.12 ObjectType
An ObjectType is Relativity Dynamic Object (RDO) type that you add to a workspace. It is synonymous with
ArtifactType. For more information, see Object type details in the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on a ObjectType DTO.
6.12.1 Creating an ObjectType
You can add an ObjectType to Relativity by calling the Create() method on the ObjectType repository as
illustrated in this code sample.
public static bool Create_ObjectType_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Create an ObjectType DTO and populate the Fields.
DTOs.ObjectType objectTypeDTO = new DTOs.ObjectType();
objectTypeDTO.Name = "New Object Type";
objectTypeDTO.ParentArtifactTypeID = 8;
objectTypeDTO.SnapshotAuditingEnabledOnDelete = true;
objectTypeDTO.Pivot = true;
objectTypeDTO.CopyInstancesOnWorkspaceCreation = false;
objectTypeDTO.Sampling = true;
objectTypeDTO.PersistentLists = false;
objectTypeDTO.RelativityApplications =
new List<DTOs.RelativityApplication> { new DTOs.RelativityApplication
(1037990),
new DTOs.RelativityApplication(1037639) };
// STEP 2: Call the Create method on the repository, passing the DTO.
WriteResultSet<DTOs.ObjectType> resultSet;
try {
resultSet = proxy.Repositories.ObjectType.Create(objectTypeDTO);
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
Relativity | Services API Guide - 172
if (!resultSet.Success) {
Console.WriteLine("Error: " + resultSet.Message);
foreach (Result<DTOs.ObjectType> result in resultSet.Results) {
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
Console.WriteLine("Overall status of creating an object type: " +
resultSet.Success);
Console.WriteLine("New Artifact ID: " + resultSet.Results.FirstOrDefault
().Artifact.ArtifactID);
return true;
}
6.12.2 Reading an ObjectType
To read Field values, you can use the Read() method on the ObjectType repository as illustrated in this code
sample.
public static bool Read_ObjectType_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Call the Read() method on the ObjectType repository and pass an
ObjectType DTO.
ResultSet<DTOs.ObjectType> results;
try {
results =
proxy.Repositories.ObjectType.Read(new DTOs.ObjectType(1036210) {
Fields = FieldValue.AllFields });
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!results.Success) {
Console.WriteLine("Error: " + results.Message);
foreach (Result<DTOs.ObjectType> result in results.Results)
{
Console.WriteLine("Result Error: " + result.Message);
Relativity | Services API Guide - 173
}
return false;
}
// STEP 2: Get the Object Type artifact from the read results.
DTOs.ObjectType objectTypeArtifact = results.Results.FirstOrDefault
().Artifact;
Console.WriteLine("Object Type Artifact ID: " +
objectTypeArtifact.ArtifactID);
Console.WriteLine("Object Type Name: " + objectTypeArtifact.Name);
Console.WriteLine("Object Type Artifact Type ID: " +
objectTypeArtifact.DescriptorArtifactTypeID);
return true;
}
6.12.3 Updating an ObjectType
You can use the Update() method on the ObjectType repository to modify its properties as illustrated in this
code sample.
public static bool Update_ObjectType_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Create an ObjectType DTO and populate the Fields you want to
update.
DTOs.ObjectType objectTypeDTO = new DTOs.ObjectType(1035966);
objectTypeDTO.Name = "Renamed Object Type";
// STEP 2: Call the Update() method on the repository and pass the DTO.
WriteResultSet<DTOs.ObjectType> resultSet;
try {
resultSet = proxy.Repositories.ObjectType.Update(objectTypeDTO);
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!resultSet.Success) {
Console.WriteLine("Error: " + resultSet.Message);
foreach (Result<DTOs.ObjectType> result in resultSet.Results) {
Relativity | Services API Guide - 174
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
Console.WriteLine("Overall status of Updating an object type: " +
resultSet.Success);
// STEP 3: Read back the Artifact for verification.
ResultSet<DTOs.ObjectType> readResult;
try {
readResult = proxy.Repositories.ObjectType.Read(objectTypeDTO);
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (!readResult.Success) {
Console.WriteLine("Error: " + readResult.Message);
foreach (Result<DTOs.ObjectType> result in resultSet.Results) {
Console.WriteLine("Result Error: " + result.Message);
}
return false;
}
Console.WriteLine("Updated Object Type Name: " +
readResult.Results.FirstOrDefault().Artifact.Name);
return true;
}
6.12.4 Deleting an ObjectType
You can remove an ObjectType from Relativity by calling the Delete() method on the ObjectType repository as
illustrated in this code sample.
public static bool Delete_ObjectType_Using_Repository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = 1016204;
// STEP 1: Call the delete method on the ArtifactType Repository, passing
the ObjectType DTO.
ResultSet<DTOs.ObjectType> results;
try {
Relativity | Services API Guide - 175
results = proxy.Repositories.ObjectType.Delete(new DTOs.ObjectType
(1038017));
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return false;
}
if (results.Success)
Console.WriteLine("Status of Delete: " + results.Success);
else
Console.WriteLine("Error deleting object type: " + results.Results
[0].Message);
return true;
}
6.12.5 Querying for an ObjectType
This code sample illustrates how to set query conditions, call the Query() method on the ObjectType
repository, and iterate through the result set.
public static bool Query_ObjectType_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Setup your query criteria.
TextCondition criteria =
new TextCondition(kCura.Relativity.Client.DTOs.ObjectTypeFieldNames.Name,
TextConditionEnum.EqualTo,
"Employees");
Query<DTOs.ObjectType> query = new Query<DTOs.ObjectType>
{
Condition = criteria,
Fields = FieldValue.AllFields
};
// STEP 2: Call the Query() method in the ObjectType repository.
QueryResultSet<DTOs.ObjectType> result = new QueryResultSet<DTOs.ObjectType>
();
try {
result = proxy.Repositories.ObjectType.Query(query, 0);
}
catch (Exception ex) {
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
Relativity | Services API Guide - 176
}
Console.WriteLine(string.Format("Number of documents returned: {0}",
result.TotalCount));
Console.WriteLine(string.Format("Additional Pages of Query Results
Available?: {0}",
!string.IsNullOrEmpty(result.QueryToken)));
// STEP 3: Iterate over the returned ObjectType result.
foreach (DTOs.Result<DTOs.ObjectType> objTypeResult in result.Results) {
DTOs.ObjectType objType = objTypeResult.Artifact;
Console.WriteLine("Object Type Name: " + objTypeResult.Artifact.Name);
Console.WriteLine("Object Type Artifact Type ID: " +
objTypeResult.Artifact.DescriptorArtifactTypeID);
}
return true;
}
6.13 RDO
A Relativity Dynamic Object (RDO) is custom object that you create in a workspace. It has a unique
ArtifactTypeID in the workspace where it is created. For more information, see Relativity objects in the
Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on an RDO.
6.13.1 Creating an RDO
You can add an RDO to Relativity by calling the Create() method on the RDO repository. This code sample use
GUIDs to reference Fields, but you can also reference Fields by their names or ArtifactIDs. See GUIDs in
application development on page 78.
public void Create_an_RDO_UsingGUIDs()
{
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
// STEP 1: Create an RDO DTO and set the ArtifactTypeGuids.
var dto = new RDO();
Relativity | Services API Guide - 177
dto.ArtifactTypeGuids.Add(new Guid("EE5BD2B1-47A8-45CE-AA5B2115B6DD86A4"));
// STEP 2: Add FieldValues to the Fields collection. Specify the GUID
// of the Field that you want to set. Set the FixedLengthText fields.
dto.Fields.Add(new FieldValue(new Guid("37159592-B5B6-4405-AF7410B5728890B4"), "Smith"));
dto.Fields.Add(new FieldValue(new Guid("3BDC0971-A87C-414E-9A37FC477279BBAD"), "Joe"));
// Set a SingleChoice Type field to a Choice using the GUID that
represents
// the Choice artifact.
dto.Fields.Add(new FieldValue(new Guid("4F06AC67-822A-414F-B6C15D4007E998EF"), new kCura.Relativity.Client.DTOs.Choice(new Guid
("4501A308-5E68-4314-AEDC-4DEB527F12A8"))));
// Set A MultiChoice field by creating a MultiChoiceFieldValueList as
its value.
// The MultiChoiceFieldValueList contains Choice DTOs, which are set
using GUIDs that represent
// the Choice artifact.
var multiChoices =new MultiChoiceFieldValueList(
new kCura.Relativity.Client.DTOs.Choice(new Guid("6A1D5E35-B4B3-49629EEB-6E6D3016D40C")),
new kCura.Relativity.Client.DTOs.Choice(new Guid("E647DF05-2E51-41E7B6A3-C3F1CD723C54")));
// Set the UpdateBehavior depending on whether you want to Merge or
Replace the new values.
multiChoices.UpdateBehavior = MultiChoiceUpdateBehavior.Replace;
// Set the MultiChoice field using its GUID and set the value to the
MultiChoiceFieldValueList.
dto.Fields.Add(new FieldValue(new Guid("C9D1C1E7-61B1-46EE-A35D406FC9503DE5"), multiChoices));
// Set a User field to a User DTO.
dto.Fields.Add(new FieldValue(new Guid("C1A2DB49-3282-40CF-84A08DEEB4E76764"),
new kCura.Relativity.Client.DTOs.User(1015411)));
// Set a SingleObject to a DTO for the object. In this example, a
SingleObject Field takes a Document.
var obj = new kCura.Relativity.Client.DTOs.Document(1038372);
Relativity | Services API Guide - 178
dto.Fields.Add(new FieldValue(new Guid("68094937-3E3A-42D4-B71B132C8A4C51F7"), obj));
// Set a MultiObject to a FieldValueList of the Type of objects. In
this example, a MultiObject Field takes instances of RDOs.
FieldValueList<RDO> objects = new FieldValueList<RDO>();
objects.Add(new RDO(1067600));
objects.Add(new RDO(1067613));
dto.Fields.Add(new FieldValue(new Guid("467D2CDE-7892-4463-9890805B937E3945"), objects));
// STEP 3: Call the Create() method on the RDO Respository.
WriteResultSet<RDO> writeResults = proxy.Repositories.RDO.Create(dto);
if (writeResults.Success)
{
Console.WriteLine(string.Format("Object was created with Artifact
ID {0}.", writeResults.Results[0].Artifact.ArtifactID));
}
else
{
Console.WriteLine(string.Format("An error occurred creating object:
{0}", writeResults.Message));
for (Int32 i = 0; i <= writeResults.Results.Count - 1; i++)
{
if (!writeResults.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in create request {0}: {1}", i, writeResults.Results
[i].Message));
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
}
6.13.2 Creating an RDO as a child object
You can create an RDO that is a child of another object other than Workspace. You must set the ParentArtifact
property of the child object to the DTO Artifact of its parent object as illustrated in this code sample.
Relativity | Services API Guide - 179
// Create an instance of the parent object with ArtifactTypeName “ParentObj”.
var rdo = new RDO("ParentObj");
rdo.TextIdentifier = "Test Parent Object";
var parentCreate = proxy.Repositories.RDO.Create(rdo);
// Create an instance of the child object with ArtifactTypeName “ChildObj”
// and set the ParentArtifact to the parent object instance previously created.
var childRDO = new RDO("ChildObj");
childRDO.TextIdentifier = "Child of Test Parent Object";
childRDO.ParentArtifact =
new kCura.Relativity.Client.DTOs.Artifact(parentCreate.Results
[0].Artifact.ArtifactID);
var childCreate = proxy.Repositories.RDO.Create(childRDO);
6.13.3 Reading an RDO
To read Field values, you can use the Read() method on the RDO repository as illustrated in this code sample.
public void Read_an_RDO_Using_Repository2()
{
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
// STEP 1: Call the Read() method on the RDO repository.
RDO employee = new RDO(1067694);
employee.ArtifactTypeID = 1000030;
employee.Fields = FieldValue.AllFields;
ResultSet<RDO> results = new ResultSet<RDO>();
results = proxy.Repositories.RDO.Read(employee);
//Check for success.
if (!results.Success)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(results.Message);
}
else
{
Console.WriteLine(string.Format("An error occurred reading object:
{0}", results.Message));
Relativity | Services API Guide - 180
for (Int32 i = 0; i <= results.Results.Count - 1; i++)
{
if (!results.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in read request {0}: {1}", i,
results.Results[i].Message));
}
}
}
// STEP 2:
employee =
FieldValue
FieldValue
FieldValue
FieldValue
FieldValue
FieldValue
Get the Artifact from the read results.
results.Results.Single().Artifact;
lastNameField = employee["Last Name"];
employmentLevelField = employee["Employment Level"];
hrRepField = employee["HR Rep"];
skillsInventoryField = employee["Skills Inventory"];
keyDocumentField = employee["Key Document"];
favoriteDocumentsField = employee["Favorite Documents"];
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID, lastNameField.Name,
lastNameField.ValueAsFixedLengthText);
// The SingleChoice field returns a Choice DTO.
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID, employmentLevelField.Name,
employmentLevelField.ValueAsSingleChoice.ArtifactID);
// The MultipleChoice field returns a MultiChoiceFieldValueList
containing a List of Choice DTOs.
MultiChoiceFieldValueList multiChoiceList =
skillsInventoryField.ValueAsMultipleChoice;
for (int index = 0; index < multiChoiceList.Count; index++)
{
kCura.Relativity.Client.DTOs.Choice choice = multiChoiceList
[index];
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID, skillsInventoryField.Name + " " + "Choice " +
index, choice.ArtifactID);
}
// The User field returns a User DTO.
Relativity | Services API Guide - 181
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID, hrRepField.Name,
hrRepField.ValueAsUser.ArtifactID + " - " +
hrRepField.ValueAsUser.FullName);
// The SingleObject field is returned as an Artifact DTO.
kCura.Relativity.Client.DTOs.Artifact documentArtifact =
keyDocumentField.ValueAsSingleObject;
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID,
keyDocumentField.Name, documentArtifact.ArtifactID);
// The MultipleObject field is returned as FieldValueList<Artifact>.
FieldValueList<kCura.Relativity.Client.DTOs.Artifact> multiObject =
favoriteDocumentsField.GetValueAsMultipleObject<kCura.Relativity.Cl
ient.DTOs.Artifact>();
for (int index = 0; index < multiObject.Count; index++)
{
Int32 id = multiObject[index].ArtifactID;
Console.WriteLine("Artifact: {0} Field: {1} Value: {2}",
employee.ArtifactID,
favoriteDocumentsField.Name + " Object " + index, id);
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
}
6.13.4 Updating an RDO
You can use the Update() method on an RDO repository to modify its properties as illustrated in this code
sample.
public void Update_RDO_Using_Repository()
{
try
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"),
new IntegratedAuthCredentials()))
{
Relativity | Services API Guide - 182
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
// STEP 1: Create an RDO DTO and add the FieldValue that you want to
update.
RDO artifact = new RDO("Employees", 1067694);
artifact.Fields.Add(new FieldValue() {Name = "Last Name", Value =
"Smith, Jr."});
// STEP 2: Call the Update() method on the RDO respository.
WriteResultSet<RDO> writeResultSet = proxy.Repositories.RDO.Update
(artifact);
if (!writeResultSet.Success)
{
Console.WriteLine("Error: " + writeResultSet.Message);
for (Int32 i = 0; i <= writeResultSet.Results.Count - 1; i++)
{
if (!writeResultSet.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in update request {0}: {1}", i, writeResultSet.Results
[i].Message));
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
}
6.13.5 Deleting an RDO
You can remove an RDO from Relativity by calling the Delete() method on the RDO repository as illustrated in
this code sample.
public void Delete_RDO()
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
{
Relativity | Services API Guide - 183
try
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
//Step 1: Create a DTO for an instance of the "Employees" RDO.
var dtoToDelete = new RDO("Employees", 1067605);
//Step 2: Call Delete on the RDO Repository and pass the RDO DTO.
WriteResultSet<RDO> deleteResult = proxy.Repositories.RDO.Delete
(dtoToDelete);
if (!deleteResult.Success)
{
Console.WriteLine("Error deleting the object: " +
deleteResult.Message);
for (Int32 i = 0; i <= deleteResult.Results.Count - 1; i++)
{
if (!deleteResult.Results[i].Success)
{
Console.WriteLine(String.Format("An error occurred in delete request {0}: {1}", i,
deleteResult.Results[i].Message));
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}",
ex.Message));
}
}
}
6.13.6 Querying for an RDO
This code sample illustrates how to set query conditions, call the Query() method on the RDO repository, and
iterate through the result set.
public void Query_an_RDO_Using_Repository()
{
using (IRSAPIClient proxy =
new RSAPIClient(new Uri("net.pipe://localhost/Relativity.Services"), new
IntegratedAuthCredentials()))
Relativity | Services API Guide - 184
{
try
{
proxy.APIOptions.WorkspaceID = WORKSPACE_ID;
// STEP 1: Setup your query criteria.
TextCondition lastNameCriteria = new TextCondition("Last Name",
TextConditionEnum.EqualTo, "Smith");
TextCondition firstNameCriteria = new TextCondition("Name",
TextConditionEnum.EqualTo, "Mike");
CompositeCondition condition = new CompositeCondition
(lastNameCriteria, CompositeConditionEnum.And,
firstNameCriteria);
kCura.Relativity.Client.DTOs.Query<RDO> query = new Query<RDO>
{ArtifactTypeID = 1000030,
Condition = condition};
query.Fields.Add(new
query.Fields.Add(new
query.Fields.Add(new
query.Fields.Add(new
query.Fields.Add(new
FieldValue("Employment Level"));
FieldValue("Skills Inventory"));
FieldValue("HR Rep"));
FieldValue("Last Name"));
FieldValue("Name"));
// STEP 2: Call the Query() method on the RDO repository.
QueryResultSet<RDO> results = new QueryResultSet<RDO>();
results = proxy.Repositories.RDO.Query(query);
//Check for success.
if (!results.Success)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(results.Message);
}
// STEP 3: Get the Artifact from the query results.
RDO employee = results.Results.Single().Artifact;
Console.WriteLine(">>>" + employee + "<<<");
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}",
ex.Message));
}
}
}
Relativity | Services API Guide - 185
6.14 RelativityApplication
You can develop applications that use Relativity Dynamic Objects (RDOs), custom pages, event handlers, and
other platform components. For more information, see Application Deployment System on the Relativity 8.1
Developers site.
The Services API supports all read and query operations on a RelativityApplication DTO.
6.14.1 Reading a RelativityApplication
To read Field values on RelativityApplication object, you can use the Read() method on the
RelativityApplication repository as illustrated in this code sample.
public static bool ReadRelativityApplicationUsingRepository(IRSAPIClient proxy)
{
// STEP 1: Create a RelativityApplication DTO for the application that you
want to read.
RelativityApplication relativityApplication = new RelativityApplication
(1037631);
relativityApplication.Fields.Add(new FieldValue
(RelativityApplicationFieldNames.Name));
relativityApplication.Fields.Add(new FieldValue
(RelativityApplicationFieldNames.Version));
ResultSet<RelativityApplication> readResultSet = null;
// STEP 2: Try to read the RelativityApplication object.
try
{
readResultSet = proxy.Repositories.RelativityApplication.Read
(relativityApplication);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// STEP 3: Check for success.
if (!readResultSet.Success)
{
Console.WriteLine("An error occurred reading the Relativity Application:
{0}", readResultSet.Message);
foreach (Result<RelativityApplication> readResult in
readResultSet.Results)
{
Relativity | Services API Guide - 186
if (!readResult.Success)
{
Console.WriteLine(" An error occurred in the read result: {0}",
readResult.Message);
}
}
return false;
}
RelativityApplication readApplication = readResultSet.Results[0].Artifact;
// STEP 4: Display the name and version of the Relativity application.
Console.WriteLine("Relativity Application Name: {0}{1}Relativity Application
Version: {2}",
readApplication.Name, Environment.NewLine, readApplication.Version);
return true;
}
6.14.2 Deleting a Relativity Application
You can call the Delete() method on the RelativityApplication repository to delete an application. The
Application Deployment System (ADS) also provides functionality for deleting and uninstalling applications
through the Relativity UI. For more information, see e Application Deployment System in the Relativity 8.1
Developers site.
public static bool DeleteRelativityApplicationUsingRepository(IRSAPIClient
proxy)
{
// STEP 1: Create a RelativityApplication DTO for the application that you
want to delete.
RelativityApplication relativityApplication = new RelativityApplication
(1037639);
WriteResultSet<RelativityApplication> writeResultSet = null;
// STEP 2: Try to delete the Relativity Application.
try
{
writeResultSet = proxy.Repositories.RelativityApplication.Delete
(relativityApplication);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
Relativity | Services API Guide - 187
//STEP 3: Check for success.
if (!writeResultSet.Success)
{
Console.WriteLine("An error occurred deleting the Relativity Application:
{0}", writeResultSet.Message);
foreach (Result<RelativityApplication> writeResult in
writeResultSet.Results)
{
if (!writeResult.Success)
{
Console.WriteLine(" An error occurred in the delete result: {0}",
writeResult.Message);
}
}
return false;
}
return true;
}
6.14.3 Querying for a RelativityApplication
To query for a RelativityApplication object, you can use the fields listed in the following table. For more
information, see Querying on page 227.
Guid
ID
InDevelopment
Fields for Application queries
Name
Version
This code sample illustrates how to set query conditions, call the Query() method on the RelativityApplication
repository, and iterate through the result set.
public static bool QueryRelativityApplicationUsingRepository(IRSAPIClient
proxy)
{
// STEP 1: Create a Relativity Application DTO for the application to query.
Query<kCura.Relativity.Client.DTOs.RelativityApplication> query = new
Query<RelativityApplication>();
query.Fields.Add(new FieldValue(ArtifactQueryFieldNames.ArtifactID));
query.Fields.Add(new FieldValue(RelativityApplicationFieldNames.Name));
query.Fields.Add(new FieldValue(RelativityApplicationFieldNames.Version));
query.Condition =
Relativity | Services API Guide - 188
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, 1037631);
ResultSet<RelativityApplication> readResultSet = null;
//STEP 2: Attempt to query the Relativity Application.
try
{
readResultSet = proxy.Repositories.RelativityApplication.Query(query);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
//STEP 3: Check for success.
if (!readResultSet.Success)
{
Console.WriteLine("An error occurred reading the Relativity Application:
{0}", readResultSet.Message);
foreach (Result<RelativityApplication> readResult in
readResultSet.Results)
{
if (!readResult.Success)
{
Console.WriteLine(" An error occurred in the read result: {0}",
readResult.Message);
}
}
return false;
}
RelativityApplication readApplication = readResultSet.Results[0].Artifact;
//STEP 4: Display the name and version of the Relativity application.
Console.WriteLine("Relativity Application Name: {0}{1}Relativity Application
Version: {2}",
readApplication.Name, Environment.NewLine, readApplication.Version);
return true;
}
6.15 RelativityScript
Using the Services API, you can execute SQL-based scripts that have been added to workspaces through the
Relativity web UI. These scripts extend the functionality of the Services API by working directly with the
Relativity | Services API Guide - 189
database to retrieve or modify data for report generation or other purposes. For more information, see Script
development on the Relativity 8.1 Developers site.
The Services API supports read and query operations on the RelativityScript DTO, as well as the functionality
for executing a script and retrieving its inputs.
6.15.1 Reading a RelativityScript
To read Field values, you can use the Read() method on the RelativityScript repository as illustrated in this
code sample.
public static bool Read_RelativityScript_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create a RelativityScript DTO for the RelativityScript that you
want to read.
DTOs.RelativityScript relScriptDTO = new DTOs.RelativityScript(1015032);
relScriptDTO.Fields = DTOs.FieldValue.AllFields;
// STEP 2: Attempt to read the RelativityScript.
DTOs.ResultSet<DTOs.RelativityScript> relScriptReadResults =
new DTOs.ResultSet<DTOs.RelativityScript>();
try
{
relScriptReadResults = proxy.Repositories.RelativityScript.Read
(relScriptDTO);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred reading the Relativity Script: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!relScriptReadResults.Success)
{
Console.WriteLine("An error occurred reading the Relativity Script: {0}",
relScriptReadResults.Message);
foreach (DTOs.Result<DTOs.RelativityScript> readResult in
relScriptReadResults.Results)
{
if (!readResult.Success)
{
Console.WriteLine(" An error occurred in read request: {0}",
readResult.Message);
Relativity | Services API Guide - 190
}
}
return false;
}
relScriptDTO = relScriptReadResults.Results[0].Artifact;
// STEP 4: Retrieve the body as XML and output the name.
XmlDocument bodyXml = relScriptDTO.Body;
Console.WriteLine("Successfully read the Relativity Script '{0}'!",
relScriptDTO.Name);
return true;
}
6.15.2 Querying for a RelativityScript
This code sample illustrates how to set query conditions, call the Query() method on the RelativityScript
repository, and iterate through the result set.
public static bool Query_RelativityScript_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the query criteria.
TextCondition nameCondition = new TextCondition
(DTOs.RelativityScriptFieldNames.Name,
TextConditionEnum.Like, "Billing Statistics");
DTOs.Query<DTOs.RelativityScript> relScriptQuery = new
DTOs.Query<DTOs.RelativityScript>
{
Condition = nameCondition,
Fields = DTOs.FieldValue.AllFields
};
// STEP 2: Attempt to query for the RelativityScript.
DTOs.QueryResultSet<DTOs.RelativityScript> relScriptQueryResults = null;
try
{
relScriptQueryResults = proxy.Repositories.RelativityScript.Query
(relScriptQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for Relativity Scripts: {0}
", ex.Message);
Relativity | Services API Guide - 191
return false;
}
// STEP 3: Check for success.
if (!relScriptQueryResults.Success)
{
Console.WriteLine("An error occurred querying for Relativity Scripts: {0}
", relScriptQueryResults.Message);
return false;
}
// STEP 4: Display the results.
Console.WriteLine("Number of Relativity Scripts returned: {0}",
relScriptQueryResults.Results.Count);
foreach (DTOs.Result<DTOs.RelativityScript> relScriptResult in
relScriptQueryResults.Results)
{
DTOs.RelativityScript curRelScript = relScriptResult.Artifact;
Console.WriteLine("Relativity Script Name: {0}",
curRelScript.TextIdentifier);
Console.WriteLine("Relativity Script ArtifactID: {0}",
curRelScript.ArtifactID);
}
return true;
}
6.15.3 Executing a RelativityScript
You can use the ExecuteRelativityScript() method to run a Relativity script by passing in the script ID, and the
script input as a string. (You can perform a query to obtain the script ID.) The ExecuteRelativityScript() method
may return a list of Artifacts and Fields, or the status of database rows affected by the script. You must be a
member of the Relativity Script Admin group to use this method.
The script should be configured with a return type of Table and have an integer column named ArtifactID. For
each row in the output table, an Artifact object will be created with the ArtifactID from the ArtifactID column,
and a set of Fields will be created for the remaining columns. The column names will be the Field names.
When you execute a Relativity script, you can pass values for input parameters that are defined in the script
body. In addition to the standard script properties, the following script called Script for Sample Project
includes the input parameter _identifier that is named ControlNumber. For more information, see Script
development on the Relativity 8.1 Developers site.
<script>
<name>Script for Sample Project</name>
Relativity | Services API Guide - 192
<description></description>
<category></category>
<input>
<constant id="_identifier " name="ControlNumber" type="text" />
</input>
<action returns="table"><![CDATA[
SELECT ArtifactID, ControlNumber, ExtractedText FROM [Document]
WHERE ControlNumber = #_identifier#]]></action>
</script>
The following code sample illustrates how to pass a value for a script parameter when running a script by
calling the ExecuteRelativityScript() method on a RelativityScript DTO Repository object.
public static bool ExecuteRelativityScript(IRSAPIClient proxy)
{
// STEP 1: Query by name for the script that you want to run.
// Alternatively, if you have the ArtifactID, you can create a
// RelativityScript object without querying as exemplified here:
// DTOs.RelativityScript script = new DTOs.RelativityScript(1036254);
DTOs.RelativityScript script;
TextCondition nameCondition =
new TextCondition(DTOs.RelativityScriptFieldNames.Name,
TextConditionEnum.EqualTo,
"Script For Sample Project");
DTOs.Query<DTOs.RelativityScript> relScriptQuery = new
DTOs.Query<DTOs.RelativityScript>
{
Condition = nameCondition,
Fields = DTOs.FieldValue.NoFields
};
try
{
DTOs.QueryResultSet<DTOs.RelativityScript> relScriptQueryResults = null;
relScriptQueryResults = proxy.Repositories.RelativityScript.Query
(relScriptQuery);
if (!relScriptQueryResults.Success)
{
Console.WriteLine(string.Format("An error occurred finding the script:
{0}",
relScriptQueryResults.Message));
return false;
}
Relativity | Services API Guide - 193
script = relScriptQueryResults.Results[0].Artifact;
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for Relativity Scripts: {0}
", ex.Message);
return false;
}
// STEP 2: Set the input parameter used in the Relativity Script.
// The following sample Relativity Script contains an input parameter called
"ControlNumber":
// <input>
// <constant id="_identifier" name="ControlNumber" type="text" />
// </input>
RelativityScriptInput input = new RelativityScriptInput("ControlNumber",
"AS000005");
List<RelativityScriptInput> inputList = new List<RelativityScriptInput> {
input };
// STEP 3: Call the script.
RelativityScriptResult scriptResult = null;
try
{
scriptResult =
proxy.Repositories.RelativityScript.ExecuteRelativityScript(script,
inputList);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
//Check for success.
if (!scriptResult.Success)
{
Console.WriteLine(string.Format(scriptResult.Message));
return false;
}
else
{
Int32 observedOutput = scriptResult.Count;
Console.WriteLine(string.Format("Number of documents returned: {0}",
observedOutput));
Relativity | Services API Guide - 194
foreach (Artifact art in scriptResult.Artifacts)
{
Console.WriteLine(string.Format("{0}: {1}", art.ArtifactID, art.Fields
[1].Value));
}
}
return true;
}
6.15.4 Retrieving Input for a RelativityScript
You can use the GetRelativityScriptInputs() method to retrieve a list of input data for a script. An individual
input parameter is represented by an instance of the RelativityScriptInputDetails class. You must be a
member of the Relativity Script Admin group to use the GetRelativityScriptInputs() method. The following
code sample illustrates how to use this method.
public static IList<RelativityScriptInputDetails> GetRelativityScriptInputs
(IRSAPIClient proxy)
{
List<RelativityScriptInputDetails> scriptInputList = null;
.
// STEP 1: Using ArtifactID, set the script you want to run.
DTOs.RelativityScript script = new DTOs.RelativityScript(1036254);
// STEP 2: Call GetRelativityScriptInputs.
try
{
scriptInputList =
proxy.Repositories.RelativityScript.GetRelativityScriptInputs(script);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return scriptInputList;
}
// STEP 3: Each RelativityScriptInputDetails object can be used to generate
a RelativityScriptInput object,
// but this example only displays information about each input.
foreach (RelativityScriptInputDetails relativityScriptInputDetails in
scriptInputList)
{
Console.WriteLine("Input Name: {0}\nInput Id: {1}\nInput Type: {2}\nInput
Is Required: {3}\n",
Relativity | Services API Guide - 195
relativityScriptInputDetails.Name,
relativityScriptInputDetails.Id,
relativityScriptInputDetails.InputType,
relativityScriptInputDetails.IsRequired);
}
return scriptInputList;
}
6.16 Tab
You select tabs to access Relativity features, such as documents, RDOs, or applications. You can also use tabs
as links to custom pages and other external resources. For more information, see Tabs in the Relativity 8.1
Documentation site, and Custom pages in the Relativity 8.1 Developers site.
The Services API supports read and query operations on a Tab DTO.
6.16.1 Reading a Tab
To read Field values on a Tab, you can use the Read() method on the Tab repository as illustrated in this code
sample.
public static bool Read_Tab(IRSAPIClient proxy)
{
// STEP 1: Call the Read() method on the Tab repository.
DTOs.Tab requestedTab = new DTOs.Tab(1034254);
requestedTab.Fields = DTOs.FieldValue.AllFields;
DTOs.ResultSet<DTOs.Tab> results = null;
try
{
results = proxy.Repositories.Tab.Read(requestedTab);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
//Check for success.
if (!results.Success)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(results.Message);
return false;
}
Relativity | Services API Guide - 196
// STEP 2: Get the Artifact from the read results.
DTOs.Tab tab = results.Results[0].Artifact;
Console.WriteLine(">>>" + tab.ToString() + "<<<");
return true;
}
6.16.2 Querying for a Tab
This code sample illustrates how to set query conditions, call the Query() method on the Tab repository, and
iterate through the result set.
public static bool Query_Tabs(IRSAPIClient proxy)
{
// STEP 1: Setup your query criteria.
DTOs.Query<DTOs.Tab> query = new DTOs.Query<DTOs.Tab>();
TextCondition parentCriteria = new TextCondition
(DTOs.TabFieldNames.LinkType, TextConditionEnum.EqualTo, "Parent");
query.Condition = parentCriteria;
query.Fields = DTOs.FieldValue.AllFields;
// STEP 2: Call the query method on the Tab Repository.
DTOs.QueryResultSet<DTOs.Tab> results = null;
try
{
results = proxy.Repositories.Tab.Query(query);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
//Check for success.
if (!results.Success)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(results.Message);
return false;
}
// STEP 3: Get the tabs from the query results.
foreach (DTOs.Result<DTOs.Tab> tabResult in results.Results)
Relativity | Services API Guide - 197
{
DTOs.Tab tab = tabResult.Artifact;
Console.WriteLine(tab.Name + " is a Parent tab.");
}
return true;
}
6.17 User
Individuals are added to Relativity as users, who are then added to groups associated with workspaces. For
more information, see Users in the the Relativity 8.1 Documentation site.
The Services API supports all CRUD and query operations on a User DTO.
6.17.1 Creating a User
You can add a User to Relativity by calling the Create() method on the User repository. For more information
about Password fields, see Fields used by Group and User objects on page 144.
This code sample illustrates how to create the User DTO and references several utility methods for retrieving
ArtifactIDs. See Utility methods used in User DTO creation on page 201.
public static bool CreateUserUsingRepository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
int
int
int
int
int
int
defaultSelectedFileType = 1;
userType = 3;
documentSkip = 1000003;
skipDefaultPreference = 1000004;
password = 1000005;
sendNewPasswordTo = 1000006;
// STEP 1: Get the ArtifactIDs for the required Choice, Group, and Client
objects.
int returnPasswordCodeID = FindChoiceArtifactID(proxy, sendNewPasswordTo,
"Return");
int passwordCodeID = FindChoiceArtifactID(proxy, password, "Auto-generate
password");
int documentSkipCodeID = FindChoiceArtifactID(proxy, documentSkip,
"Enabled");
int documentSkipPreferenceCodeID = FindChoiceArtifactID(proxy,
skipDefaultPreference, "Normal");
Relativity | Services API Guide - 198
int defaultFileTypeCodeID = FindChoiceArtifactID(proxy,
defaultSelectedFileType, "Native");
int userTypeCodeID = FindChoiceArtifactID(proxy, userType, "Internal");
int everyoneGroupArtifactID = FindGroupArtifactID(proxy, "Everyone");
int clientArtifactID = FindClientArtifactID(proxy, "Relativity Template");
// STEP 2: Create a User DTO for the User that you want to create.
kCura.Relativity.Client.DTOs.User userDTO = new
kCura.Relativity.Client.DTOs.User();
userDTO.AdvancedSearchPublicByDefault = true;
userDTO.AuthenticationData = "";
userDTO.BetaUser = false;
userDTO.ChangePassword = true;
userDTO.ChangePasswordNextLogin = false;
userDTO.ChangeSettings = true;
userDTO.Client = new kCura.Relativity.Client.DTOs.Client(clientArtifactID);
userDTO.DataFocus = 1;
userDTO.DefaultSelectedFileType = new kCura.Relativity.Client.DTOs.Choice
(defaultFileTypeCodeID);
userDTO.DocumentSkip = new kCura.Relativity.Client.DTOs.Choice
(documentSkipCodeID);
userDTO.EmailAddress = "zzz12344@test.com";
userDTO.EnforceViewerCompatibility = true;
userDTO.FirstName = "Bruce";
userDTO.Groups =
new List<kCura.Relativity.Client.DTOs.Group>
{ new kCura.Relativity.Client.DTOs.Group(everyoneGroupArtifactID) };
userDTO.ItemListPageLength = 25;
userDTO.KeyboardShortcuts = true;
userDTO.LastName = "User for User Create Testing";
userDTO.MaximumPasswordAge = 0;
userDTO.NativeViewerCacheAhead = true;
userDTO.PasswordAction = new kCura.Relativity.Client.DTOs.Choice
(passwordCodeID);
userDTO.RelativityAccess = true;
userDTO.SendPasswordTo = new kCura.Relativity.Client.DTOs.Choice
(returnPasswordCodeID);
Relativity | Services API Guide - 199
userDTO.SkipDefaultPreference = new kCura.Relativity.Client.DTOs.Choice
(documentSkipPreferenceCodeID);
userDTO.TrustedIPs = "";
userDTO.Type = new kCura.Relativity.Client.DTOs.Choice(userTypeCodeID);
WriteResultSet<kCura.Relativity.Client.DTOs.User> createResults =
new WriteResultSet<kCura.Relativity.Client.DTOs.User>();
// STEP 3: Attempt to create the User.
try
{
createResults = proxy.Repositories.User.Create(userDTO);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
return false;
}
// Check for success.
if (!createResults.Success)
{
Console.WriteLine(String.Format("An error occurred creating user: {0}",
createResults.Message));
foreach (Result<kCura.Relativity.Client.DTOs.User> createResult in
createResults.Results)
{
if (!createResult.Success)
{
Console.WriteLine(String.Format(" An error occurred in create
request: {0}", createResult.Message));
}
}
return false;
}
//STEP 4: Output the password.
Console.WriteLine(String.Format("Password for created user is {0}",
createResults.Results[0].Artifact["Password"]));
return true;
}
Relativity | Services API Guide - 200
6.17.2 Utility methods used in User DTO creation
The code sample illustrating how to create the User DTO uses the following utility methods to facilitate the
retrieval of ArtifactIDs for Choices, Groups, and Clients.
FindChoiceArtifactID() method
private static int FindChoiceArtifactID(IRSAPIClient proxy, int choiceType,
string value)
{
int artifactID = 0;
WholeNumberCondition choiceTypeCondition =
new WholeNumberCondition(ChoiceFieldNames.ChoiceTypeID,
NumericConditionEnum.EqualTo, (int)choiceType);
TextCondition choiceNameCondition =
new TextCondition(ChoiceFieldNames.Name, TextConditionEnum.EqualTo,
value);
CompositeCondition choiceCompositeCondition =
new CompositeCondition(choiceTypeCondition, CompositeConditionEnum.And,
choiceNameCondition);
Query<kCura.Relativity.Client.DTOs.Choice> choiceQuery =
new Query<kCura.Relativity.Client.DTOs.Choice>(new List<FieldValue> { new
FieldValue(ArtifactQueryFieldNames.ArtifactID) },
choiceCompositeCondition, new List<Sort>());
try
{
QueryResultSet<kCura.Relativity.Client.DTOs.Choice> choiceQueryResult =
proxy.Repositories.Choice.Query(choiceQuery);
if (choiceQueryResult.Success && choiceQueryResult.Results.Count == 1)
{
artifactID = choiceQueryResult.Results.FirstOrDefault
().Artifact.ArtifactID;
}
else
{
Console.WriteLine("The choice could not be found.");
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("An error occurred: {0}", ex.Message));
Relativity | Services API Guide - 201
}
return artifactID;
}
FindGroupArtifactID() method
private static int FindGroupArtifactID(IRSAPIClient proxy, string group)
{
int artifactID = 0;
TextCondition groupCondition =
new TextCondition(GroupFieldNames.Name, TextConditionEnum.EqualTo,
group);
Query<kCura.Relativity.Client.DTOs.Group> queryGroup =
new
kCura.Relativity.Client.DTOs.Query<kCura.Relativity.Client.DTOs.Group> {
Condition = groupCondition };
queryGroup.Fields.Add(new FieldValue(ArtifactQueryFieldNames.ArtifactID));
try
{
QueryResultSet<kCura.Relativity.Client.DTOs.Group> resultSetGroup =
proxy.Repositories.Group.Query(queryGroup, 0);
if (resultSetGroup.Success && resultSetGroup.Results.Count == 1)
{
artifactID = resultSetGroup.Results.FirstOrDefault
().Artifact.ArtifactID;
}
else
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSetGroup.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}",
ex.Message));
}
return artifactID;
}
FindClientArtifactID() method
Relativity | Services API Guide - 202
private static int FindClientArtifactID(IRSAPIClient proxy, string group)
{
int artifactID = 0;
TextCondition clientCondition =
new TextCondition(ClientFieldNames.Name, TextConditionEnum.EqualTo,
group);
Query<kCura.Relativity.Client.DTOs.Client> queryClient =
new Query<kCura.Relativity.Client.DTOs.Client> { Condition =
clientCondition };
queryClient.Fields = FieldValue.AllFields;
try
{
QueryResultSet<kCura.Relativity.Client.DTOs.Client> resultSetClient =
proxy.Repositories.Client.Query(queryClient, 0);
if (resultSetClient.Success && resultSetClient.Results.Count == 1)
{
artifactID = resultSetClient.Results.FirstOrDefault
().Artifact.ArtifactID;
}
else
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSetClient.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
}
return artifactID;
}
6.17.3 Reading a User
To read Field values, you can use the Read() method on the User repository as illustrated in this code sample.
public static bool ReadUserUsingRepository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
Relativity | Services API Guide - 203
// STEP 1: Create the User DTO.
kCura.Relativity.Client.DTOs.User user = new
kCura.Relativity.Client.DTOs.User(1015464);
user.Fields = FieldValue.AllFields;
ResultSet<kCura.Relativity.Client.DTOs.User> userResults = null;
//STEP 2: Read the User DTO.
try
{
userResults = proxy.Repositories.User.Read(user);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred reading the user: {0}", ex.Message);
return false;
}
//STEP 3: Check for success.
if (!userResults.Results.Any())
{
Console.WriteLine("Could not find the user: {0}", userResults.Message);
return false;
}
return true;
}
6.17.4 Updating a User
You can use the Update() method on the User repository to modify its properties as illustrated in this code
sample. See Fields used by Group and User objects on page 144.
public static bool UpdateUserUsingRepository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
//STEP 1: Define the query.
Condition userQueryCondition =
new TextCondition(UserFieldNames.FirstName, TextConditionEnum.EqualTo,
"Bruce");
Query<kCura.Relativity.Client.DTOs.User> userQuery =
new Query<kCura.Relativity.Client.DTOs.User>(FieldValue.AllFields,
userQueryCondition, new List<Sort>());
QueryResultSet<kCura.Relativity.Client.DTOs.User> userQueryResults = null;
Relativity | Services API Guide - 204
//STEP 2: Query for the User.
try
{
userQueryResults = proxy.Repositories.User.Query(userQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for the user: {0}",
ex.Message);
return false;
}
if (!userQueryResults.Results.Any())
{
Console.WriteLine("Could not find the user: {0}",
userQueryResults.Message);
return false;
}
//STEP 3: Retreive the User artifact and update it.
kCura.Relativity.Client.DTOs.User userToUpdate =
userQueryResults.Results.First().Artifact;
userToUpdate.FirstName = "Steve";
WriteResultSet<kCura.Relativity.Client.DTOs.User> userUpdateResults = null;
//STEP 4: Complete the update.
try
{
userUpdateResults = proxy.Repositories.User.Update(userToUpdate);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred updating the user: {0}",
ex.Message);
return false;
}
//STEP 5: Check for success.
if (userUpdateResults.Success)
{
Console.WriteLine("The user has been updated!");
}
else
{
Relativity | Services API Guide - 205
Console.WriteLine("An error occurred updating the user: {0}",
userUpdateResults.Message);
return false;
}
return true;
}
6.17.5 Deleting a User
You can remove a User from Relativity by calling the Delete() method on the User repository as illustrated in
this code sample.
public static bool DeleteUserUsingRepository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
// STEP 1: Create the User DTO.
kCura.Relativity.Client.DTOs.User user = new
kCura.Relativity.Client.DTOs.User(1015464);
ResultSet<kCura.Relativity.Client.DTOs.User> userResults = null;
// STEP 2: Delete the User.
try
{
userResults = proxy.Repositories.User.Delete(user);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred deleting for the user: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!userResults.Results.Any())
{
Console.WriteLine("Could not delete the user: {0}", userResults.Message);
return false;
}
return true;
}
6.17.6 Querying for a User
This code sample illustrates how to set query conditions, call the Query() method on the User repository, and
iterate through the result set.
Relativity | Services API Guide - 206
public static bool QueryUserUsingRepository(IRSAPIClient proxy)
{
proxy.APIOptions.WorkspaceID = -1;
// STEP 1: Create the query for a given user.
Condition userQueryCondition =
new TextCondition(UserFieldNames.FirstName, TextConditionEnum.EqualTo,
"Bruce");
Query<kCura.Relativity.Client.DTOs.User> userQuery =
new Query<kCura.Relativity.Client.DTOs.User>(FieldValue.AllFields,
userQueryCondition, new List<Sort>());
QueryResultSet<kCura.Relativity.Client.DTOs.User> userQueryResults = null;
// STEP 2: Query for the user.
try
{
userQueryResults = proxy.Repositories.User.Query(userQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for the user: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!userQueryResults.Results.Any())
{
Console.WriteLine("Could not find the user: {0}",
userQueryResults.Message);
return false;
}
return true;
}
6.18 View
Relativity uses views to provide customizable item lists. For more information, see Views in the Relativity 8.1
Documentation site.
The Services API supports read and query operations on a View DTO.
Relativity | Services API Guide - 207
6.18.1 Reading a View
To read Field values on a View, you can use the Read() method on the View repository as illustrated in this
code sample.
public static bool Read_View_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create a View DTO for the View to be read.
DTOs.View viewDTO = new DTOs.View(1034249);
viewDTO.Fields = FieldValue.AllFields;
ResultSet<DTOs.View> viewReadResults = new ResultSet<DTOs.View>();
// STEP 2: Try to read the View.
try
{
viewReadResults = proxy.Repositories.View.Read(viewDTO);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred reading the view: {0}", ex.Message);
return false;
}
// STEP 3: Check for success.
if (!viewReadResults.Success)
{
Console.WriteLine("An error occurred reading the view: {0}",
viewReadResults.Message);
foreach (Result<DTOs.View> readResult in viewReadResults.Results)
{
if (!readResult.Success)
{
Console.WriteLine(" An error occurred in read request: {0}",
readResult.Message);
}
}
return false;
}
// STEP 4: Output the name.
Console.WriteLine("Successfully read the view '{0}'!",
viewReadResults.Results[0].Artifact.Name);
return true;
}
Relativity | Services API Guide - 208
6.18.2 Querying for a View
This code sample illustrates how to set query conditions, call the Query() method on the View repository, and
iterate through the result set.
public static bool Query_View_Using_Repository(IRSAPIClient proxy)
{
// STEP 1: Create the Query criteria.
ObjectsCondition relAppCondition =
new ObjectsCondition("Relativity Applications",
ObjectsConditionEnum.AllOfThese, new int[] { 1035699 });
Query<DTOs.View> viewQuery = new Query<DTOs.View>
{
Condition = relAppCondition,
Fields = FieldValue.AllFields
};
// STEP 2: Try to query for the View.
QueryResultSet<DTOs.View> viewQueryResults = null;
try
{
viewQueryResults = proxy.Repositories.View.Query(viewQuery);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred querying for views: {0}",
ex.Message);
return false;
}
// STEP 3: Check for success.
if (!viewQueryResults.Success)
{
Console.WriteLine("An error occurred querying for views: {0}",
viewQueryResults.Message);
return false;
}
// STEP 4: Display the results.
Console.WriteLine("Number of views returned: {0}",
viewQueryResults.Results.Count);
foreach (Result<DTOs.View> viewResult in viewQueryResults.Results)
{
Relativity | Services API Guide - 209
DTOs.View curView = viewResult.Artifact;
Console.WriteLine("View Name: {0}", curView.TextIdentifier);
Console.WriteLine("View ArtifactID: {0}", curView.ArtifactID);
}
return true;
}
6.19 Workspace
In Relativity, workspaces are secure data repositories for storing documents and applications. For additional
information, see Workspaces in the Relativity 8.1 Documentation site.
The Services API supports read and query operations on a Workspace DTO.
6.19.1 Reading a Workspace
To read Field values on a Workspace, you can use the Read() method on the Workspace repository as
illustrated in this code sample.
public static bool Read_Workspace(IRSAPIClient proxy)
{
// STEP 1: Create ResultSet to store Results.
ResultSet<DTOs.Workspace> resultSet = new ResultSet<DTOs.Workspace>();
// STEP 2: Perform the Read operation.
// You could create a DTOs.Workspace object, set its ArtifactID property,
// and use the Workspace object as the parameter. However, this example
// demonstrates using the ArtifactID as a parameter.
try
{
resultSet = proxy.Repositories.Workspace.Read(1016204);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: {0}", ex.Message);
return false;
}
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Read operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
Relativity | Services API Guide - 210
}
// Display results.
Console.WriteLine("Read completed successfully.");
foreach (DTOs.Result<DTOs.Workspace> workspaceResult in resultSet.Results)
{
Console.WriteLine(String.Format("{0}Name:{1}", Environment.NewLine,
workspaceResult.Artifact.Name));
Console.WriteLine(String.Format("ArtifactID:{0}",
workspaceResult.Artifact.ArtifactID));
}
return true;
}
6.19.2 Querying for a Workspace
This code sample illustrates how to set query conditions, call the Query() method on the Workspace
repository, and iterate through the result set.
public static bool Query_Workspace(IRSAPIClient proxy)
{
//STEP 1: Create a Query and WholeNumberCondition.
WholeNumberCondition workspaceCondition =
new WholeNumberCondition(ArtifactQueryFieldNames.ArtifactID,
NumericConditionEnum.EqualTo, 1016204);
Query<DTOs.Workspace> query = new DTOs.Query<DTOs.Workspace> { Condition =
workspaceCondition };
query.Fields = FieldValue.AllFields;
//STEP 2: Create QueryResultSet to collect information about the DTO after
Query.
QueryResultSet<DTOs.Workspace> resultSet = new
QueryResultSet<DTOs.Workspace>();
//STEP 3: Perform the Query.
try
{
resultSet = proxy.Repositories.Workspace.Query(query, 0);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
Relativity | Services API Guide - 211
return false;
}
//Check for success.
if (!resultSet.Success)
{
Console.WriteLine("The Query operation failed.{0}{1}",
Environment.NewLine, resultSet.Message);
return false;
}
// Display the results.
Console.WriteLine(string.Format("Number of Workspaces returned: {0}",
resultSet.Results.Count));
foreach (DTOs.Result<DTOs.Workspace> workspaceResult in resultSet.Results)
{
Console.WriteLine(string.Format("{0}Name:{1}", Environment.NewLine,
workspaceResult.Artifact.Name));
Console.WriteLine(string.Format("ArtifactID:{0}",
workspaceResult.Artifact.ArtifactID));
}
return true;
}
7 Additional Services API functionality
The Services API includes additional features for querying, file transfers, mass operations, and others.
7.1 File transfers
Through the Services API, you can perform download and upload requests on a File field as well as clear the
field.
7.1.1 Supported file transfer operations
The RSAPIClient supports the following operations for file transfers:
n
Download () - The following overloaded methods are available:
o
Download(FileRequest) - downloads the contents of a Relativity file field and returns it in the
form of a Stream object. It takes a FileRequest and returns an instance of DownloadResponse. It
raises the DownloadComplete event when the operation is successful.
o
Download(FileRequest, String) - accepts a FileRequest, and a String which represents the
destination location of the file on disk.
Relativity | Services API Guide - 212
Note: You can also download files by using the URL retrieved from a File field on a Dynamic Object. See
Getting a download URL for a File field on page 139.
n
n
Upload () - takes an UploadRequest. It raises the UploadComplete event when the operation is successful. The Upload() and Download() methods support zero-length files.
Clear () - clears the value of a file field in Relativity. It returns no response when it completes successfully.
When an operation fails on these methods, a Failure event is raised that contains instance of FailureEventArgs
class. This instance contains the exception that would have been thrown during a failed operation. See
RSAPIClient events in the Services API class library.
7.1.2 File transfer error messages
The following table lists error classes associated with various operations related to file transfers.
Operation
All Operations
Error Classes
FileTransferFault
InvalidFieldIdFault
InvalidObjectArtifactIdFault
InvalidWorkspaceIdFault
MissingFileFieldFault
FileSizeMismatchFault
NoOverwriteFault
OperationInProgressfault
EmptyFieldFault
No error messages
Upload()
Download()
Clear()
7.1.3 Error classes
In the Services API, you can use error classes to obtain additional information for troubleshooting. Each error
class uses one or more dedicated messages. The returned exception object has as a property named
Message. The following table lists the error classes as well as their associated messages and possible causes.
Class
EmptyFieldFault
FileSizeMismatchFault
FileTransferFault
FileTransferFault
Message
Field is empty, no file to download.
Size specified in request does not
match size of file received.
Cause
Field contains no file.
Number of bytes written to disk by the
server doesn't match the number specified in the
UploadRequest.Metadata.FileSize
property.
Request could not be authenToken supplied doesn't refer to a
ticated.
logged-in session
Cannot download chunk index [X] An invalid chunk index was specified
for file, there are only [Z] chunks
during the download operation.
total.
Relativity | Services API Guide - 213
Class
FileTransferFault
FileTransferFault
InvalidFieldIdFault
InvalidObjectArtifactIdFault
InvalidWorkspaceIdFault
MissingFileFieldFault
NoOverwriteFault
OperationInProgressFault
Message
Invalid sessionId.
Cause
SessionId supplied during a transfer
operation doesn't refer to an existing
transfer session.
Unable to parse sessionId.
SessionId supplied during a transfer
operation is in an invalid format.
FieldId is invalid.
The Target.FieldId property supplied is
<= 0.
ObjectArtifactId is invalid.
The Target.ObjectArtifactId property
supplied is <= 0.
WorkspaceId is invalid.
The Target.WorkspaceId property supplied is <= 0.
No file field with id [X] could be
The Target.FieldId property supplied
found.
doesn't refer to an existing field.
Field with existing value not over- The file field referred to by Tarwritten.
get.FieldId isn't empty but
UploadRequest. Overwrite is set to
False.
An upload operation is in progress An upload operation is currently in proalready for the object with id [X] in gress on the specified field in the workthe workspace with id [Z].
space.
7.1.4 Sample error handling code
Use the following guidelines when handling errors:
n
n
n
Listen for the Failure event on the RSAPIClient class. See RSAPIClient.Failure Event in the Services API
class library.
Pull the exception thrown during a transfer operation from the FailureEventArgs.Exception property.
Inspect the type of the exception so you can take the appropriate action. All of the FaultException
errors thrown by the RSAPIClient service are caught, as well as any .NET framework exceptions. The
exception isn't always a FaultException<T>.
The following sample illustrates a basic approach to error handling in the Services API:
private void HandleFailureEvents(FalureEventArgs failureInfo)
{
Exception excepDetail = failureInfo.Exception;
if (excepDetail is FaultException<OperationInProgressFault>) {
Interaction.MsgBox(excepDetail > Message, MsgBoxStyle.Critical,
"Error!");
} else {
Interaction.MsgBox("An error occurred!", MsgBoxStyle.Critical, "Error");
}
}
Relativity | Services API Guide - 214
7.2 Mass processes
The Services API provides you with the ability to perform an operation on multiple items with a single API call.
7.2.0.1 Using Lists of Artifacts as input to CRUD methods
Each of the CRUD methods takes a List of Artifacts so you can perform these operations on multiple objects in
single call. Use the following guidelines when submitting ArtifactRequests for CRUD operations:
n
n
n
You can pass ArtifactRequests of different types. For example, you could submit a list of ArtifactRequests to the Update() method that contains Artifacts for Documents and Dynamic Objects.
You must pass all the parameters required by the CRUD method that you are using for each ArtifactRequest. For example, you must pass the ArtifactType and list of Fields for each ArtifactRequest
when creating Artifacts.
No transactional guarantee exists for the method as a whole. The creation, update or deletion of each
ArtifactRequest is handled individually. If the operation against a single ArtifactRequest fails, the Success flag on the Result object for the corresponding ArtifactRequest is set to False, and returned in the
ResultSet. The operations on the other ArtifactRequests will proceed.
7.2.0.2 MassCreate() and MassCreateWithDetails() methods
You can use the MassCreate() and MassCreateWithDetails() methods to create multiple Dynamic Objects.
Both methods use a template to minimize the repetition of Field values that are common to all the Artifacts.
The MassCreateWithDetails() method also populates the Results property with success and failure
information as part of the object creation process. This information is provided even when a partial failure
occurs.
The MassCreate() and MassCreateWithDetails() methods take the Fields specified for each Artifact included in
the List of Artifacts passed as a parameter.
View sample code for the MassCreate() method
public static bool Using_MassCreate(IRSAPIClient proxy)
{
// STEP 1: Create Artifact that serves as a template for the RDOs that you
want to create.
ArtifactRequest artifactRequest = new ArtifactRequest("Employees");
List<Field> templateFields = new List<Field>();
templateFields.Add(new
templateFields.Add(new
templateFields.Add(new
artifactRequest.Fields
Field("Name"));
Field("Last Name"));
Field("Employment Level", 1036226));
= templateFields;
// STEP 2: Create a list of Artifacts of RDOs to create via MassCreate.
List<ArtifactRequest> artifactRequestList = new List<ArtifactRequest>();
for (int i = 1; i <= 10; i++)
{
ArtifactRequest anotherArtifactRequest = new ArtifactRequest();
Relativity | Services API Guide - 215
List<Field> fields = new List<Field>();
fields.Add(new Field("Name", i.ToString()));
fields.Add(new Field("Last Name", "Employee #:" + i.ToString()));
anotherArtifactRequest.Fields = fields;
anotherArtifactRequest.ParentArtifactID = 1016204;
// The identifier 1016204 is the WorkspaceID.
artifactRequestList.Add(anotherArtifactRequest);
}
// STEP 3: Call the Services API to MassCreate the Employees.
MassCreateResult results = new MassCreateResult();
try
{
results = proxy.MassCreate(proxy.APIOptions, artifactRequest,
artifactRequestList);
Console.WriteLine(string.Format("MassCreate Success Flag: {0}",
results.Success));
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
if (!results.Success)
{
Console.WriteLine(results.Message);
foreach (Result r in results.Results)
{
Console.WriteLine(r.Message);
}
return false;
}
return true;
}
View sample code for the MassCreateWithDetails() method
public static bool Using_MassCreateWithDetails(IRSAPIClient proxy)
{
Relativity | Services API Guide - 216
// STEP 1: Create Artifact that serves as a template for the RDOs that you
want to create.
ArtifactRequest artifactRequest = new ArtifactRequest("Employees");
List<Field> templateFields = new List<Field>();
templateFields.Add(new Field("Name"));
templateFields.Add(new Field("Last Name"));
templateFields.Add(new Field("Employment Level", 1036226));
artifactRequest.Fields = templateFields;
// STEP 2: Create a list of Artifacts of the RDOs created via MassCreate.
List<ArtifactRequest> artifactRequestList = new List<ArtifactRequest>();
for (int i = 1; i <= 10; i++) {
ArtifactRequest anotherArtifactRequest = new ArtifactRequest();
List<Field> fields = new List<Field>();
fields.Add(new Field("Name", i.ToString()));
fields.Add(new Field("Last Name", "Employee #:" + i.ToString()));
anotherArtifactRequest.Fields = fields;
anotherArtifactRequest.ParentArtifactID = 1016204;
// The identifier 1016204 is the WorkspaceID.
artifactRequestList.Add(anotherArtifactRequest);
}
// STEP 3: Call the Services API to MassCreate the Employees.
MassCreateResult results = new MassCreateResult();
try {
results = proxy.MassCreateWithDetails(proxy.APIOptions, artifactRequest,
artifactRequestList);
Console.WriteLine(string.Format("MassCreate Success Flag: {0}",
results.Success));
}
catch (Exception ex) {
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
// The results objects contains the Artifact ID for each new Artifact.
if (results.Success) {
Console.WriteLine("Total Artifacts Created: " + results.Count);
Relativity | Services API Guide - 217
foreach (Result result in results.Results)
{
Console.WriteLine("Created Artifact: " + result.ArtifactID);
}
}
else {
Console.WriteLine(results.Message);
foreach (Result r in results.Results) {
Console.WriteLine(r.Message);
}
return false;
}
//Clean up.
try {
artifactRequestList = new List<ArtifactRequest>();
for (int i = 1; i <= 10; i++) {
ArtifactRequest anotherArtifactRequest =
new ArtifactRequest("Employees", results.Results[i-1].ArtifactID);
artifactRequestList.Add(anotherArtifactRequest);
}
proxy.Delete(proxy.APIOptions, artifactRequestList);
}
catch (Exception ex) {
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
return true;
}
The mass create methods are subject to the following restrictions:
n
n
n
n
Only Dynamic Objects can be created with this method.
All Artifacts to be created must be of the same ArtifactType, and all Fields must be specified by Name.
Don't use the ArtifactID.
Each Field in the template must have a value, and be specified by Name. Don't use NULL values or specify Fields by ArtifactID.
All required Fields must have values.
Note: The Configuration Table contains the MaxNumberOfArtfactsToMassCreate setting, which controls
the maximum number of Dynamic Objects that can be create with this method. The default value is
currently 1,000,000.
Relativity | Services API Guide - 218
7.2.0.3 MassEdit() method
You can use the MassEdit() method to apply the same set of Field updates to multiple Documents in a single
call. This method uses a template Document as an ArtifactRequest, which determines how the call updates
other documents. It also takes a list of ArtifactIDs that identify the Documents for editing. You can only
update Documents with this method, and updates aren't propagated to related documents as they are in the
Relativity web UI.
Note: The Configuration Table contains the MaxNumberOfArtfactsToMassEdit setting, which controls
maximum number of documents edited in a single call. The default value is 1,000,000. In addition, the
MassEdit() method updates the documents in batches. MassEditBatchAmount is the configuration setting
that controls the number of documents in each batch, and it is also used by the Relativity web UI. The
default and recommended value is 1,000.
View sample code for the MassEdit() method
public static bool Using_MassEdit(IRSAPIClient proxy)
{
// STEP 1: Create Artifact that serves as a template for the Documents that
you want to update.
List<Field> fields = new List<Field>();
fields.Add(new Field("MD5 Hash", "New Value"));
ArtifactRequest artifactRequest = new ArtifactRequest("Document");
artifactRequest.Fields = fields;
// STEP 2: Create a list of ArtifactIDs of the Documents updated via
MassEdit.
List<Int32> artifactIDsToUpdate = new List<Int32>() {1035607, 1035608};
//STEP 3: Call the Services API to MassEdit the Documents.
MassEditResult resultSet;
try
{
resultSet = proxy.MassEdit(proxy.APIOptions, artifactRequest,
artifactIDsToUpdate);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
Console.WriteLine(string.Format("MassEdit Success Flag: {0}",
resultSet.Success));
Relativity | Services API Guide - 219
// Check for success.
if (!resultSet.Success)
{
Console.WriteLine(resultSet.Message);
return false;
}
return true;
}
7.2.0.4 ExecuteBatch() method
You can use the ExecuteBatch() method to combine multiple operations in a single database transaction. For
example, you could create a set of Artifacts and update a set of Documents using a single round-trip to the
Services API.
View sample code for the ExecuteBatch() method
public static bool Using_ExecuteBatch(IRSAPIClient proxy)
{
// STEP 1: Create RDOs used later to demonstrate the ExecuteBatch() method.
ArtifactRequest artifactRequest1 = new ArtifactRequest();
artifactRequest1.ParentArtifactID = 1016204;
artifactRequest1.ArtifactTypeName = "Employees";
artifactRequest1.Fields = new List<Field>();
Field nameField1 = new Field("Name", "John");
Field lastNameField1 = new Field("Last Name", "Doe");
artifactRequest1.Fields.Add(nameField1);
artifactRequest1.Fields.Add(lastNameField1);
ArtifactRequest artifactRequest2 = new ArtifactRequest();
artifactRequest2.ParentArtifactID = 1016204;
artifactRequest2.ArtifactTypeName = "Employees";
artifactRequest2.Fields = new List<Field>();
Field nameField2 = new Field("Name", "Jane");
Field lastNameField2 = new Field("Last Name", "Smith");
artifactRequest2.Fields.Add(nameField2);
artifactRequest2.Fields.Add(lastNameField2);
List<ArtifactRequest> artifactRequestList = new List<ArtifactRequest>();
artifactRequestList.Add(artifactRequest1);
artifactRequestList.Add(artifactRequest2);
ResultSet results = new ResultSet();
Relativity | Services API Guide - 220
// Attempt to create the new Users.
try
{
results = proxy.Create(proxy.APIOptions, artifactRequestList);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
List<ArtifactRequest> artifactRequestToReadList = new List<ArtifactRequest>
();
foreach (Result result in results.Results)
{
ArtifactRequest artifactRequestToRead = new ArtifactRequest();
artifactRequestToRead.ArtifactID = result.ArtifactID;
artifactRequestToRead.ArtifactTypeID = 1000036;
artifactRequestToReadList.Add(artifactRequestToRead);
}
ReadResultSet readResultSet = new ReadResultSet();
//Read back the Users just created.
try
{
readResultSet = proxy.Read(proxy.APIOptions, artifactRequestToReadList);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
List<Artifact> sampleEmployees = new List<Artifact>();
foreach (ReadResult readResult in readResultSet.ReadResults)
{
sampleEmployees.Add(readResult.Artifact);
}
ArtifactRequest john =
new ArtifactRequest((Int32)sampleEmployees[0].ArtifactTypeID, (Int32)
sampleEmployees[0].ArtifactID);
ArtifactRequest jane =
Relativity | Services API Guide - 221
new ArtifactRequest((Int32)sampleEmployees[1].ArtifactTypeID, (Int32)
sampleEmployees[1].ArtifactID);
// STEP 2: Create an Update Command for one artifact.
List<ArtifactRequest> artifactRequestsToUpdate = new List<ArtifactRequest>
{ john };
Field lastNameField = sampleEmployees[0].Fields.FirstOrDefault(field =>
field.Name == "Last Name");
lastNameField.Value = "Doe - Updated";
john.Fields.Add(lastNameField);
// Add a new skill to this employee by updating the Skills Inventory
multichoice field.
Field skills = sampleEmployees[0].Fields.FirstOrDefault(field => field.Name
== "Skills Inventory");
// Define the skill to be added as a MultiChoice Update Value that is
'merged' with any existing skill values.
MultiChoiceUpdateValue skillToBeAdded = new MultiChoiceUpdateValue();
skillToBeAdded.Value = new List<Int32>();
skillToBeAdded.Value.Add(1036219);
skillToBeAdded.Behavior = MultiChoiceUpdateBehavior.Merge;
// Set the Skills field value to be that of the MultiChoiceUpdateValue.
skills.Value = skillToBeAdded;
john.Fields.Add(skills);
Command anUpdateCommand = new UpdateCommand(artifactRequestsToUpdate);
//STEP 3: Create a Delete Command for an artifact.
List<ArtifactRequest> artifactRequestsToDelete = new List<ArtifactRequest>
();
artifactRequestsToDelete.Add(jane);
Command aDeleteCommand = new DeleteCommand(artifactRequestsToDelete);
// STEP 4: Bundle the Command objects into a list. The commands are executed
in the order that they are provided.
List<Command> commands = new List<Command>();
commands.Add(anUpdateCommand);
commands.Add(aDeleteCommand);
ExecuteBatchResultSet executeBatchResults = new ExecuteBatchResultSet();
// STEP 5: Call the Services API to execute the batch of Commands.
try
{
Relativity | Services API Guide - 222
executeBatchResults = proxy.ExecuteBatch(proxy.APIOptions, commands,
TransactionType.Batch);
Console.WriteLine(string.Format("Batch Success Flag: {0}",
results.Success));
if (!results.Success)
{
foreach (ResultSet resultSetItem in executeBatchResults.ResultSets)
{
Console.WriteLine(resultSetItem.ResultSetType.ToString() + ": " +
resultSetItem.Success.ToString());
foreach (Result resultItem in resultSetItem.Results)
{
if (!resultItem.Success)
Console.WriteLine(resultItem.Message);
}
}
return false;
}
}
catch (Exception ex)
{
Console.WriteLine("There was an error:" + ex.Message);
}
return true;
}
Use the following guidelines when calling this method:
n
n
n
Input to the ExecuteBatch() method is a List of Command objects.
All operations execute within a database transaction. If an error occurs, the entire batch is rolled-back.
Executing a large number of create, update, and delete operations may take considerable time and result in table locking.
Note: The Configuration Table contains the MaxArtifactBatchSizeForExecuteBatch setting, which controls
the number of Artifacts processed in a single method call. The default value is 2000, but you can update it
as necessary. This setting has been implemented to limit the length of time that database transaction
opened by ExecuteBatch() method holds locks on tables, preventing Relativity users from experiencing
errors.
7.2.1 Mass delete operations
Using the Services API, you can perform mass delete operations on Documents and their associated files, as
well as on other object types. The account used to perform these operations must be a Relativity
administrator with Delete Object Dependencies permissions. See Security permissions on the Relativity 8.1
Documentation site.
Relativity | Services API Guide - 223
The methods, classes, and the enumeration used to perform mass delete operations are available in the
kCura.Relativity.Client namespace.
Note: For the code samples provided on this page, you can assume that the APIOptions object on the
proxy has the appropriate token and WorkspaceID.
7.2.1.1 MassDeleteOptions and DocumentMassDeleteOptions classes
When calling the mass delete methods, you need to pass an instance of the MassDeleteOptions or
DocumentMassDeleteOptions class. These classes provides information about how to delete objects.
DocumentMassDeleteOptions class
You pass an instance of the DocumentMassDeleteOptions class to the MassDeleteDocuments() or
MassDeleteAllDocuments() methods. To indicate how to perform the deletion, you can set either or both of
the following fields on the DocumentMassDeleteOptions class to true or false:
n
n
Force Delete – removes the selected Documents even if they have redactions, annotations, links, or
tags.
Cascade Delete – removes the selected Documents, as well as deletes all child objects and unlinks associative objects.
In addition, you can use the DeleteType enumeration to specify the type of files associated with the
Documents that you want to delete:
n
n
n
n
AllAssociatedFiles – indicates that you want to delete Documents and all dependent files, including
images and native files. It also results in the deletion of field values.
Images – indicates that you want to delete only the images associated with the selected Documents.
Natives – indicates that you want to delete only the native files associated with the selected Documents.
ImagesAndNatives – indicates that you want to delete only the images and native files associated with
the selected Documents. (The field values for the documents aren't deleted.)
MassDeleteOptions class
You pass an instance of the MassDeleteOptions class to the MassDelete() or MassDeleteAllObjects methods.
It indicates the type of the object that you want to delete, as well as whether you want to delete all
dependent objects by performing a cascade delete. You can set the Cascade Delete field to true when you
want to delete all child objects and unlink associative objects.
7.2.1.2 MassDeleteAllDocuments() method
You can use the MassDeleteAllDocuments() to delete all Documents and their associated files in the
Workspace. This code sample illustrates how to set the CascadeDelete and ForceDelete fields on the
DocumentMassDeleteOptions object when deleting all Documents and their associated files in a Workspace.
public static bool Using_MassDelete_
ToCascadeAndForceDeleteAllDocumentsInWorkspace(IRSAPIClient proxy)
{
//STEP 1: Set up delete options.
Relativity | Services API Guide - 224
var deleteOptions = new DocumentMassDeleteOptions
(DocumentMassDeleteOptions.DeleteType.AllAssociatedFiles);
deleteOptions.CascadeDelete = true;
deleteOptions.ForceDelete = true;
//STEP 2: Delete all documents.
var result = proxy.MassDeleteAllDocuments(proxy.APIOptions, deleteOptions);
//STEP 3: Check for success.
if (!result.Success)
{
Console.WriteLine(result.Message);
return false;
}
return true;
}
7.2.1.3 MassDeleteDocuments() method
You can use the MassDeleteDocuments() method to delete all files , images, natives, or both the images and
natives associated with a Document. You must use a DeleteType enum to specify the file types that you want
to delete, and then list the ArtifactID of each Document.
This code sample illustrates how to force delete images for the Documents with the specified ArtifactIDs. A
force deletion removes even Documents containing redactions and annotations from the Workspace.
public static bool Using_MassDelete_ToForceDeleteImagesForSpecificDocuments
(IRSAPIClient proxy)
{
//STEP 1: Set up delete options.
var deleteOptions = new DocumentMassDeleteOptions
(DocumentMassDeleteOptions.DeleteType.Images);
deleteOptions.ForceDelete = true;
//STEP 2: Call the mass delete method on the ArtifactIDs you want to delete.
var result =
proxy.MassDeleteDocuments(proxy.APIOptions, deleteOptions, new List<int>
{1033456, 1033457, 1033458});
//STEP 3: Check for success.
if (!result.Success)
{
Console.WriteLine(result.Message);
return false;
}
return true;
}
Relativity | Services API Guide - 225
7.2.1.4 MassDelete() method
The MassDelete() method removes a list of objects from the Workspace. You must specify the ArtifactType of
the objects, and then list the ArtifactID of each object to delete. This code sample illustrates how to perform a
cascade delete on the objects of the specified type.
public static bool Using_MassDelete_
ToCascadeDeleteSpecificObjectsOfSpecificType(IRSAPIClient proxy)
{
//STEP 1: Set up delete options.
var deleteOptions = new MassDeleteOptions(1033451);
deleteOptions.CascadeDelete = true;
//STEP 2: Call mass delete on the ArtifactIDs you want to delete.
var result =
proxy.MassDelete(proxy.APIOptions, deleteOptions, new List<int> {1033456,
1033457, 1033458});
//STEP 3: Check for success.
if (!result.Success)
{
Console.WriteLine(result.Message);
return false;
}
return true;
}
7.2.1.5 MassDeleteAllObjects() method
The MassDeleteAllObjects() method removes all objects of the specified ArtifactType from the Workspace.
This code sample illustrates how to delete all objects of the specified type without using cascade delete, which
means that dependent objects aren't deleted.
public static bool Using_MassDelete_DeleteAllObjectsOfSpecificTypeInWorkspace
(IRSAPIClient proxy)
{
//STEP 1: Set up delete options.
var deleteOptions = new MassDeleteOptions(1033451);
deleteOptions.CascadeDelete = false;
//STEP 2: Call mass delete on the object type.
var result = proxy.MassDeleteAllObjects(proxy.APIOptions, deleteOptions);
//STEP 3: Check for success.
if (!result.Success)
{
Console.WriteLine(result.Message);
Relativity | Services API Guide - 226
return false;
}
return true;
}
7.3 Querying
With the Services API, you can perform searches using Query objects and the Query() method on the
RSAPIClient class. The Query() method takes a Query object, which has Conditions that contain information
about the search that you want to execute. In addition, you can combine Conditions with an operator to
create compound queries.
You can find code samples that illustrate how to query on a specific DTO. For more information, see DTO
reference and code samples on page 81.
7.3.1 Using Query objects
You can use the Query object to describe a search that you want execute. You must indicate the ArtifactType
for the search by using the ArtifactTypeID, ArtifactTypeName, or ArtifactTypeGuid. You can use the Condition
property on a Query to provide an expression that describes the search criteria. A Condition specifies the
name of a Field, a comparison operator (such as EqualTo or GreaterThan), and a value. The list of supported
comparison operators varies by Field data type. You can use the Fields collection on the Query object to
specify Fields that you want returned for each item matching the search criteria.
The Query() method returns a QueryResult object with those items that match the search Condition. The
QueryResult object has the following properties:
n
n
QueryArtifacts - a collection of Artifacts that were found by the query.
QueryToken - when this property has a value, it indicates that the query returned more Artifacts than
number of results specified by the length parameter. See Paging on the next page.
You can sort query results by specifying one or more Fields in the Sorts property on the Query object. This
property is a collection of Sort objects, which takes a Field name, a sort direction (ascending/descending), and
a sort precedence order. (The sort order gives a high precedence to lower numbers.)
Note: A query on multi-reflected Fields returns a list of the requested data type. For example, the value of a
multi-reflected integer field returns a list of integers.
7.3.2 Available Conditions for Querying
You can combine Conditions with the AND or OR operator to create complex queries. The Services API
provides the following classes as condition types:
n
n
n
n
n
n
BooleanCondition
CompositeCondition
DateTimeCondition
DecimalCondition
FileCondition
MultiChoiceCondition
Relativity | Services API Guide - 227
n
n
n
n
n
n
n
n
n
NotCondition
ObjectCondition
ObjectsCondition
SavedSearchCondition
SingleChoiceCondition
TextCondition
UserCondition
ViewCondition
WholeNumberCondition
7.3.3 System Types supported by the Query() method
The Query() method provides the following functionality:
n
n
Searches for all Workspaces in Relativity, and all Fields in a specific Workspace. It supports queries for
Documents and Dynamic Objects based on specified search criteria.
Searches on any Field in the Available Fields or the Selected Fields list available in the view for a system
type. (The view is available through the Relativity web UI.)
This table summarizes the Relativity system types that the Services API supports.
System Types
Application
Batch
Batch Sets
Choice
Client
Group
Markup Sets
User
Object Type
Tab
Folder
Layout
View
Workspace
Error
Field
Relativity Scripts
Saved Searches
Query Support
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes (Artifact Type)
Yes (Only Workspace tab)
Yes
Yes
Yes
Yes
Yes
Yes
7.3.4 Paging
In the Services API, you can perform paging on query results that include Documents or Relativity Dynamic
Objects (RDOs). Paging provides the functionality used to return query results in small subsets.
You can use paging in searches for Documents or RDOs by calling the Query() method and passing a length
parameter, which determines the number of Artifacts returned by the initial page of results. You can set the
Relativity | Services API Guide - 228
length parameter on the QuerySubset() method to return Artifacts on subsequent pages. When the length
parameter is set to 0, the Services API uses the default value defined for the PDVDefaultQueryCacheSize
setting on the Configuration Table. This value is set to 1000, but you can update it as necessary.
The following sample code illustrates how to use paging.
var qry = new DTOs.Query<DTOs.Document>();
qry.Fields = DTOs.FieldValue.AllFields;
var resultsFirst100 = Client.Repositories.Document.Query(qry, 100);
string queryToken = resultsFirst100.QueryToken;
var resultsSecond100 = Client.Repositories.Document.QuerySubset(queryToken,
101, 100);
7.3.4.1 Paging support for system objects
In a Relativity workspace, all objects created by users are RDOs, so paging is supported for these objects. It is
also supported for Batch and Relativity Application, which are workspace system objects that are also RDOs.
Note: You can check the Boolean value assigned to the Dynamic property on an object to determine
whether it is a RDO.
7.3.5 Constraints on the Query() method
The Query() method is subject to the following constraints:
n
n
n
n
n
Queries are limited to only a single object type.
Conditions (that is search criteria) only support comparison against literal values, such as True/False,
"Hello World”, or 10.5. You can't compare one Field’s value against another.
The NOT Condition returns the set of all items that don't meet the negated criteria. This operator uses
set-based logic. For example, you might query for Documents using a numeric relational comparison
operator, such as X < 5. The query for NOT X < 5 returns documents where X is Greater Than or Equal
To 5, and it also returns all documents where X is NULL (that isn't set).
Search criteria are only applied against Fields of the object type being returned. For example, when you
search for Documents, you can only query on Fields that are associated with the Document object
type. You can't query against Fields on Dynamic Objects.
The list of available comparison operators is limited and varies by Field type. This list will be expanded in
future releases.
7.3.6 SavedSearchCondition
You can use the SavedSearchCondition to execute a saved search so that you can review its results. To
execute this query, you need the ArtifactID of the saved search stored in Relativity. You can then execute the
query by using the SavedSearchCondition on the Query() method. You can't combine any other Condition
types with a SavedSearchCondition.
Relativity | Services API Guide - 229
7.3.6.1 SelectedFields directive
You can set the SelectedFields directive when you perform a query with SavedSearchCondition or a
ViewCondition. The SelectedFields directive returns only the Fields displayed on a saved search or view in
Relativity. The following sample code illustrates how to use this directive.
query.Fields = Field.SelectedFields;
You aren't limited to the Fields defined by the saved search or view when using a SavedSearchCondition or a
ViewCondition. Instead, you can specify particular Fields that you want to retrieve, or you can use the AllFields
directive to retrieve all Fields for an ArtifactType, such as View, User, or Document. See Field directives for
DTOs on page 73.
7.3.6.2 Querying for the ArtifactID of a Saved Search
You can query for the ArtifactID of a Saved Search. After the ArtifactID is returned, you can use it to run the
Saved Search. The following code sample illustrates this process.
public static bool Query_For_Saved_SearchID(IRSAPIClient proxy)
{
// STEP 1: If you don't have the ArtifactID of a Saved Search, you can query
to find it.
var query = new Query();
query.ArtifactTypeID = (Int32)ArtifactType.Search;
query.Condition = new TextCondition("Name", TextConditionEnum.Like, "Batch
Search");
QueryResult result = null;
try
{
result = proxy.Query(proxy.APIOptions, query);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
// STEP 2: Save the ArtifactID of the returned saved search.
int searchArtifactID = result.QueryArtifacts[0].ArtifactID;
return true;
}
7.3.6.3 Querying for a Document with a SavedSearchCondition
As illustrated in the following code sample, you can use the SavedSearchCondition to query for a Document
with a saved search ID. A SavedSearchCondition can't be combined with any other Condition types.
Relativity | Services API Guide - 230
using System;
using kCura.Relativity.Client;
using kCura.Relativity.Client.DTOs;
public class A
{
public static void Query_Documents_By_Saved_Search_ID_Using_Repository
(IRSAPIClient proxy)
{
//STEP 1: Create a Query to describe the search you want to run.
DTOs.Query<DTOs.Document> query = new DTOs.Query<DTOs.Document>();
//STEP 2: Set Condition. For this example, Relativity contains a saved
search with an ArtifactID of 1036604.
query.Condition = new SavedSearchCondition(1036604);
//STEP 3: Set the SelectedFields directive to retrieve the fields defined
by the Saved Search.
query.Fields = DTOs.FieldValue.SelectedFields;
//STEP 4: Perform the query.
DTOs.ResultSet<DTOs.Document> docResults =
proxy.Repositories.Document.Query(query);
}
}
7.3.7 Specialized queries with Conditions
You can use Conditions when you want to perform specialized queries on Groups, Users, and Choices, as well
as to create compound queries.
7.3.7.1 Querying for Groups and Users
You can query for Users by building a Condition against the Groups field that takes a list of Group ArtifactIDs.
This Condition returns Users associated with those Groups. In addition, you can query for Groups by building
a Condition against the Users field that takes a list of User ArtifactIDs. This Condition returns Groups
associated with those Users.
7.3.7.2 Querying for Admin Choices by Choice Type
You can use the Query() method to retrieve the Artifact IDs and Names of the Choices associated with a
specific Choice Type. The following Choice type field values are supported when querying by Choice, but they
aren't visible on the front end:
n
n
n
n
n
n
Case Tab
Default Selected File Type
Document Skip
Group Status
Password
Resource Server Status
Relativity | Services API Guide - 231
n
n
n
Resource Server Type
Send new password to
Skip Default Preference
Note: Only text condition is supported on Choice Type field.
Sample Code
//STEP 1: Create a Query to describe the search you want to run.
Query q = new Query();
//STEP 2: Set the ArtifactTypeName to tell Relativity the type of item you want
to search for.
q.ArtifactTypeID = 7;
q.ArtifactTypeName = "Choice";
//STEP 3: Create a Fields list to indicate which fields you want returned.
q.Fields.Add(new Field("Name"));
q.Fields.Add(new Field("Artifact ID"));
q.Condition = new TextCondition("Choice Type", TextConditionEnum.EqualTo,
"Password");
7.3.7.3 Querying with complex compound conditional expressions
Conditions may be combined into logical expressions using a CompositeCondition object. A
CompositeCondition object can be initialized with two Conditions and an Operator (using And or Or). In
addition, multiple CompositeConditions can be nested to create complex expressions, resulting in binary tree
expressions. Since the structure of the tree drives the precedence of operator evaluation, it may significantly
influence the outcome of the query. The following illustration shows how expression C1 AND C2 OR C3 may be
evaluated.
Relativity | Services API Guide - 232
In the first example, the AND composite condition is the root of the Condition tree, while the OR condition
between C2 and C3 is given precedence. In the second example, the AND condition is given precedence and is
evaluated before the OR condition at the root of the Condition tree. The following code sample illustrates how
to use a CompositeCondition in a query.
//Create a TextCondition to specify the search criteria.
TextCondition criteria1 = new TextCondition();
criteria1.Field = "Control Number";
criteria1.Operator = TextConditionEnum.In;
TextCondition criteria2 = new TextCondition();
criteria2.Field = "Group Identifier";
criteria2.Operator = TextConditionEnum.EqualTo;
criteria2.Value = "999";
CompositeCondition composite = new CompositeCondition();
composite.Operator = CompositeConditionEnum.And;
composite.Condition1 = criteria1;
composite.Condition2 = criteria2;
//Set the composite criteria as the Query's Condition.
q.Condition = composite;
7.3.8 ViewCondition
You can use the ViewCondition to execute a view so that you can review its contents. To execute this query,
you need the ArtifactID of the view stored in Relativity. You can then execute the query by using the
ViewCondition on the Query() method. You can't combine any other Condition types with a ViewCondition.
7.3.8.1 Supported Fields for ViewCondition
The Services API supports the following Fields that you can use when querying with Views:
Relativity | Services API Guide - 233
Artifact ID
Available in Object Tab
Created By
Created On
Display Field
Group Definition
Indentation Definition Field
Fields supported for ViewCondition
Indentation Method
Last Modified By
Last Modified On
Name
Object Type
Order
Owner
Relativity Applications
Render Links
Security
View Type
Visible
Visualization Type
7.3.8.2 SelectedFields directive
You can set the SelectedFields directive when you perform a query with SavedSearchCondition or a
ViewCondition. The SelectedFields directive returns only the Fields displayed on a saved search or view in
Relativity. The following sample code illustrates how to use this directive.
query.Fields = Field.SelectedFields;
You aren't limited to the Fields defined by the saved search or view when using a SavedSearchCondition or a
ViewCondition. Instead, you can specify particular Fields that you want to retrieve, or you can use the AllFields
directive to retrieve all Fields for an ArtifactType, such as View, User, or Document. See Field directives for
DTOs on page 73.
7.3.8.3 Querying for the ArtifactID of a View
You can query for the ArtifactID of a View and then set a the ViewCondition with it. When the query executes,
it retrieves Fields from the View as illustrated in the following sample code.
public static bool Query_And_Execute_By_ViewID(IRSAPIClient proxy)
{
//STEP 1: If you don't have the ArtifactID of a View, you can query to find
it.
var query = new DTOs.Query<View>();
query.Condition = new TextCondition(ViewFieldNames.Name,
TextConditionEnum.EqualTo, "All Fields");
DTOs.QueryResultSet<View> result = null;
try
{
result = proxy.Repositories.View.Query(query);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
Relativity | Services API Guide - 234
//Save the ArtifactID of the returned view.
var viewID = result.Results[0].Artifact.ArtifactID;
//STEP 2: Create a new Query to execute the View.
var executeViewQuery = new Query<DTOs.Field>();
//STEP 3: Set a ViewCondition used to pass the ArtifactID of the View.
executeViewQuery.Condition = new ViewCondition(viewID);
executeViewQuery.Fields = FieldValue.AllFields;
//STEP 4: Call the Query method on the Field Repository.
DTOs.QueryResultSet<DTOs.Field> executeViewResult = null;
try
{
executeViewResult = proxy.Repositories.Field.Query(executeViewQuery, 5);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("An error occurred: {0}", ex.Message));
return false;
}
//Check for success.
if (executeViewResult.Success)
{
Console.WriteLine("Retrieved first 5 fields from View 'All Fields':");
foreach (Result<DTOs.Field> field in executeViewResult.Results)
{
Console.WriteLine("Field Name: {0}. Object Type: {1}. Field Type:
{2}.", field.Artifact.Name,
field.Artifact.ObjectType.DescriptorArtifactTypeID,
field.Artifact.FieldTypeID);
}
}
else
{
Console.WriteLine("Error retrieving fields.");
}
return true;
}
7.3.8.4 Searching for Fields with a ViewCondition
As illustrated in the following code sample, you can use the ViewCondition to search for Fields by their view ID.
A ViewCondition can't be combined with any other Condition types.
Relativity | Services API Guide - 235
using System;
using kCura.Relativity.Client;
using kCura.Relativity.Client.DTOs;
public class A
{
public static void Query_Fields_By_Field_View_ID_Using_Repository
(IRSAPIClient proxy)
{
//STEP 1: Create a Query to describe the search you want to run.
DTOs.Query<DTOs.Field> query = new DTOs.Query<DTOs.Field>();
//STEP 2: Set Condition. For this example, Relativity contains a view
with an ArtifactID of 1003689.
query.Condition = new ViewCondition(1003689);
//STEP 3: Set the SelectedFields directive to retrieve the fields defined
by the view.
query.Fields = DTOs.FieldValue.SelectedFields;
//STEP 4: Perform the query.
DTOs.ResultSet<DTOs.Field> docResults = proxy.Repositories.Field.Query
(query);
}
}
8 Troubleshooting the Services API
You can use the following information to identify the causes of Services API errors. It also provides sample
code for writing errors to a log file. For more information about capturing errors, see Writing to the error log
on page 112.
8.1 Common causes of Services API errors
In the Services API, the following conditions result in an error:
n
n
n
Required fields aren't included in a method call
Permission levels are inadequate for the specified operation
Values passed to methods aren't within a predefined range or object type
For many operations, a message indicating an error is returned in the ResultSet collection. Each object in the
collection has a Success/Status field of type Boolean and Message description field. When an error occurs, the
Success/Status field is set to False, and an error description is added to the Message field. The Services API
throws an exception when a communication failure, timeout, or other serious error occurs, which is
transmitted back to the client as a SOAP Fault that can be caught.
Relativity | Services API Guide - 236
8.2 Error occurs when machines in a workgroup attempt to log
in
If you receive an error when machines that are part of a workgroup attempt to log in to the Services API, you
need to synchronize your client and server clocks. (Machines on the domain are already synchronized with
the server.) By default, clock synchronization has a 5 minute range. For information about synchronizing
client and server clocks, see this Microsoft article (http://technet.microsoft.com/en-us/library/cc779145
(WS.10).aspx).
Relativity | Services API Guide - 237
Proprietary Rights
This documentation (“Documentation”) and the software to which it relates (“Software”) belongs to kCura
Corporation and/or kCura’s third party software vendors. kCura grants written license agreements which
contain restrictions. All parties accessing the Documentation or Software must: respect proprietary rights of
kCura and third parties; comply with your organization’s license agreement, including but not limited to
license restrictions on use, copying, modifications, reverse engineering, and derivative products; and refrain
from any misuse or misappropriation of this Documentation or Software in whole or in part. The Software and
Documentation is protected by the Copyright Act of 1976, as amended, and the Software code is protected
by the Illinois Trade Secrets Act. Violations can involve substantial civil liabilities, exemplary damages, and
criminal penalties, including fines and possible imprisonment.
©2013. kCura Corporation. All rights reserved. Relativity® and kCura® are registered trademarks of kCura
Corporation.
Relativity | Services API Guide - 238