InfluxDB.Client 4.15.0-dev.13282

This is a prerelease version of InfluxDB.Client.
There is a newer version of this package available.
See the version list below for details.
dotnet add package InfluxDB.Client --version 4.15.0-dev.13282                
NuGet\Install-Package InfluxDB.Client -Version 4.15.0-dev.13282                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="InfluxDB.Client" Version="4.15.0-dev.13282" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add InfluxDB.Client --version 4.15.0-dev.13282                
#r "nuget: InfluxDB.Client, 4.15.0-dev.13282"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install InfluxDB.Client as a Cake Addin
#addin nuget:?package=InfluxDB.Client&version=4.15.0-dev.13282&prerelease

// Install InfluxDB.Client as a Cake Tool
#tool nuget:?package=InfluxDB.Client&version=4.15.0-dev.13282&prerelease                

InfluxDB.Client

CircleCI

The reference client that allows query, write and management (bucket, organization, users) for the InfluxDB 2.x.

Documentation

This section contains links to the client library documentation.

Features

Queries

For querying data we use QueryApi that allow perform asynchronous, streaming, synchronous and also use raw query response.

Asynchronous Query

The asynchronous query is not intended for large query results because the Flux response can be potentially unbound.

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class AsynchronousQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var tables = await queryApi.QueryAsync(flux, "org_id");
            tables.ForEach(table =>
            {
                table.Records.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
                });
            });
        }        
    }
}

The asynchronous query offers a possibility map FluxRecords to POCO:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class AsynchronousQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var temperatures = await queryApi.QueryAsync<Temperature>(flux, "org_id");
            temperatures.ForEach(temperature =>
            {
                Console.WriteLine($"{temperature.Location}: {temperature.Value} at {temperature.Time}");
            });
        }  
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}

Streaming Query

The Streaming query offers possibility to process unbound query and allow user to handle exceptions, stop receiving more results and notify that all data arrived.

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class StreamingQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryAsync(flux, record =>
            {
                //
                // The callback to consume a FluxRecord.
                //
                Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
            }, exception =>
            {
                //
                // The callback to consume any error notification.
                //
                Console.WriteLine($"Error occurred: {exception.Message}");
            }, () =>
            {
                //
                // The callback to consume a notification about successfully end of stream.
                //
                Console.WriteLine("Query completed");
            }, "org_id");
        }
    }
}

And there is also a possibility map FluxRecords to POCO:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class StreamingQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryAsync<Temperature>(flux, temperature =>
            {
                //
                // The callback to consume a FluxRecord mapped to POCO.
                //
                Console.WriteLine($"{temperature.Location}: {temperature.Value} at {temperature.Time}");
            }, org: "org_id");
        }  
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}

Raw Query

The Raw query allows direct processing original CSV response:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class RawQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var csv = await queryApi.QueryRawAsync(flux, org: "org_id");
            
            Console.WriteLine($"CSV response: {csv}");
        }
    }
}

The Streaming version allows processing line by line:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class RawQueryAsynchronous
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryRawAsync(flux, line =>
            {
                //
                // The callback to consume a line of CSV response
                //
                Console.WriteLine($"Response: {line}");
            }, org: "org_id");
        }
    }
}

Synchronous query

The synchronous query is not intended for large query results because the response can be potentially unbound.

using System;
using InfluxDB.Client;

namespace Examples
{
    public static class SynchronousQuery
    {
        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:9999", "my-token");

            const string query = "from(bucket:\"my-bucket\") |> range(start: 0)";
           
            //
            // QueryData
            //
            var queryApi = client.GetQueryApiSync();
            var tables = queryApi.QuerySync(query, "my-org");
            
            //
            // Process results
            //
            tables.ForEach(table =>
            {
                table.Records.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
                });
            });
        }
    }
}

Writes

For writing data we use WriteApi or WriteApiAsync which is simplified version of WriteApi without batching support.

WriteApi supports:

  1. writing data using InfluxDB Line Protocol, Data Point, POCO
  2. use batching for writes
  3. produces events that allow user to be notified and react to this events
    • WriteSuccessEvent - published when arrived the success response from server
    • WriteErrorEvent - published when occurs a unhandled exception from server
    • WriteRetriableErrorEvent - published when occurs a retriable error from server
    • WriteRuntimeExceptionEvent - published when occurs a runtime exception in background batch processing
  4. use GZIP compression for data

The writes are processed in batches which are configurable by WriteOptions:

Property Description Default Value
BatchSize the number of data point to collect in batch 1000
FlushInterval the number of milliseconds before the batch is written 1000
JitterInterval the number of milliseconds to increase the batch flush interval by a random amount 0
RetryInterval the number of milliseconds to retry unsuccessful write. The retry interval is used when the InfluxDB server does not specify "Retry-After" header. 5000
MaxRetries the number of max retries when write fails 3
MaxRetryDelay the maximum delay between each retry attempt in milliseconds 125_000
ExponentialBase the base for the exponential retry delay, the next delay is computed using random exponential backoff as a random value within the interval retryInterval * exponentialBase^(attempts-1) and retryInterval * exponentialBase^(attempts). Example for retryInterval=5_000, exponentialBase=2, maxRetryDelay=125_000, maxRetries=5 Retry delays are random distributed values within the ranges of [5_000-10_000, 10_000-20_000, 20_000-40_000, 40_000-80_000, 80_000-125_000] 2

Writing data

By POCO

Write Measurement into specified bucket:

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class WritePoco
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by POCO
                //
                var temperature = new Temperature {Location = "south", Value = 62D, Time = DateTime.UtcNow};

                writeApi.WriteMeasurement(temperature, WritePrecision.Ns, "bucket_name", "org_id");
            }
        }
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}
By Data Point

Write Data point into specified bucket:

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteDataPoint
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by Data Point
                
                var point = PointData.Measurement("temperature")
                    .Tag("location", "west")
                    .Field("value", 55D)
                    .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);
                
                writeApi.WritePoint(point, "bucket_name", "org_id");
            }
        }
    }
}

DataPoint Builder Immutability: The builder is immutable therefore won't have side effect when using for building multiple point with single builder.

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteDataPoint
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by Data Point
                
                var builder = PointData.Measurement("temperature")
                    .Tag("location", "west");
                
                var pointA = builder
                    .Field("value", 55D)
                    .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);
                
                writeApi.WritePoint(pointA, "bucket_name", "org_id");
                
                var pointB = builder
                    .Field("age", 32)
                    .Timestamp(DateTime.UtcNow, WritePrecision.Ns);
                
                writeApi.WritePoint(pointB, "bucket_name", "org_id");
            }
        }
    }
}
By LineProtocol

Write Line Protocol record into specified bucket:

using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;

namespace Examples
{
    public static class WriteLineProtocol
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                //
                // Write by LineProtocol
                //
                writeApi.WriteRecord("temperature,location=north value=60.0", WritePrecision.Ns,"bucket_name", "org_id");
            }
        }
    }
}
Using WriteApiAsync
using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteApiAsyncExample
    {   
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
        
        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", 
                            "my-user", "my-password");

            //
            // Write Data
            //
            var writeApiAsync = client.GetWriteApiAsync();

            //
            //
            // Write by LineProtocol
            //
            await writeApiAsync.WriteRecordAsync("temperature,location=north value=60.0", WritePrecision.Ns,
                "my-bucket", "my-org");

            //
            //
            // Write by Data Point
            //               
            var point = PointData.Measurement("temperature")
                            .Tag("location", "west")
                            .Field("value", 55D)
                            .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);

            await writeApiAsync.WritePointAsync(point, "my-bucket", "my-org");

            //
            // Write by POCO
            //
            var temperature = new Temperature {Location = "south", Value = 62D, Time = DateTime.UtcNow};

            await writeApiAsync.WriteMeasurementAsync(temperature, WritePrecision.Ns, "my-bucket", "my-org");

            //
            // Check written data
            //
            var tables = await influxDbClient.GetQueryApi()
                            .QueryAsync("from(bucket:\"my-bucket\") |> range(start: 0)", "my-org");
            
            tables.ForEach(table =>
            {
                var fluxRecords = table.Records;
                fluxRecords.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValue()}");
                });
            });
        }
    }
}
Default Tags

Sometimes is useful to store same information in every measurement e.g. hostname, location, customer. The client is able to use static value, app settings or env variable as a tag value.

The expressions:

  • California Miner - static value
  • ${version} - application settings
  • ${env.hostname} - environment property
Via Configuration file

In a configuration file you are able to specify default tags by tags element.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="influx2" type="InfluxDB.Client.Configurations.Influx2, InfluxDB.Client" />
    </configSections>
    <appSettings>
        <add key="SensorVersion" value="v1.00"/>
    </appSettings>
    <influx2 url="http://localhost:8086"
             org="my-org"
             bucket="my-bucket"
             token="my-token"
             logLevel="BODY"
             timeout="10s">
        <tags>
            <tag name="id" value="132-987-655"/>
            <tag name="customer" value="California Miner"/>
            <tag name="hostname" value="${env.Hostname}"/>
            <tag name="sensor-version" value="${SensorVersion}"/>
        </tags>
    </influx2>
</configuration>
Via API
var options = new InfluxDBClientOptions(Url)
{
    Token = token,
    DefaultTags = new Dictionary<string, string>
    {
        {"id", "132-987-655"},
        {"customer", "California Miner"},
    }
};   
options.AddDefaultTag("hostname", "${env.Hostname}")
options.AddDefaultTags(new Dictionary<string, string>{{ "sensor-version", "${SensorVersion}" }})

Both of configurations will produce the Line protocol:

mine-sensor,id=132-987-655,customer="California Miner",hostname=example.com,sensor-version=v1.00 altitude=10

Handle the Events

Events that can be handle by WriteAPI EventHandler are:

  • WriteSuccessEvent - for success response from server
  • WriteErrorEvent - for unhandled exception from server
  • WriteRetriableErrorEvent - for retriable error from server
  • WriteRuntimeExceptionEvent - for runtime exception in background batch processing

Number of events depends on number of data points to collect in batch. The batch size is configured by BatchSize option (default size is 1000) - in case of one data point, event is handled for each point, independently on used writing method (even for mass writing of data like WriteMeasurements, WritePoints and WriteRecords).

Events can be handled by register writeApi.EventHandler or by creating custom EventListener:

Register EventHandler
writeApi.EventHandler += (sender, eventArgs) =>
{
    switch (eventArgs)
    {
        case WriteSuccessEvent successEvent:
            string data = @event.LineProtocol;
            //
            // handle success response from server
            // Console.WriteLine($"{data}");
            //
            break;
        case WriteErrorEvent error:
            string data = @error.LineProtocol;
            string errorMessage = @error.Exception.Message;
            //
            // handle unhandled exception from server
            //
            // Console.WriteLine($"{data}");
            // throw new Exception(errorMessage);
            //
            break;
        case WriteRetriableErrorEvent error:
            string data = @error.LineProtocol;
            string errorMessage = @error.Exception.Message;
            //
            // handle retrievable error from server
            //
            // Console.WriteLine($"{data}");
            // throw new Exception(errorMessage);
            //
            break;
        case WriteRuntimeExceptionEvent error:
            string errorMessage = @error.Exception.Message;
            //
            // handle runtime exception in background batch processing
            // throw new Exception(errorMessage);
            //
            break;
    }
};

//
// Write by LineProtocol
//
writeApi.WriteRecord("influxPoint,writeType=lineProtocol value=11.11" +
    $" {DateTime.UtcNow.Subtract(EpochStart).Ticks * 100}", WritePrecision.Ns, "my-bucket", "my-org");
Custom EventListener

Advantage of using custom Event Listener is possibility of waiting on handled event between different writings - for more info see EventListener.

Delete Data

Delete data from specified bucket:

using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;

namespace Examples
{
    public static class WriteLineProtocol
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Delete data
            //
            await client.GetDeleteApi().Delete(DateTime.UtcNow.AddMinutes(-1), DateTime.Now, "", "bucket", "org");
        }
    }
}

Filter trace verbose

You can filter out verbose messages from InfluxDB.Client by using TraceListener.

using System;
using System.Diagnostics;
using InfluxDB.Client.Core;

namespace Examples
{
  public static class MyProgram
  {
    public static void Main()
    {
      TraceListener ConsoleOutListener = new TextWriterTraceListener(Console.Out)
      {
        Filter = InfluxDBTraceFilter.SuppressInfluxVerbose(),
      };
      Trace.Listeners.Add(ConsoleOutListener);

      // My code ...
    }
  }
}

Management API

The client has following management API:

API endpoint Description Implementation
/api/v2/authorizations Managing authorization data AuthorizationsApi
/api/v2/buckets Managing bucket data BucketsApi
/api/v2/orgs Managing organization data OrganizationsApi
/api/v2/users Managing user data UsersApi
/api/v2/sources Managing sources SourcesApi
/api/v2/tasks Managing one-off and recurring tasks TasksApi
/api/v2/scrapers Managing ScraperTarget data ScraperTargetsApi
/api/v2/labels Managing resource labels LabelsApi
/api/v2/telegrafs Managing telegraf config data TelegrafsApi
/api/v2/setup Managing onboarding setup InfluxDBClient#OnBoarding()
/ready Get the readiness of a instance at startup InfluxDBClient#Ready()
/health Get the health of an instance anytime during execution InfluxDBClient#Health()

The following example demonstrates how to use a InfluxDB 2.x Management API. For further information see endpoints implementation.

using System;
using System.Collections.Generic;
using System.Linq;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using Task = System.Threading.Tasks.Task;

namespace Examples
{
    public static class ManagementExample
    {
        public static async Task Main()
        {
            const string url = "http://localhost:8086";
            const string token = "my-token";
            const string org = "my-org";
            
            using var client = new InfluxDBClient(url, token);

            // Find ID of Organization with specified name (PermissionAPI requires ID of Organization).
            var orgId = (await client.GetOrganizationsApi().FindOrganizationsAsync(org: org)).First().Id;

            //
            // Create bucket "iot_bucket" with data retention set to 3,600 seconds
            //
            var retention = new BucketRetentionRules(BucketRetentionRules.TypeEnum.Expire, 3600);

            var bucket = await client.GetBucketsApi().CreateBucketAsync("iot_bucket", retention, orgId);

            //
            // Create access token to "iot_bucket"
            //
            var resource = new PermissionResource(PermissionResource.TypeBuckets, bucket.Id, null,
                orgId);

            // Read permission
            var read = new Permission(Permission.ActionEnum.Read, resource);

            // Write permission
            var write = new Permission(Permission.ActionEnum.Write, resource);

            var authorization = await client.GetAuthorizationsApi()
                .CreateAuthorizationAsync(orgId, new List<Permission> { read, write });

            //
            // Created token that can be use for writes to "iot_bucket"
            //
            Console.WriteLine($"Authorized token to write into iot_bucket: {authorization.Token}");
        }
    }
}

If there is no API implementation for particular service you could create the service by:

var dbrpService = _client.CreateService<DBRPsService>(typeof(DBRPsService));

Advanced Usage

Monitoring & Alerting

The example below show how to create a check for monitoring a stock price. A Slack notification is created if the price is lesser than 35.

Create Threshold Check

The Check set status to Critical if the current value for a stock measurement is lesser than 35.

var org = ...;

var query = "from(bucket: \"my-bucket\") "
        + "|> range(start: v.timeRangeStart, stop: v.timeRangeStop)  "
        + "|> filter(fn: (r) => r._measurement == \"stock\")  "
        + "|> filter(fn: (r) => r.company == \"zyz\")  "
        + "|> aggregateWindow(every: 5s, fn: mean)  "
        + "|> filter(fn: (r) => r._field == \"current\")  "
        + "|> yield(name: \"mean\")";

var threshold = new LesserThreshold(value: 35F, level: CheckStatusLevel.CRIT,
                type: LesserThreshold.TypeEnum.Lesser);

var message = "The Stock price for XYZ is on: ${ r._level } level!";

await Client
    .GetChecksApi()
    .CreateThresholdCheckAsync("XYZ Stock value", query, "5s", message, threshold, org.Id);
Create Slack Notification endpoint
var url = "https://hooks.slack.com/services/x/y/z"; 

var endpoint = await Client
    .GetNotificationEndpointsApi()
    .CreateSlackEndpointAsync("Slack Endpoint", url, org.Id);
Create Notification Rule
await Client
    .GetNotificationRulesApi()
    .CreateSlackRuleAsync("Critical status to Slack", "10s", "${ r._message }", RuleStatusLevel.CRIT, endpoint, org.Id);

Custom mapping of DomainObject to/from InfluxDB

The default mapper uses Column attributes to define how the DomainObject will be mapped to and from the InfluxDB. The our APIs also allow to specify custom mapper. For more information see following example:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core.Flux.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class CustomDomainMapping
    {
        /// <summary>
        /// Define Domain Object
        /// </summary>
        private class Sensor
        {
            /// <summary>
            /// Type of sensor.
            /// </summary>
            public String Type { get; set; }
            
            /// <summary>
            /// Version of sensor.
            /// </summary>
            public String Version { get; set; }

            /// <summary>
            /// Measured value.
            /// </summary>
            public double Value { get; set; }

            public DateTimeOffset Timestamp { get; set; }

            public override string ToString()
            {
                return $"{Timestamp:MM/dd/yyyy hh:mm:ss.fff tt} {Type}, {Version} value: {Value}";
            }
        }

        /// <summary>
        /// Define Custom Domain Object Converter
        /// </summary>
        private class DomainEntityConverter : IDomainObjectMapper
        {
            /// <summary>
            /// Convert to DomainObject.
            /// </summary>
            public object ConvertToEntity(FluxRecord fluxRecord, Type type)
            {
                if (type != typeof(Sensor))
                {
                    throw new NotSupportedException($"This converter doesn't supports: {type}");
                }

                var customEntity = new Sensor
                {
                    Type = Convert.ToString(fluxRecord.GetValueByKey("type")),
                    Version = Convert.ToString(fluxRecord.GetValueByKey("version")),
                    Value = Convert.ToDouble(fluxRecord.GetValueByKey("data")),
                    Timestamp = fluxRecord.GetTime().GetValueOrDefault().ToDateTimeUtc(),
                };
                
                return Convert.ChangeType(customEntity, type);
            }
            
            /// <summary>
            /// Convert to DomainObject.
            /// </summary>
            public T ConvertToEntity<T>(FluxRecord fluxRecord)
            {
                return (T)ConvertToEntity(fluxRecord, typeof(T));
            }

            /// <summary>
            /// Convert to Point
            /// </summary>
            public PointData ConvertToPointData<T>(T entity, WritePrecision precision)
            {
                if (!(entity is Sensor sensor))
                {
                    throw new NotSupportedException($"This converter doesn't supports: {entity}");
                }

                var point = PointData
                    .Measurement("sensor")
                    .Tag("type", sensor.Type)
                    .Tag("version", sensor.Version)
                    .Field("data", sensor.Value)
                    .Timestamp(sensor.Timestamp, precision);

                return point;
            }
        }

        public static async Task Main(string[] args)
        {
            const string host = "http://localhost:9999";
            const string token = "my-token";
            const string bucket = "my-bucket";
            const string organization = "my-org";
            var options = new InfluxDBClientOptions(host)
            {
                Token = token,
                Org = organization,
                Bucket = bucket
            };

            var converter = new DomainEntityConverter();
            using var client = new InfluxDBClient(options);

            //
            // Prepare data to write
            //
            var time = new DateTimeOffset(2020, 11, 15, 8, 20, 15,
                new TimeSpan(3, 0, 0));

            var entity1 = new Sensor
            {
                Timestamp = time,
                Type = "temperature",
                Version = "v0.0.2",
                Value = 15
            };
            var entity2 = new Sensor
            {
                Timestamp = time.AddHours(1),
                Type = "temperature",
                Version = "v0.0.2",
                Value = 15
            };
            var entity3 = new Sensor
            {
                Timestamp = time.AddHours(2),
                Type = "humidity",
                Version = "v0.13",
                Value = 74
            };
            var entity4 = new Sensor
            {
                Timestamp = time.AddHours(3),
                Type = "humidity",
                Version = "v0.13",
                Value = 82
            };

            //
            // Write data
            //
            await client.GetWriteApiAsync(converter)
                .WriteMeasurementsAsync(new []{entity1, entity2, entity3, entity4}, WritePrecision.S);

            //
            // Query Data to Domain object
            //
            var queryApi = client.GetQueryApiSync(converter);

            //
            // Select ALL
            //
            var query = $"from(bucket:\"{bucket}\") " +
                        "|> range(start: 0) " +
                        "|> filter(fn: (r) => r[\"_measurement\"] == \"sensor\")" +
                        "|> pivot(rowKey:[\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")";
           
            var sensors = queryApi.QuerySync<Sensor>(query);
            //
            // Print result
            //
            sensors.ForEach(it => Console.WriteLine(it.ToString()));
        }
    }
}

Client configuration file

A client can be configured via App.config file.

The following options are supported:

Property name default description
Url - the url to connect to InfluxDB
Org - default destination organization for writes and queries
Bucket - default destination bucket for writes
Token - the token to use for the authorization
LogLevel NONE rest client verbosity level
Timeout 10000 ms The timespan to wait before the HTTP request times out
AllowHttpRedirects false Configure automatically following HTTP 3xx redirects
VerifySsl true Ignore Certificate Validation Errors when false

The Timeout supports ms, s and m as unit. Default is milliseconds.

Configuration example
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="influx2" type="InfluxDB.Client.Configurations.Influx2, InfluxDB.Client" />
    </configSections>

    <influx2 url="http://localhost:8086"
             org="my-org"
             bucket="my-bucket"
             token="my-token"
             logLevel="BODY"
             timeout="10s">
    </influx2>
</configuration>

and then:

var client = InfluxDBClientFactory.Create();

Client connection string

A client can be constructed using a connection string that can contain the InfluxDBClientOptions parameters encoded into the URL.

var client = new InfluxDBClient("http://localhost:8086?timeout=5000&logLevel=BASIC");

The following options are supported:

Property name default description
org - default destination organization for writes and queries
bucket - default destination bucket for writes
token - the token to use for the authorization
logLevel NONE rest client verbosity level
timeout 10000 ms The timespan to wait before the HTTP request times out.
allowHttpRedirects false Configure automatically following HTTP 3xx redirects
verifySsl true Ignore Certificate Validation Errors when false

The timeout supports ms, s and m as unit. Default is milliseconds.

Gzip support

InfluxDBClient does not enable gzip compress for http requests by default. If you want to enable gzip to reduce transfer data's size, you can call:

influxDBClient.EnableGzip();

How to use WebProxy

You can configure the client to tunnel requests through an HTTP proxy. The WebProxy could be configured via InfluxDBClientOptions parameter WebProxy:

var options = new InfluxDBClientOptions("http://localhost:8086")
{
    Token = "my-token",
    WebProxy = new WebProxy("http://proxyserver:80/", true)
};

var client = new InfluxDBClient(options);

Redirects configuration

Client automatically doesn't follows HTTP redirects. You can enable redirects by AllowRedirects configuration option:

var options = new InfluxDBClientOptions("http://localhost:8086")
{
    Token = "my-token",
    AllowRedirects = true
};

using var client = new InfluxDBClient(options);

⚠️ Due to a security reason Authorization header is not forwarded when redirect leads to a different domain. You can create custom Authenticator which change this behaviour - see more.

Log HTTP Request and Response

The Requests and Responses can be logged by changing the LogLevel. LogLevel values are None, Basic, Headers, Body. Note that applying the Body LogLevel will disable chunking while streaming and will load the whole response into memory.

client.SetLogLevel(LogLevel.Body)
Check the server status and version

Server availability can be checked using the influxDBClient.PingAsync() endpoint.

Version

The latest package for .NET CLI:

dotnet add package InfluxDB.Client

Or when using with Package Manager:

Install-Package InfluxDB.Client
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (30)

Showing the top 5 NuGet packages that depend on InfluxDB.Client:

Package Downloads
InfluxDB.Client.Linq

The library supports querying InfluxDB 2.x by LINQ expressions.

NBomber.Sinks.InfluxDB

NBomber sink that writes stats data to InfluxDB.

Serilog.Sinks.InfluxDB.Syslog

InfluxDB sink for Serilog with .NET standard 2.0 using syslog format for Influx 2.X

IoTSharp.HealthChecks.InfluxDB

HealthChecks.InfluxDB is the health check package for InfluxDB.

OpenTelemetry.Exporter.InfluxDB

An OpenTelemetry .NET exporter that exports to InfluxDB.

GitHub repositories (8)

Showing the top 5 popular GitHub repositories that depend on InfluxDB.Client:

Repository Stars
Xabaril/AspNetCore.Diagnostics.HealthChecks
Enterprise HealthChecks for ASP.NET Core Diagnostics Package
testcontainers/testcontainers-dotnet
A library to support tests with throwaway instances of Docker containers for all compatible .NET Standard versions.
IoTSharp/IoTSharp
IoTSharp is an open-source IoT platform for data collection, processing, visualization, and device management.
ConcreteMC/Alex
A Minecraft client written in C# aimed at compatibility with MC:Java & MC:Bedrock
melanchall/drywetmidi
.NET library to read, write, process MIDI files and to work with MIDI devices
Version Downloads Last updated
4.19.0-dev.14906 298 10/2/2024
4.19.0-dev.14897 42 10/2/2024
4.19.0-dev.14896 49 10/2/2024
4.19.0-dev.14895 62 10/2/2024
4.19.0-dev.14811 172 9/13/2024
4.18.0 49,659 9/13/2024
4.18.0-dev.14769 119 9/4/2024
4.18.0-dev.14743 68 9/3/2024
4.18.0-dev.14694 63 9/3/2024
4.18.0-dev.14693 51 9/3/2024
4.18.0-dev.14692 53 9/3/2024
4.18.0-dev.14618 64 9/2/2024
4.18.0-dev.14609 55 9/2/2024
4.18.0-dev.14592 50 9/2/2024
4.18.0-dev.14446 407 8/19/2024
4.18.0-dev.14414 165 8/12/2024
4.17.0 55,777 8/12/2024
4.17.0-dev.headers.read.1 182 7/22/2024
4.17.0-dev.14350 42 8/5/2024
4.17.0-dev.14333 41 8/5/2024
4.17.0-dev.14300 41 8/5/2024
4.17.0-dev.14291 39 8/5/2024
4.17.0-dev.14189 85 7/23/2024
4.17.0-dev.14179 57 7/22/2024
4.17.0-dev.14101 204 7/1/2024
4.17.0-dev.14100 59 7/1/2024
4.17.0-dev.14044 98 6/24/2024
4.16.0 35,793 6/24/2024
4.16.0-dev.13990 1,647 6/3/2024
4.16.0-dev.13973 59 6/3/2024
4.16.0-dev.13972 57 6/3/2024
4.16.0-dev.13963 66 6/3/2024
4.16.0-dev.13962 61 6/3/2024
4.16.0-dev.13881 59 6/3/2024
4.16.0-dev.13775 163 5/17/2024
4.16.0-dev.13702 67 5/17/2024
4.15.0 36,130 5/17/2024
4.15.0-dev.13674 82 5/14/2024
4.15.0-dev.13567 891 4/2/2024
4.15.0-dev.13558 63 4/2/2024
4.15.0-dev.13525 61 4/2/2024
4.15.0-dev.13524 65 4/2/2024
4.15.0-dev.13433 222 3/7/2024
4.15.0-dev.13432 67 3/7/2024
4.15.0-dev.13407 97 3/7/2024
4.15.0-dev.13390 65 3/7/2024
4.15.0-dev.13388 61 3/7/2024
4.15.0-dev.13282 252 3/6/2024
4.15.0-dev.13257 77 3/6/2024
4.15.0-dev.13113 1,121 2/1/2024
4.15.0-dev.13104 69 2/1/2024
4.15.0-dev.13081 69 2/1/2024
4.15.0-dev.13040 131 2/1/2024
4.15.0-dev.13039 70 2/1/2024
4.15.0-dev.12863 2,071 1/8/2024
4.15.0-dev.12846 78 1/8/2024
4.15.0-dev.12837 75 1/8/2024
4.15.0-dev.12726 2,644 12/1/2023
4.15.0-dev.12725 85 12/1/2023
4.15.0-dev.12724 78 12/1/2023
4.15.0-dev.12691 80 12/1/2023
4.15.0-dev.12658 91 12/1/2023
4.15.0-dev.12649 77 12/1/2023
4.15.0-dev.12624 79 12/1/2023
4.15.0-dev.12471 1,018 11/7/2023
4.15.0-dev.12462 81 11/7/2023
4.14.0 435,113 11/7/2023
4.14.0-dev.12437 81 11/7/2023
4.14.0-dev.12343 127 11/2/2023
4.14.0-dev.12310 82 11/2/2023
4.14.0-dev.12284 349 11/1/2023
4.14.0-dev.12235 102 11/1/2023
4.14.0-dev.12226 81 11/1/2023
4.14.0-dev.11972 5,525 8/8/2023
4.14.0-dev.11915 145 7/31/2023
4.14.0-dev.11879 162 7/28/2023
4.13.0 274,070 7/28/2023
4.13.0-dev.11854 101 7/28/2023
4.13.0-dev.11814 357 7/21/2023
4.13.0-dev.11771 148 7/19/2023
4.13.0-dev.11770 107 7/19/2023
4.13.0-dev.11728 127 7/18/2023
4.13.0-dev.11686 202 7/17/2023
4.13.0-dev.11685 90 7/17/2023
4.13.0-dev.11676 105 7/17/2023
4.13.0-dev.11479 2,017 6/27/2023
4.13.0-dev.11478 100 6/27/2023
4.13.0-dev.11477 103 6/27/2023
4.13.0-dev.11396 454 6/19/2023
4.13.0-dev.11395 92 6/19/2023
4.13.0-dev.11342 343 6/15/2023
4.13.0-dev.11330 279 6/12/2023
4.13.0-dev.11305 97 6/12/2023
4.13.0-dev.11296 99 6/12/2023
4.13.0-dev.11217 371 6/6/2023
4.13.0-dev.11089 290 5/30/2023
4.13.0-dev.11064 121 5/30/2023
4.13.0-dev.10998 160 5/29/2023
4.13.0-dev.10989 115 5/29/2023
4.13.0-dev.10871 871 5/8/2023
4.13.0-dev.10870 93 5/8/2023
4.13.0-dev.10819 272 4/28/2023
4.12.0 172,749 4/28/2023
4.12.0-dev.10777 132 4/27/2023
4.12.0-dev.10768 113 4/27/2023
4.12.0-dev.10759 107 4/27/2023
4.12.0-dev.10742 90 4/27/2023
4.12.0-dev.10685 101 4/27/2023
4.12.0-dev.10684 103 4/27/2023
4.12.0-dev.10643 110 4/27/2023
4.12.0-dev.10642 96 4/27/2023
4.12.0-dev.10569 97 4/27/2023
4.12.0-dev.10193 1,742 2/23/2023
4.11.0 111,930 2/23/2023
4.11.0-dev.10176 178 2/23/2023
4.11.0-dev.10059 3,142 1/26/2023
4.10.0 69,025 1/26/2023
4.10.0-dev.10033 143 1/25/2023
4.10.0-dev.10032 120 1/25/2023
4.10.0-dev.10031 133 1/25/2023
4.10.0-dev.9936 3,567 12/26/2022
4.10.0-dev.9935 140 12/26/2022
4.10.0-dev.9881 179 12/21/2022
4.10.0-dev.9880 119 12/21/2022
4.10.0-dev.9818 610 12/16/2022
4.10.0-dev.9773 288 12/12/2022
4.10.0-dev.9756 116 12/12/2022
4.10.0-dev.9693 362 12/6/2022
4.9.0 191,086 12/6/2022
4.9.0-dev.9684 110 12/6/2022
4.9.0-dev.9666 122 12/6/2022
4.9.0-dev.9617 137 12/6/2022
4.9.0-dev.9478 202 12/5/2022
4.9.0-dev.9469 129 12/5/2022
4.9.0-dev.9444 102 12/5/2022
4.9.0-dev.9411 122 12/5/2022
4.9.0-dev.9350 158 12/1/2022
4.8.0 5,572 12/1/2022
4.8.0-dev.9324 202 11/30/2022
4.8.0-dev.9232 182 11/28/2022
4.8.0-dev.9223 120 11/28/2022
4.8.0-dev.9222 116 11/28/2022
4.8.0-dev.9117 404 11/21/2022
4.8.0-dev.9108 122 11/21/2022
4.8.0-dev.9099 122 11/21/2022
4.8.0-dev.9029 194 11/16/2022
4.8.0-dev.8971 124 11/15/2022
4.8.0-dev.8961 128 11/14/2022
4.8.0-dev.8928 134 11/14/2022
4.8.0-dev.8899 132 11/14/2022
4.8.0-dev.8898 142 11/14/2022
4.8.0-dev.8839 131 11/14/2022
4.8.0-dev.8740 243 11/7/2022
4.8.0-dev.8725 120 11/7/2022
4.8.0-dev.8648 362 11/3/2022
4.7.0 102,419 11/3/2022
4.7.0-dev.8625 268 11/2/2022
4.7.0-dev.8594 281 10/31/2022
4.7.0-dev.8579 118 10/31/2022
4.7.0-dev.8557 108 10/31/2022
4.7.0-dev.8540 126 10/31/2022
4.7.0-dev.8518 119 10/31/2022
4.7.0-dev.8517 118 10/31/2022
4.7.0-dev.8509 115 10/31/2022
4.7.0-dev.8377 814 10/26/2022
4.7.0-dev.8360 134 10/25/2022
4.7.0-dev.8350 176 10/24/2022
4.7.0-dev.8335 130 10/24/2022
4.7.0-dev.8334 127 10/24/2022
4.7.0-dev.8223 221 10/19/2022
4.7.0-dev.8178 241 10/17/2022
4.7.0-dev.8170 122 10/17/2022
4.7.0-dev.8148 128 10/17/2022
4.7.0-dev.8133 118 10/17/2022
4.7.0-dev.8097 111 10/17/2022
4.7.0-dev.8034 945 10/11/2022
4.7.0-dev.8025 147 10/11/2022
4.7.0-dev.8009 199 10/10/2022
4.7.0-dev.8001 136 10/10/2022
4.7.0-dev.7959 203 10/4/2022
4.7.0-dev.7905 329 9/30/2022
4.7.0-dev.7875 174 9/29/2022
4.6.0 47,853 9/29/2022
4.6.0-dev.7832 168 9/29/2022
4.6.0-dev.7817 132 9/29/2022
4.6.0-dev.7779 192 9/27/2022
4.6.0-dev.7778 139 9/27/2022
4.6.0-dev.7734 160 9/26/2022
4.6.0-dev.7733 129 9/26/2022
4.6.0-dev.7677 237 9/20/2022
4.6.0-dev.7650 229 9/16/2022
4.6.0-dev.7626 202 9/14/2022
4.6.0-dev.7618 184 9/14/2022
4.6.0-dev.7574 133 9/13/2022
4.6.0-dev.7572 116 9/13/2022
4.6.0-dev.7528 266 9/12/2022
4.6.0-dev.7502 161 9/9/2022
4.6.0-dev.7479 191 9/8/2022
4.6.0-dev.7471 136 9/8/2022
4.6.0-dev.7447 192 9/7/2022
4.6.0-dev.7425 129 9/7/2022
4.6.0-dev.7395 154 9/6/2022
4.6.0-dev.7344 334 8/31/2022
4.6.0-dev.7329 117 8/31/2022
4.6.0-dev.7292 132 8/30/2022
4.6.0-dev.7240 316 8/29/2022
4.5.0 63,688 8/29/2022
4.5.0-dev.7216 146 8/27/2022
4.5.0-dev.7147 304 8/22/2022
4.5.0-dev.7134 342 8/17/2022
4.5.0-dev.7096 180 8/15/2022
4.5.0-dev.7070 277 8/11/2022
4.5.0-dev.7040 190 8/10/2022
4.5.0-dev.7011 240 8/3/2022
4.5.0-dev.6987 146 8/1/2022
4.5.0-dev.6962 158 7/29/2022
4.4.0 49,457 7/29/2022
4.4.0-dev.6901 339 7/25/2022
4.4.0-dev.6843 379 7/19/2022
4.4.0-dev.6804 144 7/19/2022
4.4.0-dev.6789 136 7/19/2022
4.4.0-dev.6760 134 7/19/2022
4.4.0-dev.6705 223 7/14/2022
4.4.0-dev.6663 1,119 6/24/2022
4.4.0-dev.6655 155 6/24/2022
4.3.0 175,311 6/24/2022
4.3.0-dev.multiple.buckets3 292 6/21/2022
4.3.0-dev.multiple.buckets2 266 6/17/2022
4.3.0-dev.multiple.buckets1 135 6/17/2022
4.3.0-dev.6631 146 6/22/2022
4.3.0-dev.6623 131 6/22/2022
4.3.0-dev.6374 457 6/13/2022
4.3.0-dev.6286 989 5/20/2022
4.2.0 71,721 5/20/2022
4.2.0-dev.6257 610 5/13/2022
4.2.0-dev.6248 148 5/12/2022
4.2.0-dev.6233 237 5/12/2022
4.2.0-dev.6194 244 5/10/2022
4.2.0-dev.6193 159 5/10/2022
4.2.0-dev.6158 3,055 5/6/2022
4.2.0-dev.6135 200 5/6/2022
4.2.0-dev.6091 530 4/28/2022
4.2.0-dev.6048 169 4/28/2022
4.2.0-dev.6047 148 4/28/2022
4.2.0-dev.5966 499 4/25/2022
4.2.0-dev.5938 396 4/19/2022
4.1.0 47,151 4/19/2022
4.1.0-dev.5910 361 4/13/2022
4.1.0-dev.5888 157 4/13/2022
4.1.0-dev.5887 163 4/13/2022
4.1.0-dev.5794 853 4/6/2022
4.1.0-dev.5725 571 3/18/2022
4.0.0 59,068 3/18/2022
4.0.0-rc3 992 3/4/2022
4.0.0-rc2 719 2/25/2022
4.0.0-rc1 2,200 2/18/2022
4.0.0-dev.5709 154 3/18/2022
4.0.0-dev.5684 166 3/15/2022
4.0.0-dev.5630 151 3/4/2022
4.0.0-dev.5607 161 3/3/2022
4.0.0-dev.5579 166 2/25/2022
4.0.0-dev.5556 164 2/24/2022
4.0.0-dev.5555 160 2/24/2022
4.0.0-dev.5497 165 2/23/2022
4.0.0-dev.5489 151 2/23/2022
4.0.0-dev.5460 158 2/23/2022
4.0.0-dev.5444 163 2/22/2022
4.0.0-dev.5333 177 2/17/2022
4.0.0-dev.5303 169 2/16/2022
4.0.0-dev.5280 163 2/16/2022
4.0.0-dev.5279 161 2/16/2022
4.0.0-dev.5241 346 2/15/2022
4.0.0-dev.5225 169 2/15/2022
4.0.0-dev.5217 151 2/15/2022
4.0.0-dev.5209 153 2/15/2022
4.0.0-dev.5200 168 2/14/2022
4.0.0-dev.5188 716 2/10/2022
4.0.0-dev.5180 378 2/10/2022
4.0.0-dev.5172 378 2/10/2022
4.0.0-dev.5130 386 2/10/2022
4.0.0-dev.5122 395 2/9/2022
4.0.0-dev.5103 393 2/9/2022
4.0.0-dev.5097 392 2/9/2022
4.0.0-dev.5091 372 2/9/2022
4.0.0-dev.5084 366 2/8/2022
3.4.0-dev.5263 165 2/15/2022
3.4.0-dev.4986 400 2/7/2022
3.4.0-dev.4968 429 2/4/2022
3.3.0 145,525 2/4/2022
3.3.0-dev.4889 422 2/3/2022
3.3.0-dev.4865 419 2/1/2022
3.3.0-dev.4823 332 1/19/2022
3.3.0-dev.4691 1,180 1/7/2022
3.3.0-dev.4557 2,218 11/26/2021
3.2.0 97,029 11/26/2021
3.2.0-dev.4533 5,081 11/24/2021
3.2.0-dev.4484 366 11/11/2021
3.2.0-dev.4475 227 11/10/2021
3.2.0-dev.4387 292 10/26/2021
3.2.0-dev.4363 254 10/22/2021
3.2.0-dev.4356 202 10/22/2021
3.1.0 94,631 10/22/2021
3.1.0-dev.4303 449 10/18/2021
3.1.0-dev.4293 226 10/15/2021
3.1.0-dev.4286 207 10/15/2021
3.1.0-dev.4240 261 10/12/2021
3.1.0-dev.4202 217 10/11/2021
3.1.0-dev.4183 227 10/11/2021
3.1.0-dev.4131 201 10/8/2021
3.1.0-dev.3999 223 10/5/2021
3.1.0-dev.3841 336 9/29/2021
3.1.0-dev.3798 416 9/17/2021
3.0.0 60,791 9/17/2021
3.0.0-dev.3726 2,548 8/31/2021
3.0.0-dev.3719 180 8/31/2021
3.0.0-dev.3671 428 8/20/2021
2.2.0-dev.3652 185 8/20/2021
2.1.0 283,314 8/20/2021
2.1.0-dev.3605 224 8/17/2021
2.1.0-dev.3584 537 8/16/2021
2.1.0-dev.3558 190 8/16/2021
2.1.0-dev.3527 329 7/29/2021
2.1.0-dev.3519 249 7/29/2021
2.1.0-dev.3490 319 7/20/2021
2.1.0-dev.3445 274 7/12/2021
2.1.0-dev.3434 259 7/9/2021
2.0.0 65,937 7/9/2021
2.0.0-dev.3401 7,624 6/25/2021
2.0.0-dev.3368 260 6/23/2021
2.0.0-dev.3361 238 6/23/2021
2.0.0-dev.3330 270 6/17/2021
2.0.0-dev.3291 258 6/16/2021
1.20.0-dev.3218 533 6/4/2021
1.19.0 133,454 6/4/2021
1.19.0-dev.3204 227 6/3/2021
1.19.0-dev.3160 218 6/2/2021
1.19.0-dev.3159 189 6/2/2021
1.19.0-dev.3084 2,513 5/7/2021
1.19.0-dev.3051 269 5/5/2021
1.19.0-dev.3044 223 5/5/2021
1.19.0-dev.3008 258 4/30/2021
1.18.0 36,201 4/30/2021
1.18.0-dev.2973 248 4/27/2021
1.18.0-dev.2930 1,203 4/16/2021
1.18.0-dev.2919 244 4/13/2021
1.18.0-dev.2893 243 4/12/2021
1.18.0-dev.2880 211 4/12/2021
1.18.0-dev.2856 241 4/7/2021
1.18.0-dev.2830 1,842 4/1/2021
1.18.0-dev.2816 205 4/1/2021
1.17.0 46,279 4/1/2021
1.17.0-dev.linq.17 884 3/18/2021
1.17.0-dev.linq.16 254 3/16/2021
1.17.0-dev.linq.15 236 3/15/2021
1.17.0-dev.linq.14 252 3/12/2021
1.17.0-dev.linq.13 287 3/11/2021
1.17.0-dev.linq.12 209 3/10/2021
1.17.0-dev.linq.11 255 3/8/2021
1.17.0-dev.2776 225 3/26/2021
1.17.0-dev.2713 192 3/25/2021
1.17.0-dev.2707 195 3/25/2021
1.17.0-dev.2652 254 3/19/2021
1.17.0-dev.2619 192 3/18/2021
1.17.0-dev.2566 195 3/16/2021
1.17.0-dev.2549 201 3/15/2021
1.17.0-dev.2505 236 3/12/2021
1.17.0-dev.2446 221 3/11/2021
1.17.0-dev.2402 217 3/8/2021
1.17.0-dev.2371 214 3/5/2021
1.16.0 19,352 3/5/2021
1.16.0-dev.linq.10 1,647 2/4/2021
1.16.0-dev.linq.9 233 2/4/2021
1.16.0-dev.2359 247 3/4/2021
1.16.0-dev.2273 207 2/12/2021
1.16.0-dev.2255 213 2/11/2021
1.16.0-dev.2228 222 2/5/2021
1.16.0-dev.2147 254 1/29/2021
1.15.0 32,782 1/29/2021
1.15.0-dev.linq.8 218 1/28/2021
1.15.0-dev.linq.7 208 1/27/2021
1.15.0-dev.linq.6 279 1/20/2021
1.15.0-dev.linq.5 257 1/19/2021
1.15.0-dev.linq.4 392 1/15/2021
1.15.0-dev.linq.3 207 1/14/2021
1.15.0-dev.linq.2 220 1/13/2021
1.15.0-dev.linq.1 236 1/12/2021
1.15.0-dev.2135 210 1/28/2021
1.15.0-dev.2009 218 1/19/2021
1.15.0-dev.1793 227 1/11/2021
1.15.0-dev.1753 263 1/7/2021
1.15.0-dev.1752 251 1/7/2021
1.15.0-dev.1705 870 12/16/2020
1.15.0-dev.1677 575 12/4/2020
1.14.0 45,681 12/4/2020
1.14.0-dev.1665 267 12/3/2020
1.14.0-dev.1648 268 12/2/2020
1.14.0-dev.1632 329 11/27/2020
1.14.0-dev.1577 462 10/30/2020
1.14.0-dev.1571 325 10/30/2020
1.13.0 15,164 10/30/2020
1.13.0-dev.1545 415 10/15/2020
1.13.0-dev.1516 475 10/8/2020
1.13.0-dev.1489 578 10/2/2020
1.13.0-dev.1478 315 10/2/2020
1.12.0 37,187 10/2/2020
1.12.0-dev.1466 261 10/1/2020
1.12.0-dev.1421 562 9/23/2020
1.12.0-dev.1345 328 9/18/2020
1.12.0-dev.1306 331 9/15/2020
1.12.0-dev.1251 342 9/2/2020
1.12.0-dev.1216 1,953 8/14/2020
1.11.0 24,294 8/14/2020
1.11.0-dev.1205 299 8/14/2020
1.11.0-dev.1185 299 8/10/2020
1.11.0-dev.1166 353 7/28/2020
1.11.0-dev.1150 299 7/28/2020
1.11.0-dev.1144 314 7/28/2020
1.11.0-dev.1125 296 7/20/2020
1.11.0-dev.1111 295 7/17/2020
1.10.0 17,128 7/17/2020
1.10.0-dev.1098 283 7/15/2020
1.10.0-dev.1077 395 7/10/2020
1.10.0-dev.1049 409 6/29/2020
1.10.0-dev.1022 326 6/23/2020
1.10.0-dev.1021 311 6/23/2020
1.10.0-dev.990 312 6/19/2020
1.9.0 20,719 6/19/2020
1.9.0-dev.984 328 6/19/2020
1.9.0-dev.971 285 6/17/2020
1.9.0-dev.955 288 6/17/2020
1.9.0-dev.886 309 6/10/2020
1.9.0-dev.848 329 6/8/2020
1.9.0-dev.842 283 6/8/2020
1.9.0-dev.836 285 6/8/2020
1.9.0-dev.786 1,260 5/27/2020
1.9.0-dev.762 594 5/15/2020
1.8.0 18,550 5/15/2020
1.8.0-dev.748 301 5/12/2020
1.8.0-dev.669 555 4/22/2020
1.8.0-dev.668 290 4/21/2020
1.8.0-dev.661 287 4/20/2020
1.8.0-dev.650 285 4/20/2020
1.8.0-dev.639 299 4/20/2020
1.8.0-dev.620 288 4/17/2020
1.7.0 14,542 4/17/2020
1.7.0-dev.608 322 4/16/2020
1.7.0-dev.574 288 4/14/2020
1.7.0-dev.563 287 4/14/2020
1.7.0-dev.534 303 4/6/2020
1.7.0-dev.528 302 4/6/2020
1.7.0-dev.512 340 4/3/2020
1.7.0-dev.495 307 3/30/2020
1.7.0-dev.469 1,154 3/13/2020
1.6.0 2,929 3/13/2020
1.6.0-dev.458 328 3/13/2020
1.6.0-dev.443 321 3/9/2020
1.6.0-dev.422 331 2/28/2020
1.6.0-dev.410 335 2/27/2020
1.6.0-dev.404 337 2/27/2020
1.6.0-dev.356 331 2/14/2020
1.5.0 1,567 2/14/2020
1.5.0-dev.349 310 2/14/2020
1.5.0-dev.341 313 2/12/2020
1.5.0-dev.312 325 1/22/2020
1.4.0 4,057 1/17/2020
1.3.0 2,034 12/6/2019
1.2.0 6,193 11/8/2019
1.1.0 939 10/11/2019
1.0.0 3,202 8/23/2019