REQUEST A DEMO

Use Dovetail SDK in .Net

One of our customers ran into a roadblock trying to migrate custom projects over to Dovetail SDK. The primary issues were getting the right references set up for a project, then creating and referencing the database objects using APIs in the various Dovetail SDK toolkits.

I was asked to put together a sample project as a guide for getting a project underway, so I wanted to document that process here and have this also serve as a guide for future projects.

In Visual Studio, I created a new Console Application to hold the example, and added a few references to the project.

The core of the project is the Dovetail SDK, so the first reference is to fcSDK.dll. This DLL has the core of what the project needs to create the required application and session objects, and provides to tools to access the database. Dovetail SDK also needs to access to the API library that has been created, so a reference to FChoice.Toolkits.Clarify.dll is required. With proper licenses installed, this DLL provides access to any of the toolkits.

For this example, I wanted to validate that the examples I created worked as expected, so my intention was to build an integration test suite that performs all of the work. Not only do tests help document the concepts and procedures involved, but also provide positive reinforcement and validation that the examples work as designed. As a result, I added a reference to nunit.framework.dll to make the test framework available.

For all three of these references, I set each one of the to be copied locally so my build process would include everything that was required to execute the application.

For the code, I created an Examples folder to hold the code. For the database connection I added a configuration file to the project, in the Examples namespace. This app.config file is used by Dovetail SDK for the connection string.

?xml version=1.0 encoding=utf-8 ?
configuration
   appSettings
      add key=fchoice.dbtype value=MSSQL /
      add key=fchoice.connectionstring value=Data Source=server; Initial Catalog=database; User Id=username; Password=password; /
      add key=connect_string_params value=/
      add key=fchoice.nocachefile value=true/
      add key=fchoice.clarify.ignoredatetimemilliseconds value=true/
   /appSettings
/configuration

Everything is now in place to make the examples work, so it’s time to add the code. I added an empty class definition, and named it LogisticsToolkitExample.cs. A test project runs in a test fixture, so that is the main component of the class.

using NUnit.Framework; 

namespace Example.Examples{    
   [TestFixture]    
   public class LogisticsToolkitExample 
   {    
   }
}

A class that is used as a test fixture has a few restrictions:

  • It must be a publicly exported type or NUnit will not see it.
  • It must have a default constructor or NUnit will not be able to construct it.
  • The constructor should not have any side effects, since NUnit may construct the class multiple times in the course of a session.

The application, session, and toolkit objects only need to be initialized once for the test fixture, so I added TestFixtureSetup and TestFixtureTeardown methods to the class next. The Setup area will contain a single set of functions that are performed once prior to executing any of the tests in the fixture, and the Teardown method will get performed once after all of the tests are completed.

        [TestFixtureSetUp]        
        public void TestFixtureSetUp()        
        {        
        }         
        
        [TestFixtureTearDown]        
        public void TestFixtureTearDown()        
        {        
        }
The application and session objects are the first things to add in the setup method, since they provide both validation and database access. I also added a private ClarifySession variable to hold the session object for reference in the tests.
[TestFixtureSetUp]        
public void TestFixtureSetUp()        
{            
   ClarifyApplication.Initialize();            
   _clarifySession = ClarifyApplication.Instance.CreateSession("sa", "sa", ClarifyLoginType.User);        
}

Adding access to the Toolkits is the next step, and those are also set up as private variables that are initialized in the Setup method.

[TestFixtureSetUp]        
public void TestFixtureSetUp()        
{            
   ClarifyApplication.Initialize();            
   _clarifySession = ClarifyApplication.Instance.CreateSession("sa", "sa", ClarifyLoginType.User);             

   _logisticsToolkit = new LogisticsToolkit(_clarifySession);            
   _interfacesToolkit = new InterfacesToolkit(_clarifySession);        
}

This is all that is required in the Setup method to make things work, and the session object needs to be closed after the tests are completed. That is done in the Teardown method, so the code is added there.

[TestFixtureTearDown]        
public void TestFixtureTearDown()        
{            
   _clarifySession.CloseSession();        
}

Now everything is in place to actually do some work, so it is time to write some code. The customer wanted help with Part Requests. A good test project is not data dependent, so some private methods to add some data are needed here. These also serve as good examples of using other APIs, so they serve multiple purposes in the project. With the methods below we can find an existing contact, create some sample part data, and add Part Request headers and detail.

private void CreatePartRequestHeader()
{
    //create a part request header using the Logistics Toolkit API
    var setupHdr = new CreatePartRequestHeaderSetup(_firstName, _lastName, _phone, _workingSiteIdNum);
    var partRequestHeader = _logisticsToolkit.CreatePartRequestHeader(setupHdr);
     _partRequestHeaderIDNum = partRequestHeader.IDNum;
}

private void CreatePartRequestDetail()
{
    //create a part request detail using the Logistics Toolkit API
    var setupDet = new CreatePartRequestDetailSetup(_partRequestHeaderIDNum, _partNum, _domain, _modLevel, _serialNumber);
    var partRequestDetail = _logisticsToolkit.CreatePartRequestDetail(setupDet);
     _partRequestDetailIDNum = partRequestDetail.IDNum;
}

private void GetContact()
{
    //get a contact from the database using generics
    var clarifyDataSet = new ClarifyDataSet(_clarifySession);
    var contactGeneric = clarifyDataSet.CreateGeneric("rol_contct");
    contactGeneric.AppendFilter("objid", NumberOps.MoreThan, 0);
    contactGeneric.MaximumRows = 1;
    contactGeneric.Query();
     var contact = contactGeneric.Rows[0];
    _firstName = Convert.ToString(contact["first_name"]);
    _lastName = Convert.ToString(contact["last_name"]);
    _phone = Convert.ToString(contact["phone"]);
    _workingSiteIdNum = Convert.ToString(contact["site_id"]);
}

private void CreatePartData()
{
    //create a part and revision using the Interface Toolkit API
    _partNum = GetRandomString15CharactersLong();
    _domain = "Product";
    _modLevel = "1.0";
     _interfacesToolkit.CreatePart(_partNum, _domain, 30, PartRepairType.Repairable);
    _interfacesToolkit.CreatePartRevision(_partNum, _domain, _modLevel);
}

private static string GetRandomString15CharactersLong()
{
    return Guid.NewGuid().ToString().Substring(0, 15).Replace("-", string.Empty);
}

The variables that the helper methods fill in are also added to the class:

private const int _serialNumber = 1;
private string _partNum = null;
private string _domain = null;
private string _modLevel = null;
private string _workingSiteIdNum;
private string _firstName;
private string _lastName;
private string _phone;
private string _partRequestHeaderIDNum;
private string _partRequestDetailIDNum;

The helper methods can all get called in the Setup method in this example since only one Part Request is needed, and are added to the bottom of the Setup method. Here is the final Setup method:

public void TestFixtureSetUp()
{
    ClarifyApplication.Initialize();
    _clarifySession = ClarifyApplication.Instance.CreateSession("sa", "sa", ClarifyLoginType.User);

    _logisticsToolkit = new LogisticsToolkit(_clarifySession);
    _interfacesToolkit = new InterfacesToolkit(_clarifySession);

    GetContact();
    CreatePartData();
    CreatePartRequestHeader();
    CreatePartRequestDetail();
}

The test now just needs to wire it all up. The call to the API is now very easy since all of the required parameters are known. Validation that everything works can also be done in the test with a quick round trip to the database and verification of the results.

[Test]
public void ChangePartRequestStatus()
{
    //change the part request status using the Logistics Toolkit API
    var setup = new ChangePartRequestStatusSetup(_partRequestDetailIDNum);
    setup.NewStatus = "Awaiting Confirmation";
    setup.GenerateTimeBombs = true;
    setup.Notes = "Status changed via API";

    var result = _logisticsToolkit.ChangePartRequestStatus(setup);

    // verification via generics
    var dataSet = new ClarifyDataSet(_clarifySession);
    var partRequestDetailGeneric = dataSet.CreateGeneric("demand_dtl");
    partRequestDetailGeneric.AppendFilter("objid", NumberOps.Equals, result.Objid);

    var actEntryGeneric = dataSet.CreateGeneric("act_entry");
    actEntryGeneric.TraverseFromParent(partRequestDetailGeneric, "demand_dtl2act_entry");
    actEntryGeneric.AppendFilter("act_code", NumberOps.Equals, 300);

    partRequestDetailGeneric.Query();

    var partRequestDetail = partRequestDetailGeneric.Rows[0];

    Assert.AreEqual("Awating Confirmation", Convert.ToString(partRequestDetail["act_entry record"]));
    Assert.AreEqual(1, actEntryGeneric.Rows.Count, "act_entry record");
}

This test method creates a ChangePartRequestStatusSetup object, and sets the properties on it to be changed. The API call to ChangePartRequestStatus takes the setup object, does the work, and returns a result. The verification is done using database access to get get the Part request from the database. The status field is verified that is changed to the new value, and the activity entry is also checked to make sure that the API completed successfully.

This example just scratches the surface of the capability of the Dovetail SDK and its Toolkit APIs, but should help get similar projects get started down the path to success.

The complete class file can be found in this example class code file.