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

Workspace

In Relativity, workspaces are secure data repositories for storing documents and applications. For additional information, see Workspaces on the Relativity Documentation site.

The Services API supports create, read, update, delete, and query operations on a Workspace DTO.

Note: You can also read, update, and delete workspaces using the single-artifact access methods common to all Relativity DTOs. For more information, see Single-artifact access.

This page contains the following information:

Create a Workspace

To create a workspace, use the CreateAsync() method on the Workspace Repository. The method takes a Workspace Template ID and a Workspace DTO.

    Notes:
  • When interacting with workspaces, you must specify -1 as the WorkspaceID in the APIOptions object:
    proxy.APIOptions.WorkspaceID = -1;
  • If the specified workspace template includes a server that is not available in your Relativity environment, you must either use a different server ID or a different template.

Use the Workspace DTO to set the Name property of the new workspace and any optional properties, as shown in the example below. If you don't set any of the properties, the system uses the values from the template. The CreateAsync() method returns a ProcessOperationResult object and the Success property, which indicates whether the operation was successfully started. The Success property does not indicate whether it completed successfully.

To check the progress of the operation, you can either use the MonitorProcessState() method or GetProcessState(). Both methods take the APIOptions and the ProcessID. Use the MonitorProcessState() to asynchronously capture events that indicate the progress of the Workspace creation, as the sample demonstrates. Inspect the ProcessInformation object with the events, which have information about the state of the process.

As an alternative to using MonitorProcessState(), synchronously call GetProcessState to check the state of the process a single time.

Retrieve the new ID of the new workspace from the ProcessInformation object by inspecting the first item in the OperationArtifactIDs property, when the Workspace creation process completes. The example also demonstrates this. You can retrieve the final ProcessInformation object by either handling the ProcessComplete event when using MonitorProcessState(), or calling GetProcessState once the operation finishes.

The following code sample illustrates how to create a workspace with the name "Test Create Workspace" and a set of optional properties. Note the asynchronous process status monitoring and event handling logic.

Note: Starting with 9.5.219.30, the DefaultFileLocation property contains a ResoureServer object. You can set it by specifying the resource server ArtifactID as the choice ArtifactID.

Note: For more information about the starter template, see Starter template on the Relativity Server2021 Documentation site.

public bool Create_Workspace(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicated by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Query for the starter template
    int? templateArtifactID = null;
    kCura.Relativity.Client.DTOs.Query<Client.DTOs.Workspace> query = new kCura.Relativity.Client.DTOs.Query<Client.DTOs.Workspace>();
    query.Condition = new kCura.Relativity.Client.TextCondition(kCura.Relativity.Client.DTOs.FieldFieldNames.Name, kCura.Relativity.Client.TextConditionEnum.EqualTo, Data.Constants.WORKSPACE_TEMPLATE_NAME);
    query.Fields = kCura.Relativity.Client.DTOs.FieldValue.AllFields;
    kCura.Relativity.Client.DTOs.QueryResultSet<kCura.Relativity.Client.DTOs.Workspace> resultSet = proxy.Repositories.Workspace.Query(query, 0);
    if (resultSet.Success)
    {
        templateArtifactID = resultSet.Results.FirstOrDefault().Artifact.ArtifactID;
    }
    else
    {
        logger.LogError(resultSet.Message);
        return false;
    }

    //Create a Workspace DTO with the data to use to create the workspace.  
    var workspaceDTO = new kCura.Relativity.Client.DTOs.Workspace();

    //Set primary fields
    //NOTE: At a minimum, the name of the workspace is required. Any values not set 
    //through the DTO will be used from the template workspace that is set in the CreateAsync method call.
    //NOTE: The name of the sample data is being set to a random string so that sample data can be debugged
    //and never causes collisions. You can set this to any string that you want
    workspaceDTO.Name = string.Format("API {0}", Guid.NewGuid());

    //Set secondary fields if you want to override the template
    //workspaceDTO.MatterID = 101010;
    //workspaceDTO.ResourcePoolID = 135790;
    //workspaceDTO.Status = new Client.DTOs.Choice(987654); //or use the Guid of a Choice
    //workspaceDTO.DownloadHandlerApplicationPath = "Relativity.Distributed";
    //workspaceDTO.DefaultFileLocation = new Client.DTOs.Choice(787878); // 787878 = ResourceServer's ArtifactID or use the ArtifactID/GUID of a Choice
    //workspaceDTO.SQLFullTextLanguageCodeID = 1033;  //from sql server sys.fulltext_languages

    //NOTE: If the server ID of your template workspace does not exist in your instance of Relativity, you need to set it
    //workspaceDTO.ServerID = 123456;

    //Create a ProcessOperationResult to track the process of the operation and execute the Create
    kCura.Relativity.Client.ProcessOperationResult result = new kCura.Relativity.Client.ProcessOperationResult();
    //Create a ProcessInformation to return the status of the Workspace creation process.
    kCura.Relativity.Client.ProcessInformation processInfo;
    try
    {
        //Call CreateAsync passing the templateID and workspaceDTO. 
        //This returns a ProcessOperationResult with a Success property and a ProcessID property.
        //NOTE: The Success property indicates the success of starting the create process, 
        //not the success of the actual workspace creation.
        result = proxy.Repositories.Workspace.CreateAsync(templateArtifactID.Value, workspaceDTO);

    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Unhandled Exception");
        return false;
    }

    //Check for success for triggering the Workspace Creation Process
    if (result.Success)
    {
        //There are two ways to monitor the progress of creating a Workspace.  Either use MonitorProcessState which will create a polling process and return events
        //with the status, or call GetProcessState to return the current status.

        //Below is an example of using the progress events with MonitorProcessState and creating a task that will block until the process is finished.

        //Wire up the Events that are thrown by the Workspace Creation process, and call MonitorProcessState to create a 
        //polling process that will capture the events.
        proxy.ProcessComplete += HandleProcessCompleteEvent;
        proxy.ProcessProgress += HandleProcessProgressEvent;
        proxy.ProcessCompleteWithError += HandleProcessCompleteWithErrorEvent;
        proxy.ProcessFailure += HandleProcessFailureEvent;

        proxy.MonitorProcessState(proxy.APIOptions, result.ProcessID);

        //Create a task that we can use to wait on the Events until a Completed, Error, or  Failure event is received.
        //This will block until SetResult is called from one of the Completed or Failure events.
        //this method.
        Task<kCura.Relativity.Client.ProcessInformation> task = _tcs.Task;
        processInfo = (kCura.Relativity.Client.ProcessInformation)task.Result;

        //Disconnect from the Events
        proxy.ProcessComplete -= HandleProcessCompleteEvent;
        proxy.ProcessProgress -= HandleProcessProgressEvent;
        proxy.ProcessCompleteWithError -= HandleProcessCompleteWithErrorEvent;
        proxy.ProcessFailure -= HandleProcessFailureEvent;

        //Alternatively to using MonitorProcessState, you can return the current process state by calling 
        //GetProcessState and passing the process id of the operation.
        kCura.Relativity.Client.ProcessInformation processState = proxy.GetProcessState(proxy.APIOptions, result.ProcessID);
        logger.LogDebug("Process Status: {Status}", processState.Status);

        while (processState.State != ProcessStateValue.Completed)
        {
            System.Threading.Thread.Sleep(1000);
            processState = proxy.GetProcessState(proxy.APIOptions, result.ProcessID);
        }
        int? workspaceId = processState.OperationArtifactIDs.FirstOrDefault();

        DataHelper.DeleteData[Data.Constants.WORKSPACE_ID_LIST].Add(workspaceId.Value);
    }

    return true;
}

private void HandleProcessProgressEvent(object sender, kCura.Relativity.Client.ProcessProgressEventArgs eventArgs)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    kCura.Relativity.Client.ProcessInformation info = eventArgs.ProcessInformation;

    logger.LogDebug("Completed {OperationsCompleted} of {TotalOperations} Operations", info.OperationsCompleted, info.TotalOperations);
}

private void HandleProcessCompleteEvent(object sender, kCura.Relativity.Client.ProcessCompleteEventArgs eventArgs)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    kCura.Relativity.Client.ProcessInformation info = eventArgs.ProcessInformation;

    logger.LogDebug("Workspace created: {OperationArtifactIDs}", info.OperationArtifactIDs.FirstOrDefault());

    _tcs.SetResult(eventArgs.ProcessInformation);
}

private void HandleProcessCompleteWithErrorEvent(object sender, kCura.Relativity.Client.ProcessCompleteWithErrorEventArgs eventArgs)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    kCura.Relativity.Client.ProcessInformation info = eventArgs.ProcessInformation;

    logger.LogDebug("Workspace created with error: {OperationArtifactIDs}, {Message}", info.OperationArtifactIDs.FirstOrDefault(), info.Message);

    _tcs.SetResult(eventArgs.ProcessInformation);
}

private void HandleProcessFailureEvent(object sender, kCura.Relativity.Client.ProcessFailureEventArgs eventArgs)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    kCura.Relativity.Client.ProcessInformation info = eventArgs.ProcessInformation;

    logger.LogDebug("Workspace creation failed: {Message}", info.Message);

    _tcs.SetResult(eventArgs.ProcessInformation);
}

Read a Workspace

To read Field values on a single Workspace, use the ReadSingle() method on the Workspace repository as the code sample illustrates.

public bool Read_Workspace_Single(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Perform the read in a try/catch in case it fails
    try
    {
        //NOTE: SampleWorkspace_ID is sample data created for this example
        kCura.Relativity.Client.DTOs.Workspace workspace = proxy.Repositories.Workspace.ReadSingle(this.SampleWorkspace_ID);

        string name = workspace.Name;
    }
    catch (APIException ex)
    {
        //Exceptions are returned as an APIException
        logger.LogError(ex, "Unhandled Exception");
        return false;
    }
    return true;
}

You can also use the Read() method to read multiple Workspace objects:

public bool Read_Workspace_Batch(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Create a list of workspaces to Read
    List<kCura.Relativity.Client.DTOs.Workspace> workspacesToRead = new List<Client.DTOs.Workspace>();

    //Create and add one or more workspaces to the list
    //NOTE: SampleWorkspace_ID is sample data created for this example
    kCura.Relativity.Client.DTOs.Workspace workspaceToRead = new kCura.Relativity.Client.DTOs.Workspace(this.SampleWorkspace_ID);
    workspaceToRead.Fields = Client.DTOs.FieldValue.AllFields;
    workspacesToRead.Add(workspaceToRead);

    //Create ResultSet to store Results 
    kCura.Relativity.Client.DTOs.ResultSet<kCura.Relativity.Client.DTOs.Workspace> resultSet = new kCura.Relativity.Client.DTOs.ResultSet<Client.DTOs.Workspace>();

    //Perform the Read operation in a try/catch in case it fails
    try
    {
        resultSet = proxy.Repositories.Workspace.Read(workspacesToRead);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Unhandled Exception");
        return false;
    }

    // Check for success
    if (resultSet.Success)
    {
        //Save the Workspace from the results
        kCura.Relativity.Client.DTOs.Workspace workspaceDTO = resultSet.Results.FirstOrDefault().Artifact;

        //Read some basic Fields from the workspace
        int artifactID = workspaceDTO.ArtifactID;
        string textIdentifier = workspaceDTO.TextIdentifier;
    }
    else
    {
        logger.LogError(resultSet.Message);
        return false;
    }

    return true;
}

Update a Workspace

Update a Workspace using the Update() method on the Workspace repository, as the code example illustrates. Instantiate the DTO using an Artifact ID or GUID, set the properties on the DTO, and then pass the DTO to the Update method on the Workspace repository.

Note: The Services API does not support setting production restrictions on a workspace. For additional information, see Adding and editing production restrictions on the Relativity Server2021 Documentation site.

public bool Update_Workspace_Single(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy) { //Set the ForContext for the method. kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false); //Set the workspace ID //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1 proxy.APIOptions.WorkspaceID = -1; //Read the workspace to update //NOTE: SampleWorkspace_ID is sample data created for this example //NOTE: The workspace can also be created manually, rather than reading it kCura.Relativity.Client.DTOs.Workspace workspaceToUpdate = proxy.Repositories.Workspace.ReadSingle(this.SampleWorkspace_ID); //Update the fields on the Workspace DTO //The name of the sample data is being set to a random string so that sample data can be debugged //and never causes collisions. You can set this to the any string that you want workspaceToUpdate.Name = string.Format("API Upd. {0}", Guid.NewGuid()); //Update the workspace in a try/catch in case it fails try { proxy.Repositories.Workspace.UpdateSingle(workspaceToUpdate); } catch (Exception ex) { logger.LogError(ex, "Unhandled Exception"); return false; } return true; }

Delete a Workspace

To delete a Workspace, instantiate a DTO using an Aritfact ID or GUID, and then pass the DTO to the Delete() method on the Workspace Repository.

public bool Delete_Workspace_Single(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{


    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Create a workspace to delete
    int? workspaceToDeleteID = null;
    int? rootFolderID = null;
    bool success = Client.SamplesLibrary.Data.WorkspaceHelper.TryCreate(proxy, out workspaceToDeleteID, Data.Constants.WORKSPACE_TEMPLATE_NAME, out rootFolderID);
    if (success)
    {
        try
        {
            //Delete the workspace
            //NOTE: This will mark the workspace for deletion.  Similar to the Relativity interface, the SQL Server
            //Database will not be removed until the Case Manager agent executes.
            proxy.Repositories.Workspace.DeleteSingle(workspaceToDeleteID.Value);
        }
        catch (APIException ex)
        {
            //Exceptions are returned as an APIException
            logger.LogError(ex, "Unhandled Exception");
            return false;
        }
    }
    else
    {
        logger.LogError("Delete failed");
        return false;
    }

    return true;
}

Query for a Workspace

In addition to read, Workspace DTOs support the query operation. For detailed information about querying Relativity objects, see Search Relativity.

This code sample illustrates how to set the query condition using the workspace Artifact ID, call the Query method on the Workspace repository, and iterate through the result set.

public bool Query_Workspace_ArtifactID(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Define the query
    //NOTE: SampleField_SingleChoice_ID is sample data created for this example
    kCura.Relativity.Client.DTOs.Query<kCura.Relativity.Client.DTOs.Workspace> query = new kCura.Relativity.Client.DTOs.Query<kCura.Relativity.Client.DTOs.Workspace>();
    query.Condition = new kCura.Relativity.Client.WholeNumberCondition(kCura.Relativity.Client.DTOs.ArtifactQueryFieldNames.ArtifactID, kCura.Relativity.Client.NumericConditionEnum.EqualTo, this.SampleWorkspace_ID);

    //Request the fields you want from Workspace
    //NOTE: A best practice is to specify fields rather than using AllFields. This keeps
    //the data returned predicable in large environments with many fields 
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue(kCura.Relativity.Client.DTOs.WorkspaceFieldNames.TextIdentifier));
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue("Name"));
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue("Status"));

    //Create QueryResultSet and query for the workspaces in a try/catch
    kCura.Relativity.Client.DTOs.QueryResultSet<Client.DTOs.Workspace> resultSet = new kCura.Relativity.Client.DTOs.QueryResultSet<kCura.Relativity.Client.DTOs.Workspace>();
    try
    {
        resultSet = proxy.Repositories.Workspace.Query(query, 0);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Unhandled Exception");
        return false;
    }

    //Check for success
    if (resultSet.Success)
    {
        logger.LogDebug("Number of Workspaces returned: {TotalCount}", resultSet.TotalCount);
        return true;
    }
    else
    {
        logger.LogError(resultSet.Message);
        return false;
    }
}

This code sample illustrates how to set the query TextCondition using the workspace name:


public bool Query_Workspace_Name(Client.SamplesLibrary.Helper.IHelper helper, IRSAPIClient proxy)
{
    //Set the ForContext for the method.
    kCura.Relativity.Client.SamplesLibrary.Logging.ISampleLogger logger = _logger.ForContext("MethodName", new StackFrame(0).GetMethod().Name, false);

    //Set the workspace ID
    //NOTE: For admin objects, the EDDS database is indicatd by an ID of -1
    proxy.APIOptions.WorkspaceID = -1;

    //Define the query
    //NOTE: SampleField_SingleChoice_ID is sample data created for this example
    kCura.Relativity.Client.DTOs.Query<kCura.Relativity.Client.DTOs.Workspace> query = new kCura.Relativity.Client.DTOs.Query<Client.DTOs.Workspace>();
    query.Condition = new kCura.Relativity.Client.TextCondition(kCura.Relativity.Client.DTOs.WorkspaceFieldNames.Name, kCura.Relativity.Client.TextConditionEnum.EqualTo, Data.Constants.WORKSPACE_TEMPLATE_NAME);

    //Request the fields you want from Workspace
    //NOTE: A best practice is to specify fields rather than using AllFields. This keeps
    //the data returned predicable in large environments with many fields 
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue(kCura.Relativity.Client.DTOs.WorkspaceFieldNames.TextIdentifier));
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue("Name"));
    query.Fields.Add(new kCura.Relativity.Client.DTOs.FieldValue("Status"));

    //Create QueryResultSet and query for the workspaces in a try/catch
    kCura.Relativity.Client.DTOs.QueryResultSet<kCura.Relativity.Client.DTOs.Workspace> resultSet = new kCura.Relativity.Client.DTOs.QueryResultSet<kCura.Relativity.Client.DTOs.Workspace>();
    try
    {
        resultSet = proxy.Repositories.Workspace.Query(query, 0);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Unhandled Exception");
        return false;
    }

    //Check for success
    if (resultSet.Success)
    {
        logger.LogDebug("Number of Workspaces returned: {TotalCount}", resultSet.TotalCount);
        return true;
    }
    else
    {
        logger.LogError(resultSet.Message);
        return false;
    }
}

Multi-tenancy

With the introduction of support for multi-tenancy, Client becomes the parent of the Workspace object. Subsequently the ParentArtifact property is set to the Client associated with the Workspace based on the Matter.