Question

detNet RestAPI Cognite SDK example


Hello,

I am quite new on usinf RestAPI. My company has the license to use CDF. I also inderstood that Cognite has developed dotNet RestApi SDK.

I searched a bit but I could not find an example of how we can use this SDK for data retrieval especially for time-series data. How could I get a snippet of code showing an example how to use this?

Thanks.

 


10 replies

Userlevel 1

Hi @samirhaj! To use the CDF .NET SDK you will first need to use authenticate against your Identity Provider (IdP) to acquire a valid token. If you are using an Azure Active Directory (AAD), you can use the MSAL .NET library for this purpose.

Here’s a minimal C# example that reads the AAD and associated CDF variables from environment variables, initiate an interactive flow to acquire the token and uses the token to instantiate the CDF client. If you refer to the MSAL documentation, it’s straightforward to extend this example to other authentication flows.

string clientId = System.Environment.GetEnvironmentVariable("CLIENT_ID");
string tenantId = System.Environment.GetEnvironmentVariable("TENANT_ID");
string cluster = System.Environment.GetEnvironmentVariable("CDF_CLUSTER");
string project = System.Environment.GetEnvironmentVariable("CDF_PROJECT");

var scopes = new List<string>{ $"https://{cluster}.cognitedata.com/.default" };

var app = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.WithRedirectUri("http://local host")
.Build();

AuthenticationResult result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
string accessToken = result.AccessToken;

var httpClient = new HttpClient();
var client = Client.Builder.Create(httpClient)
.SetAppId("testNotebook")
.AddHeader("Authorization", $"Bearer {accessToken}")
.SetProject(project)
.SetBaseUrl(new Uri($"https://{cluster}.cognitedata.com"))
.Build();

Be mindful that I had to separate the words local and host, as this is a word that’s currently not allowed in the Cognite Hub.

Once you have instantiated a client, you can fetch some time series datapoints. Here’s a minimal example on how to do fetch the last 7 days of data from a time series with externalId = "pi:160704" with 1h granularity:

var res = await client.DataPoints.ListAsync(new DataPointsQuery{
Start = "7d-ago",
End = "now",
Items = new List<DataPointsQueryItem> {
new DataPointsQueryItem {
ExternalId = "pi:160704",
Aggregates = new List<string> { "average" },
Granularity = "1h",
Limit = 10_000
}
}
});
var ts = res.Items[0];
var dps = ts.AggregateDatapoints.Datapoints;

Thanks for your prompt reply @Everton Colling

One more question: in the code above where you have defined the CogniteSdk client as “var”, why this client has not been initialized with an instance of CogniteSdk client first (pseudo-code example: Client client = new Client())? I am asking this because I want to access to the client to use that in all methods but if I define it as local var, it will not be accessible in the bottom part of the code above where the client is used to fetch time-series data (which needs a method to call until fetch all the data we need but the instantiation method need to call once. Am I missing something here? 

Userlevel 1

In this case, declaring the client with var or CogniteSdk.Client does not make a difference. The last command Build() creates an instance of the client that you can use to fetch time series data points as with the example above.

Userlevel 5
Badge

Hi @samirhaj checking to see if you need more information on the above? 

Hi @Anita Hæhre : There were some specifics regarding our own company interface with Cognite, so I continued the discussion with @Everton Colling in the private session. 

Userlevel 5
Badge

Thanks @samirhaj, I’ll then close this thread. Do let the community know if we can help again with this or other issues, we’re here to help:) 

Hi @Everton Colling 

Thanks for your reply.

My ultimate goal is to convert the data that I pull out from cognite interface into a csv file (in which each of the data type with its ExternalId in one column of the csv and DateTime in the first column), so I would rather have the output result that looks like this now;

{ DateTime = 3/23/2023 21:00:00, Average = 13.713887271148339 }

{ DateTime = 3/23/2023 22:00:00, Average = 13.662878633528655 }

into the format that I won’t see the words “DateTime = “ and “Average = ” in each row of data. So I mean something similar to the following if possible?

DateTime                     Average

3/23/2023 21:00:00      13.713887271148339

3/23/2023 22:00:00       13.662878633528655

.

.

.

One other question I have is that in the console.writeline() of the code, there is no string “DateTime = “ or “Average = “, so I wonder how these words was printed out to the console?

 

Best regards.

Userlevel 1

Hi @samirhaj!

In C#, when you create a new object using the syntax new { propertyName = propertyValue }, you are creating an anonymous type object. In the case when you omit the property name, like when using the syntax new { propertyValue }, the compiler automatically generates a property name for each property based on the name of the property value.

When you call Console.WriteLine with an anonymous type object as its argument, it automatically calls the ToString() method of the object to obtain a string representation of the object, which includes the names and values of its properties.

As for your desire to create a CSV with the data, it’s quite simple, here’s a minimal example on how to do it:

using (var writer = new StreamWriter("output.csv"))
{
writer.WriteLine("DateTime,Average");
foreach (var dp in dps)
writer.WriteLine($"{dp.DateTime},{dp.Average}");
}

In this example we are using the StreamWriter which is part of the System.IO namespace in C#. We are first writing the header of the CSV followed by iterating over the dps items and writing only their values. The data will be saved into a file called output.csv.

You can adapt the example above and change the header to include the externalID instead of the aggregate name.

Ok, Thanks for your reply.

One more question here: to set how often we want to fetch data for us, should we configure the Granularity parameter or ... ? For example, if I want the data for every 1 sec or 10 sec or 1 minute. I tried to put Granularity to be “0.5h” but it crashed. 

Could you please advise?

 

Best regards.

 

Userlevel 1

For 0.5h you should use a granularity of 30m (as granularity cannot be a rational number). You can refer to the Cognite API documentation for more information about valid options for granularity and aggregateshttps://docs.cognite.com/dev/concepts/aggregation/#granularity.

Reply