InfluxDB.Client

2025-12-07 0 402

InfluxDB Client for .NET

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://loc*a*l*host: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://loc*a*l*host: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 interface or DynamicInfluxRow 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 = 200 } );

   InfluxChunkedResult<ComputerInfo> currentResult;
   InfluxChunkedSeries<ComputerInfo> currentSerie;
   InfluxChunk<ComputerInfo> currentChunk;
   int resultCount = 0;
   int serieCount = 0;
   int rowCount = 0;

   using( chunkedResultSet )
   {
      while( ( currentResult = await chunkedResultSet.GetNextResultAsync() ) != null )
      {
         while( ( currentSerie = await currentResult.GetNextSeriesAsync() ) != null )
         {
            while( ( currentChunk = await currentSerie.GetNextChunkAsync() ) != null )
            {
               rowCount += currentChunk.Rows.Count;
            }
            serieCount++;
         }
         resultCount++;
      }
   }

   Assert.Equal( 1 * 2, resultCount );
   Assert.Equal( InfluxClientFixture.Regions.Length * 2, serieCount );
   Assert.Equal( 5000 * 2, rowCount );
}

In the coming versions of C# there will be the capability to iterate over async enumerables, and once this feature hits, I will support that as well. See the video below:

https://channel9.msd***n.com/Blogs/Seth-Juarez/A-Preview-of-C-8-with-Mads-Torgersen#time=16m30s

Preserving timezone offsets

When specifying the timezone clause, influxdb will return timestamps with their offsets. You can preserve this offset in the returned timestamp by using either a DateTimeOffset or Nullable as the timestamp type. If you use DateTime or Nullable as the timestamp type, the timestamp will always be converted to UTC.

Custom timestamp type

Alternatively, you can implement your own ITimestampParser to support custom types, for instance NodaTime. Once implemented you can register on the InfluxClient. Simply implement the following interface:

/// <summary>
/// ITimestampParser is responsible for parsing the \'time\' column
/// of data returned, allowing use of custom DateTime types.
/// </summary>
/// <typeparam name=\"TTimestamp\"></typeparam>
public interface ITimestampParser<TTimestamp>
{
   /// <summary>
   /// Parses a epoch time (UTC) or ISO8601-timestamp (potentially with offset) to a date and time.
   /// This is used when reading data from influxdb.
   /// </summary>
   /// <param name=\"precision\">TimestampPrecision provided by the current InfluxQueryOptions.</param>
   /// <param name=\"epochTimeLongOrIsoTimestampString\">The raw value returned by the query.</param>
   /// <returns>The parsed timestamp.</returns>
   TTimestamp ToTimestamp( TimestampPrecision? precision, object epochTimeLongOrIsoTimestampString );

   /// <summary>
   /// Converts the timestamp to epoch time (UTC). This is used when writing data to influxdb.
   /// </summary>
   /// <param name=\"precision\">TimestampPrecision provided by the current InfluxWriteOptions.</param>
   /// <param name=\"timestamp\">The timestamp to convert.</param>
   /// <returns>The UTC epoch time.</returns>
   long ToEpoch( TimestampPrecision precision, TTimestamp timestamp );
}

Writing to different measurement names in single call

Often you may want to write to multiple measurements with different measurement names by executing a single call.

This can be achieved by either implementing the following interface on your POCO classes:

   /// <summary>
   /// Interface that can be used to specify a per-row measurement name.
   /// </summary>
   public interface IHaveMeasurementName
   {
      /// <summary>
      /// Gets or sets the measurement name.
      /// </summary>
      string MeasurementName { get; set; }
   }
   

Or by putting the [InfluxMeasurement] attribute on your class or property definitions of your POCO class.

When using it on a class you must specify a name, like so:

   [InfluxMeasurement( \"MyTableName\" )]
   public class ClassWithMeasurementName
   {
      [InfluxTimestamp]
      internal DateTime Timestamp { get; set; }

      [InfluxField( \"cpu\" )]
      internal double? CPU { get; set; }
   }

When using it on a property, don\’t specify a name. It will use the property value (which must be a string):

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

      [InfluxField( \"cpu\" )]
      internal double? CPU { get; set; }

      [InfluxMeasurement]
      public string TableName { get; set; }
   }

When using one of these approaches you can then use the following overloads WriteAsync method, which don\’t take a measurementName as an argument:

      public Task WriteAsync<TInfluxRow>( string db, IEnumerable<TInfluxRow> rows )
      
      public Task WriteAsync<TInfluxRow>( string db, IEnumerable<TInfluxRow> rows, InfluxWriteOptions options )
      

In case you want to do this with dynamic classes, you can simply use the NamedDynamicInfluxRow (which implements the IHaveMeasurementName interface).

The following priority is used when determine which measurement to write a record to in case multiple approaches are used:

  • The name provided in the WriteAsync method.
  • The name provided by the IHaveMeasurementName interface
  • The name provided by the property annotated with the InfluxMeasurementAttribute.
  • The name provided in the class annotated with the InfluxMeasurementAttribute.

In case you use the IHaveMeasurementName or a property with the InfluxMeasurementAttribute, the measurement name will be written to that property during read operations.

Parameter binding and SQL injection prevention

The InfluxClient also supports parameter binding to support the prevention of sql injection.

To use this, simply use the methods that takes the parameter \”object parameters\”. This can be an anonymous object, dictionary or any object that supports JSON serialization through Newtonsoft.Json.

When parameterizing values in the object or dictionary, do not prefix the names with $, like the names are in the actual query.

Here\’s an example of what that might look like:

var resultSet = await client.ReadAsync<ComputerInfo>( 
   db,
   \"SELECT * FROM myMeasurementName WHERE time >= $myParam\", 
   new { myParam = new DateTime( 2010, 1, 1, 1, 1, 3, DateTimeKind.Utc ) } );

Any type that you would usually use through this client library can be used as a parameter.

Other operations

The main interface for interacting with influxdb can be seen below.

下载源码

通过命令行克隆项目:

git clone https://github.com/MikaelGRA/InfluxDB.Client.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 InfluxDB.Client https://www.zuozi.net/31264.html

simple http server
上一篇: simple http server
常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务