SkillAgentSearch skills...

InfluxDB.Client

InfluxDB Client for .NET

Install / Use

/learn @MikaelGRA/InfluxDB.Client
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

InfluxDB Client for .NET

<!-- [![Build status](https://ci.appveyor.com/api/projects/status/0rkna8pevwiv9acy/branch/master?svg=true)](https://ci.appveyor.com/project/MikaelGRA/influxdb-client/branch/master) -->

This library makes it easy to be a client for InfluxDB on .NET!

The basic idea behind the library is that it should be able to turn queries directly into objects of your own classes. Much like micro-ORMS such as dapper.

The goal is that we want to be able to support LINQ syntax in the future.

Installation

Install it through nuget with the following command.

Install-Package Vibrant.InfluxDB.Client

The package can be found here.

Or you can simply grab it in one of the github releases.

Reading/Writing

The library exposes all HTTP operations on InfluxDB (1.0+) and can be used for reading/writing data to/from in two primary ways:

  • Using your own POCO classes.
  • Using dynamic classes.

A simple example of how to use the library is available here.

Using your own POCO classes

Start by defining a class that represents a row in InfluxDB that you want to store.

public class ComputerInfo
{
   [InfluxTimestamp]
   public DateTime Timestamp { get; set; }

   [InfluxTag( "host" )]
   public string Host { get; set; }

   [InfluxTag( "region" )]
   public string Region { get; set; }

   [InfluxField( "cpu" )]
   public double CPU { get; set; }

   [InfluxField( "ram" )]
   public long RAM { get; set; }
}

On your POCO class you must specify these things:

  • 1 property with the type DateTime, DateTime?, DateTimeOffset or DateTimeOffset? as the timestamp used in InfluxDB by adding the [InfluxTimestamp] attribute.
  • 0-* properties with the type string, long, ulong, int, uint, short, ushort, byte, sbyte, double, float, bool, DateTime, DateTimeOffset, decimal or a user-defined enum (nullables too) with the [InfluxTag] attribute that InfluxDB will use as indexed tags. Note that all tags in InfluxDB is still stored a string. The library will simply making the conversion to the specified type automatically.
  • 1-* properties with the type string, long, ulong, int, uint, short, ushort, byte, sbyte, double, float, bool, DateTime, DateTimeOffset, decimal or a user-defined enum (nullables too) with the [InfluxField] attribute that InfluxDB will use as fields.

Once you've defined your class, you're ready to use the InfluxClient, which is the main entry point to the API:

Here's how to write to the database:

private ComputerInfo[] CreateTypedRowsStartingAt( DateTime start, int rows )
{
   var rng = new Random();
   var regions = new[] { "west-eu", "north-eu", "west-us", "east-us", "asia" };
   var hosts = new[] { "some-host", "some-other-host" };

   var timestamp = start;
   var infos = new ComputerInfo[ rows ];
   for ( int i = 0 ; i < rows ; i++ )
   {
      long ram = rng.Next( int.MaxValue );
      double cpu = rng.NextDouble();
      string region = regions[ rng.Next( regions.Length ) ];
      string host = hosts[ rng.Next( hosts.Length ) ];

      var info = new ComputerInfo { Timestamp = timestamp, CPU = cpu, RAM = ram, Host = host, Region = region };
      infos[ i ] = info;

      timestamp = timestamp.AddSeconds( 1 );
   }

   return infos;
}

public async Task Should_Write_Typed_Rows_To_Database()
{
   var client = new InfluxClient( new Uri( "http://localhost:8086" ) );
   var infos = CreateTypedRowsStartingAt( new DateTime( 2010, 1, 1, 1, 1, 1, DateTimeKind.Utc ), 500 );
   await client.WriteAsync( "mydb", "myMeasurementName", infos );
}

Here's how to query from the database:

public async Task Should_Query_Typed_Data()
{
   var resultSet = await client.ReadAsync<ComputerInfo>( "mydb", "SELECT * FROM myMeasurementName" );
   
   // resultSet will contain 1 result in the Results collection (or multiple if you execute multiple queries at once)
   var result = resultSet.Results[ 0 ];
   
   // result will contain 1 series in the Series collection (or potentially multiple if you specify a GROUP BY clause)
   var series = result.Series[ 0 ];
   
   // series.Rows will be the list of ComputerInfo that you queried for
   foreach ( var row in series.Rows )
   {
      Console.WriteLine( "Timestamp: " + row.Timestamp );
      Console.WriteLine( "CPU: " + row.CPU );
      Console.WriteLine( "RAM: " + row.RAM );
      // ...
   }
}

Using dynamic classes

POCO classes does not fit every use-case. This becomes obvious once you are implementing a system and you don't know what the fields/tags will be at compile time. In this case you must use dynamic classes.

In order for this to work, you must use the interface IInfluxRow that specifies reading/writing methods for tags and fields. This library already includes one implementatioon of this interfaces that uses dictionaries and has basic support for the DLR. This class is called DynamicInfluxRow.

Here's how to write using dynamic classes.

private DynamicInfluxRow[] CreateDynamicRowsStartingAt( DateTime start, int rows )
{
   var rng = new Random();
   var regions = new[] { "west-eu", "north-eu", "west-us", "east-us", "asia" };
   var hosts = new[] { "some-host", "some-other-host" };
   
   var timestamp = start;
   var infos = new DynamicInfluxRow[ rows ];
   for ( int i = 0 ; i < rows ; i++ )
   {
      long ram = rng.Next( int.MaxValue );
      double cpu = rng.NextDouble();
      string region = regions[ rng.Next( regions.Length ) ];
      string host = hosts[ rng.Next( hosts.Length ) ];

      var info = new DynamicInfluxRow();
      info.Fields.Add( "cpu", cpu );
      info.Fields.Add( "ram", ram );
      info.Tags.Add( "host", host );
      info.Tags.Add( "region", region );
      info.Timestamp = timestamp;

      infos[ i ] = info;

      timestamp = timestamp.AddSeconds( 1 );
   }
   return infos;
}

public async Task Should_Write_Dynamic_Rows_To_Database()
{
   var client = new InfluxClient( new Uri( "http://localhost:8086" ) );
   var infos = CreateDynamicRowsStartingAt( new DateTime( 2010, 1, 1, 1, 1, 1, DateTimeKind.Utc ), 500 );
   await client.WriteAsync( "mydb", "myMeasurementName", infos );
}

Do note, that if you use dynamic classes, user-defined enums and DateTimes as fields/tags are not supported, as there is no way to differentiate between a string and an enum/DateTime.

Also note, if you want to use custom timestamp type or DateTimeOffset with this interface, you can use the generic IInfluxRow<TTimestamp> interface or DynamicInfluxRow<TTimestamp> class.

Here's how to query from the database:

public async Task Should_Query_Dynamic_Data()
{
   var resultSet = await client.ReadAsync<DynamicInfluxRow>( "mydb", "SELECT * FROM myMeasurementName" );
   
   // resultSet will contain 1 result in the Results collection (or multiple if you execute multiple queries at once)
   var result = resultSet.Results[ 0 ];
   
   // result will contain 1 series in the Series collection (or potentially multiple if you specify a GROUP BY clause)
   var series = result.Series[ 0 ];
   
   // series.Rows will be the list of DynamicInfluxRow that you queried for (which can be cast to dynamic)
   foreach ( dynamic row in series.Rows )
   {
      Console.WriteLine( "Timestamp: " + row.time ); // Can also access row.Timestamp
      Console.WriteLine( "CPU: " + row.cpu );
      Console.WriteLine( "RAM: " + row.ram );
      // ...
   }
}

Read only operations

Often, you may not be selecting the exact structure that you are also inserting. Maybe you are doing some aggregation or calculations on the data that you are retrieving that changes the name of the returned columns.

In this case, you can simply define a new class and use the InfluxComputedAttribute. Any columns that matches the name specified in the attribute (tag or field, aggregated or not) will go into the property with this attribute.

[InfluxComputedAttribute]

Classes with this attribute should not be used for insertion, as there is no way for the client to know if it is a field or tag.

If you are using the IInfluxRow interface (DynamicInfluxRow, for instance), then the "Fields" collection is filled up with all columns that does not match a known tag for the specific measurement.

Chunking

Sometimes you may retrieve a massive amount of data from the database, so much in fact, that keeping it all in memory at any one time is unfeasible. In this case you need the chunking feature provided by InfluxDB. You can take advantage of this feature by enabling chunking through the InfluxQueryOptions class. When enabled the client will provide the chunking options to InfluxDB when it is retrieving data.

The default ReadAsync operations will, however, simply read all chunks before returning control to the user. To support scenarios where you want to read the data chunk by chunk, you can instead use the method ReadChunkedAsync. This will return a different type of result set that allows you to asynchonously iterate over all the chunks (while still maintaining the structure of the queries that you initially made). Here's an example taken from the unit tests:

[Fact]
public async Task Should_Write_And_Query_Deferred_Grouped_Data_With_Multi_Query()
{
   var start = new DateTime( 2011, 1, 1, 1, 1, 1, DateTimeKind.Utc );
   var infos = InfluxClientFixture.CreateTypedRowsStartingAt( start, 5000, false );
   await client.WriteAsync( InfluxClientFixture.DatabaseName, "groupedComputerInfo4", infos );
   await client.WriteAsync( InfluxClientFixture.DatabaseName, "groupedComputerInfo5", infos );

   var chunkedResultSet = await client.ReadChunkedAsync<ComputerInfo>( 
      InfluxClientFixture.DatabaseName, 
      $"SELECT * FROM groupedComputerInfo4 GROUP BY region;SELECT * FROM groupedComputerInfo5 GROUP BY region", 
      new InfluxQueryOptions { ChunkSize = 20

Related Skills

View on GitHub
GitHub Stars101
CategoryDevelopment
Updated13d ago
Forks21

Languages

C#

Security Score

100/100

Audited on Mar 25, 2026

No findings