Lesson 4 - Validate object changes

Relativity Dynamic Objects (RDOs) are objects you define. You can set properties for them, manage data links to other objects, and incorporate additional features including event handlers and object rules.

Event handlers manipulate or validate data that users see or modify through the Relativity UI.

In this lesson, you will learn how to complete these tasks:

  • Create a Relativity Dynamic Object (RDO) to categorize objects.
  • Implement a Pre Save event handler using the Relativity Visual Studio templates.
  • Use an event handler to apply unique business logic to documents and RDOs.
  • Remotely debug an event handler code running on a virtual machine.
  • Attach event handlers to RDOs and work with GUIDs.
  • Add validation logic to an event handler that uses the MediaWiki API.
  • Query data by making calls to Object Manager API from the event handler.
  • Write testable, scalable and maintainable code for event handlers

Estimated completion time - 2-3 hours

Step 1 - Implement a Pre Save event handler

You can use the Relativity templates for Visual Studio to implement event handlers and other entities. For more information, see Visual Studio templates

You can find general information about event handlers on Best practices for event handlers.

In this lesson, you use the event handler template to implement a Pre Save event handler, which validates the Name field on an Article Category object when it is created and updated. A Pre Save event handler performs this validation before the data is saved to the database.

Use the following steps to implement the event handler:

  1. Download the Relativity templates from Visual Studio Marketplace.
  2. Install the templates in Visual Studio 2019, if you haven't done so.
  3. In Visual Studio, open the HelloWikipedia solution that you created in Lesson 3 - Create a RESTful API.
    You will be using the IWikipediaService class in the solution.
  4. Use the Pre Save event handler template to create a new project called ValidateArticleCategoryEventHandler in the HelloWikipedia solution.

    (Click to expand)

    Add a new project dialog

  5. Enter ValidateArticleCategoryEventHandler in the Project name field.

    (Click to expand)

    Configure your new project dialog

  6. Rename the PreSaveEventHandler.cs file in the project to ValidateArticleCategoryEventHandler.cs.
  7. If Visual Studio doesn't prompt you to update the class name, then rename the PreSaveEventHandler class name to ValidateArticleCategoryEventHandler in the PreSaveEventHandler.cs file.

    (Click to expand)

    Renamed class example

  8. Create a file called Constants.cs in the ValidateArticleCategoryEventHandler project.
  9. Add the GUIDs for ArticleCategory object and the Name field for this object from the application created in Lesson 2 - Build an application without any code by completing these steps:
    • Log in to your Relativity instance.
    • Navigate to the details views of the Hello Wikipedia application.
    • Click Show Component GUIDs in the Application console.
    • Note the GUIDs for the Article Category and the Article Category – Name.

      (Click to expand)

      Application Components list view

  10. Add the following code for the Constants class to the Constants.cs file.
  11. Override the RequiredFields property in the ValidateArticleCategoryEventHandler class by adding a new Field object called Name.
    Copy
    public override FieldCollection RequiredFields
    {
        get
        {
            var retVal = new FieldCollection();
            retVal.Add(new kCura.EventHandler.Field(Constants.CategoryNameGUID));
            return retVal;
        }
    }
  12. Set the CustomAttributes.Description attribute to Validate Article Category Event handler.

    Copy
    [kCura.EventHandler.CustomAttributes.Description("Validate Article Category Event handler")]
  13. Create a new GUID to identify the event handler.

    Use the GUID generator in Visual Studio.

    (Click to expand)

    Create GUID dialog

    Verify that your code is like the following sample:

    Copy
    [System.Runtime.InteropServices.Guid("a4c0eefd-0113-4737-8f2c-4de6b8309c7d")]
  14. Build your event handler project by clicking Build > Build Solution.

Step 2 - Upload the event handler assembly to Relativity

To use the event handler, you must upload it to Relativity and associate it with an application.

Use the following steps to upload your event handler assembly:

  1. Log in to the Relativity instance on your DevVM.
  2. Locate My First Workspace created in Lesson 2 - Build an application without any code.
  3. Navigate to the Resource File tab and click New Resource File.
  4. In the Resource File field, click Browse to select the ValidateArticleCategoryEventHandler.dll from the directory where you built the project. See Step 1 - Implement a Pre Save event handler.
  5. In the Application field, click ellipsis button to select Hello Wikipedia, which is the application created in Lesson 2 - Build an application without any code.
    This action links your event handler assembly to the Hello Wikipedia application.
  6. Click Save.
  7. Upload the ValidateArticleCategoryEventHandler.pdb by repeating steps 4-6.
    Uploading the .pdb file to facilitates remote debugging the event handler.

    (Click to expand)

    Application & Scripts tab

  8. In your workspace, locate the Object Type tab.
  9. Navigate to the details view of the Article Category object type.
  10. To attach the event handler to your new object type, click New on the Event Handlers associative list.
  11. Select your event handler in the dialog box.

    (Click to expand)

    Select Event Handler dialog

    In the next section, you run your event handler.

Step 3 - Remotely debugging an event handler

After adding your event handler assembly to Relativity, you can now remotely debug it.

Note: Debugging an event handler is slightly different than debugging a Kepler service. Be sure to review the following debugging steps. For information about Kepler services, see Lesson 3 - Create a RESTful API.

Use the following steps to remotely debug your event handler:

  1. Open your Visual Studio project.
  2. Add a breakpoint in the Execute() method of your code.

    (Click to expand)

    Breakpoint in code

  3. Launch Remote Debugger tool on your DevVM.
  4. On the Debug menu, click Attach to Process.
    The Attach to Process window appears.
  5. Select all w3wp processes.

    (Click to expand)

    Attach debugger to processes

  6. Set a breakpoint on the first line of the Execute() method.

    Note: When you debug for the first time and attach to the w3p processes to debug the event handler, the breakpoint may indicate that the symbols haven't loaded. This behavior is expected because the symbols load the first time the event is triggered.

    (Click to expand)

    Breakpoint in Execute() method

  7. To trigger the breakpoint, navigate to the Article Category tab in your workspace, and click New Article Category.
  8. Enter Computer Science in the Name field. Clear the checkboxes so they are disabled, and click Save.
    These steps should trigger the breakpoint in Visual Studio.

Step 4 - Add validation logic to an event handler

You can update your event handler to validate whether a newly created or updated article category is valid in Wikipedia. Use the GetCategoriesByPrefixAsync() method that was implemented in Lesson 3 - Create a RESTful API for this purpose.

Use the following steps to add validation logic:

  1. Add the following project references to the ValidateArticleCategoryEventHandler project by right-clicking on References > Add Reference >Projects tab:
    • WikipediaKepler.Interfaces

    (Click to expand)

    Reference Manager

  2. Verify that the references display in the Solution Explorer:

    (Click to expand)

    Solution Explorer

  3. Add a new class named ValidateArticleCategoryEventHandlerJob to the ValidateArticleCategoryEventHandler project and make sure that it's public.

    (Click to expand)

    New class in Visual Studio

  4. Update the ValidateArticleCategoryEventHandlerJob class by following statements:
    Copy
    using kCura.EventHandler; 
    using Relativity.API; 
    using Relativity.Kepler.Logging; 
    using Relativity.Services.Objects; 
    using Relativity.Services.Objects.DataContracts; 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Net; 
    using System.Text; 
    using System.Threading.Tasks; 
    using WikipediaKepler.Interfaces.WikipediaManagement.v1;
  5. Update the ValidateArticleCategoryEventHandlerJob class by adding the following properties and the constructor:
    Copy
    ILog logger;
    IWikipediaService wikiService;
    IObjectManager objectManager;
    IEHHelper helper;
    Artifact activeArtifact;

    public ValidateArticleCategoryEventHandlerJob(Artifact activeArtifact, ILog logger, IWikipediaService wikiService, IObjectManager objectManager, IEHHelper helper)
    {
        this.logger = logger;
        this.wikiService = wikiService;
        this.objectManager = objectManager;
        this.helper = helper;
        this.activeArtifact = activeArtifact;
    }
  6. Update the ValidateArticleCategoryEventHandlerJob class by adding the EnsureCategoryExistsInWiki() and ExecuteAsync() methods
  7. Update references in ValidateArticleCategoryEventHandler class as follows:
  8. Add the following property and constructor to the ValidateArticleCategoryEventHandler class.
    Copy
    ILog Logger;

    public ValidateArticleCategoryEventHandler()
    {
        this.Logger = Log.Logger;
    }
  9. Add the following code to modify Execute() method in ValidateArticleCategoryEventHandler class:
    Copy
    public override Response Execute()
    {
        var retVal = new Response();

        try
        {
            var serviceManager = Helper.GetServicesManager();
            Logger.LogVerbose($"Start '{nameof(Execute)}' method");
            using (var objectManager = serviceManager.CreateProxy<IObjectManager>(ExecutionIdentity.System))
            using (var wikiService = serviceManager.CreateProxy<IWikipediaService>(ExecutionIdentity.System))
            {
                var job = new ValidateArticleCategoryEventHandlerJob(this.ActiveArtifact, this.Logger, wikiService, objectManager, this.Helper);
                retVal = Task.Run(async () => await job.ExecuteAsync()).ConfigureAwait(false).GetAwaiter().GetResult();
            }

            Logger.LogDebug($"{nameof(retVal)}: {retVal}", null, retVal);
        }
        catch (Exception ex)
        {
            retVal.Success = false;
            retVal.Message = $"{ex}";

            Logger.LogError($"An error occured in '{nameof(Execute)}' method", ex, ex);
        }
        finally
        {
            Logger.LogVerbose($"End '{nameof(Execute)}' method");
        }

        return retVal;
    }
  10. Try out the validation by creating a new Article Category with the name SciFi movie.
    The red error message prevents you from saving the Article Category. Try editing one of the existing categories and notice the same error message.

    (Click to expand)

    Validation message

Step 5 - Make service calls from the event handler

You can make calls to Relativity APIs from your event handler. For example, you can use the Object Manager API to query for duplicate article categories being added to the same workspace. You can also use the services exposed on this API to facilitate working with Document objects and RDOs. For more information, see Object Manager (.NET).

Use the following steps to make service calls from the event handler:

  1. To detect whether the Article Category exists in Wikipedia, call the Kepler service created in Lesson 3 - Create a RESTful API.

    Update the EnsureCategoryExistsInWiki() method in the ValidateArticleCategoryEventHandlerJob class as follows:

    Copy
    public async Task<bool> EnsureCategoryExistsInWiki(IWikipediaService wikiService, string category) 

         var foundCategories = await wikiService.GetCategoriesByPrefixAsync(category); 
         return foundCategories.Exists(s => s.Title == category); 
    }
  2. To detect duplicate article categories, update the EnsureCategoryWithThatNameExists() method in the ValidateArticleCategoryEventHandlerJob class as follows:
    Copy
    public async Task<bool> EnsureCategoryWithThatNameExists(string categoryName, IObjectManager objectManager, IEHHelper helper)
    {
        var currentWorkspaceArtifactID = helper.GetActiveCaseID();
        var queryRequest = new QueryRequest
        {
            ObjectType = new ObjectTypeRef { Guid = Constants.ArticleCategoryGUID },
            Fields = new List<FieldRef> { new FieldRef { Guid = Constants.CategoryNameGUID, Name = "Name" } },
            Condition = $"('Name' == '{categoryName}')",
        };

        var categoryObjects = await objectManager.QuerySlimAsync(currentWorkspaceArtifactID, queryRequest, 1, 1000);

        //Identify duplicates for all records except for the current record
        bool doesDuplicateExists = categoryObjects.Objects.Count > 0
           && categoryObjects.Objects.All(x => x.ArtifactID != activeArtifact.ArtifactID);
        return doesDuplicateExists;
    }
  3. Click Build > Build Solution in Visual Studio to verify that the code is building successfully.
  4. Upload the updated .dll and .pdb files for the event handler to test the validation code used when creating or editing an Article Category.
    Use the instructions in Step 2 - Upload the event handler assembly to Relativity.
  5. Create a new Article Category with name SciFi movie after .dll and .pdb files for the event handler are updated.

    This update should throw a validation exception because SciFi movie isn't a valid category in Wikipedia.

    (Click to expand)

    Validation error for article category

Step 6 - Write unit tests

In this section, you write unit tests to verify that your code is working properly and to prevent breaking this logic in the future.

Use the following steps to write unit tests:

  1. Open the HelloWikipedia solution in Visual Studio.
  2. Use the Unit Test Project (.NET Framework) template to create a new project called ValidateArticleCategoryEventHandler.Tests.

    (Click to expand)

    Unit Test Project template

  3. Enter ValidateArticleCategoryEventHandler.Tests in the Project name field.

    (Click to expand)

    Configure your new project dialog

  4. Add the following project references to the ValidateArticleCategoryEventHandlerJobTests project by right-clicking on References > Add Reference >Projects tab:
    • WikipediaKepler.Interfaces
    • ValidateArticleCategoryEventHandler
  5. From the NuGet Package Manager in Visual Studio, uninstall the MSTest.TestAdapter and MSTest.TestFramework NuGet packages from the ValidateArticleCategoryEventHandler.Tests project.
  6. From the NuGet Package Manager in Visual Studio, install the following NuGet packaged in your test project:
    • NUnit 3.12.0
    • Moq 4.14.5 - use this package to mock the objects in your project.
    • Relativity.EventHandler 11.2.172.14
  7. Rename the UnitTest1.cs file in the project to ValidateArticleCategoryEventHandlerJobTests.cs.
  8. Rename the UnitTest1 class in the ValidateArticleCategoryEventHandlerJobTests.cs file to ValidateArticleCategoryEventHandlerJobTests.

    (Click to expand)

    Rename test code class

  9. Add the following code to update the using statements in the ValidateArticleCategoryEventHandlerJobTests.cs file.
    Copy
    using Moq; 
    using NUnit.Framework; 
    using Relativity.API; 
    using Relativity.Kepler.Logging; 
    using Relativity.Services.Objects; 
    using Relativity.Services.Objects.DataContracts; 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Threading.Tasks; 
    using WikipediaKepler.Interfaces.WikipediaManagement.v1; 
    using WikipediaKepler.Interfaces.WikipediaManagement.v1.Models;
  10. Update the class attribute from [TestClass] to [TestFixture].
  11. Delete the TestMethod1() method from the ValidateArticleCategoryEventHandlerJobTests class.

    (Click to expand)

    TextFixture code

  12. Add the following properties to the ValidateArticleCategoryEventHandlerJobTests.cs class:
    Copy
    IWikipediaService wikiService; 
    ILog logger; 
    IEHHelper helper; 
    kCura.EventHandler.Artifact activeArtifact;

    List<string> wikiCategories = new List<string> { "Category 1", "Category 2", "Category 4" }; 
    List<string> dbCategories = new List<string> { "Category 1", "Category 2", "Category 3" };
  13. Add the SetUp() method to the new class as follows:
    Copy
    [SetUp]

    public void SetUp()
    {
      var wiki = new Mock < IWikipediaService > ();
      wiki.Setup(s =>s.GetCategoriesByPrefixAsync(It.IsAny < string > ())).Returns(Task.FromResult(
      new List < CategoryResponseModel > (wikiCategories.Select(s =>new CategoryResponseModel {
        Title = s
      }))));

      wikiService = wiki.Object;
      logger = new Mock < ILog > ().Object;
      helper = new Mock < IEHHelper > ().Object;
      activeArtifact = new kCura.EventHandler.Artifact(0, null, 0, "", true, new kCura.EventHandler.FieldCollection());
    }
  14. Add the ValidateArticleCategory_TestExecuteLogic() method and using the TestCase attribute, add different test cases.
  15. Build the test project.
  16. In Visual Studio, click Test > Run All Tests.
  17. Verify that all the tests passed.

    After confirming that the validation logic works as expected, you can export the application. It contains the event handler attached to the Article Category object type, and it runs validation logic when a user saves an Article Category object.