Session - STARIONGROUP/COMET-SDK-Community-Edition GitHub Wiki

Introduction

The Session class is the core class of the COMET-SDK for API developers that wish to develop C# applications that need to interface with ECSS-E-TM-10-25A Annex C. It provides a layer of abstraction for the IDal interface that exposes the methods that can be used to Create, Read, Update and Delete objects from an Annex C data-source.

The ISession interface works with POCO instances, the IDal interface works with DTO instances.

Credentials

The Credentials class is used to capture information required to connect to a data-source. It carries the username, password and URI of the data-source. The Credentials are used to instantiate a Sesssion object and cannot be changed while the Session is active.

ISession interface

The Session class implements the ISession interface that exposes the following core methods:

method description async
Open Open a connection to a data-source y
Read Read Things from a data-source y
Update Update changed Things from a data-source y
Write Write updates to Things to a data-source y
Refresh Update the Cache with updated Things from a data-source y
Reload Reload all Things from a data-source for all open TopContainers y
Close Close the connection to a data-source and clear the Cache n

The ISession interface exposes more convenience methods that are explained in the following sections.

Session Constructor

The Session class constructor expects 2 arguments, an instance of IDal and an instance of Credential. The IDal interface represents a Data Access Layer implementation used to perform operations on a ECSS-E-TM-10-25 Annex C data-source.

var uri = new Uri("https://cdp4services-public.cdp4.org");
var credentials = new Credentials("some-user-name", "some-password", uri);
var dal = new CdpServicesDal();

var session = new Session(dal, credentials);

Open

The Open method connects to the data-source and requests data from the SiteDirectory route provided by the Annex C data-source. The data-source returns an array of DTO instances that are processed by the Assembler, converted into POCO instances that are add to the Cache. Messages are produced for the objects that are added to the Cache by means of the CDP Message Bus.

try
{
    await session.Open();
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

The Open method should be used in combination with await operator, await can only be used in an asynchronous method modified by the async keyword.

The data that is returned contains enough information for the current user to select an Iteration or a Reference Data Library to work with.

Read

Five distinct Read methods are provided by the ISession interface:

  1. public async Task Read(Iteration iteration, DomainOfExpertise domain): reads data from the data-source related to a specific Iteration, including all the objects that are contained by the specified Iteration.
  2. public async Task Read(ReferenceDataLibrary rdl): reads data from the data-source related to a specific ReferenceDataLibrary, including all the objects that are contained by the specified Iteration.
  3. public async Task Read(Thing thing): reads any Thing from the data-source.
  4. public async Task Read(Thing thing, IQueryAttributes queryAttributes): reads any Thing from the data-source and takes an extra parameter IQueryAttributes to construct extra read constraints.
  5. public async Task Read(IEnumerable<Thing> things, IQueryAttributes queryAttributes): reads an enumerable list of any Thing from the data-source and takes an extra parameter IQueryAttributes to construct extra read constraints.

The IQueryAttributes interface is used to specify constraints on the Read method. It is typically used to readd all revisions of a specifc Thing.

RevisionNumber: Returns the set of all objects contained by the Thing that have a revisionNumber that is greater than the given value. This enables getting the net change of objects since a previous revision

FromRevisionNumber: Specifies, using an integer, that all revisions of an object are requested starting at the specified lower revision. If no revisionTo is specified the range that is requested includes all revisions until the most recent revision.

ToRevisionNumber: Specifies, using an integer, that all revisions of an object are requested until the specified upper revision. If no revisionFrom is specified the range that is requested starts a revision 0.

FromRevisionTimestamp: Specifies, using a TimeStamp, that all revisions of an object are requested starting at the specified lower revision. If no revisionTo is specified the range that is requested includes all revisions until the most recent revision.

ToRevisionTimestamp: Specifies, using an TimeStamp, that all revisions of an object are requested until the specified upper revision. If no revisionFrom is specified the range that is requested starts a revision 0.

Most concepts contained by an Iteration are owned by a DomainOfExpertise. The Session class maintains a list of opened Iterations and the DomainOfExpertise used to open that Iteration in the OpenIterations property.

In order to read an Iteration from a data-source a temporary container EngineeringModel and Iteration object need to be created. The session.Open() method retrieves data from the SiteDirectory which does not contain the EngineeringModel and Iteration objects. It does however contain the EngineeringModelSetup and IterationSetup objects. These setup objects represent meta-data regarding the EngineeringModel and Iteration that we can use to create the Iteration object used in the Read method.

try
{
    // assume that you know the unique identifier of the EngineeringModel, the Iteration, and DomainOfExpertise object that you want to open.
    // These can be retrieved from the cache based on the EngineeringModelSetup and IterationSetup objects that were returned with the Open method

    var engineeringModel = new EngineeringModel(Guid.Parse("694508eb-2730-488c-9405-6ca561df68dd"), session.Assembler.Cache, session.Credentials.Uri);

    var iteration = new Iteration(Guid.Parse("44647ff6-ffe3-44ff-9ed9-3256e2a97f9d"), session.Assembler.Cache, session.Credentials.Uri);

    // construct a containment chain -> this is used to compute the route of the Iteration that is to be retrieved from the data-source
    engineeringModel.Iteration.Add(iteration);

    // get the DomainOfExpertise from the Cache (loaded when the session.Open method was called)
    Lazy<Thing> lazyDomainOfExpertise; 
    session.Assembler.Cache.TryGetValue(new CacheKey(Guid.Parse("8790fe92-d1fa-42ea-9520-e0ddac52f1ad"), null), out lazyDomainOfExpertise); 

    // read the Iteration
    await session.Read(iteration, (DomainOfExpertise)lazyDomainOfExpertise.Value);
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

Messages are produced for the objects that are added and/or updated to the Cache by means of the CDP Message Bus.

Since march 2020 the COMET SDK is capable of receiving extra constraints for Read actions in the form of the IQueryAttributes class. This class is used to construct ECSS TM 10 25 Annex C request query attributes.

Update

Annex C provides the capability to query only those objects that have changed, meaning: changed since the last time the Thing was updated. This is a means to limit the trafic between the client and data-source. The ISession interface exposes the Update method for this purpose. The revision numnber, which is maintained by the data-source for each Thing is used to determine the delta's that need to be returned by the server.

try
{
    // Update the Iteration that was previously read using the Read method.
    await session.Update(iteration);
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

Messages are produced for the objects that are added and/or updated to the Cache by means of the CDP Message Bus.

Write

The Write method is used to write updates to Things. Multiple Things can be updated in one transaction. Annex C specifies that 2 routes can be used to update any data in a data-source. The SiteDirectory and Iteration routes support updates, any other routes do not support updates. Any data that is contained in the SiteDirectory containment that needs to be added, updated or deleted is sent to the SiteDirectory route; Any data that is contained in the EngineeringModel\{iid}\Iteration{iid} containment that needs to be added, updated or deleted is sent to the EngineeringModel\{iid}\Iteration{iid} route. In COMET-SDK terms this is handled by the ThingTransaction, OperationContainer and Operation classes. Annex C does not allow Things contained by the SiteDirectory and an Iteration to be updated in the same transaction.

Note: concepts that are contained by an EngineeringModel, but are not in the containment tree of an Iteration are also sent to an Iteration route, e.g. ModelLogEntry.

The following example shows how to add an ElementDefinition to an Iteration:

    // get the Iteration that the new ElementDefinition needs to be added to from the cache
    Lazy<Thing> lazyIteration; 
    session.Assembler.Cache.TryGetValue(new CacheKey(Guid.Parse("44647ff6-ffe3-44ff-9ed9-3256e2a97f9d"), null), out lazyIteration);
    var iteration = (Iteration)lazyIteration.Value;

    // set the context of the transaction to the iteration the new ElementDefinition needs to be added to.
    // Only a SiteDirectory or Iteration object can be set as context.
    var context = TransactionContextResolver.ResolveContext(iteration);
    var transaction = new ThingTransaction(context);

    // Create a shallow clone of the iteration, the new ElementDefintion will be added to this object. The cached
    // Iteration object should not be changed, so we record the change on a clone.
    var iterationClone = iteration.Clone(false);

    // Create a new instance of ElementDefinition
    var elementDefinition = new ElementDefinition();
    elementDefinition.ShortName = "BAT";
    elementDefinition.Name = "Battery";
    elementDefinition.Owner = domainOfExpertise;

    // register the new ElementDefinition and the container Iteration (clone) with the transaction.
    transaction.Create(elementDefinition, iterationClone);

    // finalize the transaction, the result is an OperationContainer that the session class uses to write the changes
    // to the Iteration object (the list of contained elements is updated) and and the new ElementDefinition.
    var operationContainer = this.transaction.FinalizeTransaction();

try
{
    await session.Write(operationContainer);
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

Refresh

The Refresh method is used to query a data-source for all Things that have changed. The Refresh method uses the Update method performs an Update on the SiteDirectory and all Iterations that have been Read by the session.

try
{
    await session.Refresh();
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

Messages are produced for the objects that are added and/or updated to the Cache by means of the CDP Message Bus.

Reload

The Reload method is used to query a data-source for all Things in the context of the SiteDirectory and the open Iterations of the session. Where the Refresh method is used to get the delta's, the Reload method is used to get all data, regardless of whether it has been changed or not.

try
{
    await session.Refresh();
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}

Messages are produced for the objects that are added and/or updated to the Cache by means of the CDP Message Bus.

Close

The Close() method closses the connection the underlying IDal has to the datasource, clears the Cache, the OpenReferenceDataLibraries as well as the OpenIterations.

Once the Session has been closed a SessionEvent is sent through the CDP Message Bus notifying listeners that the Session has been closed. This can used by GUI implementations to perform any clean-up that may be required once a Session has been closed.

try
{
    await session.Close();
}
catch(Exception ex)
{
    // handle the exception here and don't forget to do some logging
}
⚠️ **GitHub.com Fallback** ⚠️