diff --git a/README-CN.md b/README-CN.md index 79c2427..e8a12c1 100644 --- a/README-CN.md +++ b/README-CN.md @@ -1,74 +1,14 @@ -# C# 连接器 +# 介绍 -[English edition](./README.md) +| Github Action Tests | CodeCov | +|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![actions](https://github.com/taosdata/taos-connector/actions/workflows/linux.yml/badge.svg) | [![codecov](https://codecov.io/gh/taosdata/taos-connector-dotnet/graph/badge.svg?token=U30JZYDGMS)](https://codecov.io/gh/taosdata/taos-connector-dotnet) | -`TDengine.Connector` 是 TDengine 提供的 C# 语言连接器。C# 开发人员可以通过它开发存取 TDengine 集群数据的 C# 应用软件。 - -`TDengine.Connector` 连接器支持通过 TDengine 客户端驱动(taosc)建立与 TDengine 运行实例的连接,提供数据写入、查询、数据订阅、schemaless 数据写入、参数绑定接口数据写入等功能。 `TDengine.Connector` 自 v3.0.1 起还支持 WebSocket 连接,提供数据写入、查询、参数绑定接口数据写入等功能。 - -本文介绍如何在 Linux 或 Windows 环境中安装 `TDengine.Connector`,并通过 `TDengine.Connector` 连接 TDengine 集群,进行数据写入、查询等基本操作。 - -**注意**: - -* `TDengine.Connector` 3.x 不兼容 TDengine 2.x,如果在运行 TDengine 2.x 版本的环境下需要使用 C# 连接器请使用 TDengine.Connector 的 1.x 版本 。 -* `TDengine.Connector` 3.1.0 版本进行了完整的重构,不再兼容 3.0.2 及以前版本。3.0.2 文档请参考 [nuget](https://www.nuget.org/packages/TDengine.Connector/3.0.2) - -`TDengine.Connector` 的源码托管在 [GitHub](https://github.com/taosdata/taos-connector-dotnet/tree/3.0)。 - -## 支持的平台 - -支持的平台和 TDengine 客户端驱动支持的平台一致。 - -**注意** TDengine 不再支持 32 位 Windows 平台。 - -## 版本支持 +[English](README.md) | 简体中文 -| **Connector 版本** | **TDengine 版本** | **主要功能** | -|------------------|--------------------------|------------------------------| -| 3.1.5 | 3.3.2.0 及以上/3.1.2.0 及以上 | 修复 websocket sql 包含中文时长度计算错误 | -| 3.1.4 | 3.3.2.0 及以上/3.1.2.0 及以上 | 提升 websocket 查询和写入性能 | -| 3.1.3 | 3.2.1.0 及以上/3.1.1.18 及以上 | 支持 WebSocket 自动重连 | -| 3.1.2 | 3.2.1.0 及以上/3.1.1.18 及以上 | 修复 schemaless 资源释放 | -| 3.1.1 | 3.2.1.0 及以上/3.1.1.18 及以上 | 支持 varbinary 和 geometry 类型 | -| 3.1.0 | 3.2.1.0 及以上/3.1.1.18 及以上 | WebSocket 使用原生实现 | - -## 处理异常 - -`TDengine.Connector` 会抛出异常,应用程序需要处理异常。taosc 异常类型 `TDengineError`,包含错误码和错误信息,应用程序可以根据错误码和错误信息进行处理。 - -## TDengine DataType 和 C# DataType - -| TDengine DataType | C# Type | -|-------------------|------------------| -| TIMESTAMP | DateTime | -| TINYINT | sbyte | -| SMALLINT | short | -| INT | int | -| BIGINT | long | -| TINYINT UNSIGNED | byte | -| SMALLINT UNSIGNED | ushort | -| INT UNSIGNED | uint | -| BIGINT UNSIGNED | ulong | -| FLOAT | float | -| DOUBLE | double | -| BOOL | bool | -| BINARY | byte[] | -| NCHAR | string (utf-8编码) | -| JSON | byte[] | -| VARBINARY | byte[] | -| GEOMETRY | byte[] | - -**注意**:JSON 类型仅在 tag 中支持。 - -## 安装步骤 - -### 安装前准备 - -* 安装 [.NET SDK](https://dotnet.microsoft.com/download) -* [Nuget 客户端](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools) (可选安装) -* 安装 TDengine 客户端驱动,具体步骤请参考[安装客户端驱动](https://docs.taosdata.com/develop/connect/#%E5%AE%89%E8%A3%85%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%A9%B1%E5%8A%A8-taosc) +`TDengine.Connector` 是 TDengine 提供的 C# 语言连接器。C# 开发人员可以通过它开发存取 TDengine 集群数据的 C# 应用软件。 -### 安装连接器 +# 获取驱动 可以在当前 .NET 项目的路径下,通过 dotnet CLI 添加 Nuget package `TDengine.Connector` 到当前项目。 @@ -84,1056 +24,36 @@ dotnet add package TDengine.Connector ``` -## 建立连接 - -Native 连接 - -``` csharp -var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - -WebSocket 连接 - -```csharp -var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - -ConnectionStringBuilder 支持的参数如下: -* protocol: 连接协议,可选值为 Native 或 WebSocket,默认为 Native -* host: TDengine 或 taosadapter 运行实例的地址 -* port: TDengine 或 taosadapter 运行实例的端口 - * 当 protocol 为 WebSocket 时 useSSL 为 false 时,port 默认为 6041 - * 当 protocol 为 WebSocket 时 useSSL 为 true 时,port 默认为 443 -* useSSL: 是否使用 SSL 连接,仅当 protocol 为 WebSocket 时有效,默认为 false -* token: 连接 TDengine cloud 的 token,仅当 protocol 为 WebSocket 时有效 -* username: 连接 TDengine 的用户名 -* password: 连接 TDengine 的密码 -* db: 连接 TDengine 的数据库 -* timezone: 解析时间结果的时区,默认为 `TimeZoneInfo.Local`,使用 `TimeZoneInfo.FindSystemTimeZoneById` 方法解析字符串为 `TimeZoneInfo` 对象。 -* connTimeout: WebSocket 连接超时时间,仅当 protocol 为 WebSocket 时有效,默认为 1 分钟,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* readTimeout: WebSocket 读超时时间,仅当 protocol 为 WebSocket 时有效,默认为 5 分钟,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* writeTimeout: WebSocket 写超时时间,仅当 protocol 为 WebSocket 时有效,默认为 10 秒,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* enableCompression: 是否启用 WebSocket 压缩(dotnet 版本 6 及以上,连接器版本 3.1.1 及以上生效),默认为 false -* autoReconnect: 是否自动重连(连接器版本 3.1.3 及以上生效),默认为 false -* reconnectRetryCount: 重连次数(连接器版本 3.1.3 及以上生效),默认为 3 -* reconnectIntervalMs: 重连间隔时间(连接器版本 3.1.3 及以上生效),默认为 2000 - -### 指定 URL 和 Properties 获取连接 - -C# 连接器不支持此功能 - -### 配置参数的优先级 - -C# 连接器不支持此功能 - -## 使用示例 - -### 创建数据库和表 - -Native 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### 插入数据 - -Native 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### 查询数据 - -Native 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### 执行带有 reqId 的 SQL - -Native 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### 通过参数绑定写入数据 - -Native 样例 - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeStmt -{ - internal abstract class NativeStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSStmt -{ - internal abstract class WSStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - -注意:使用 BindRow 需要注意原始 C# 列类型与 TDengine 列类型的需要一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 - -### 无模式写入 - -Native 样例 - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - -### 执行带有 reqId 的无模式写入 - -```csharp -public void SchemalessInsert(string[] lines, TDengineSchemalessProtocol protocol, - TDengineSchemalessPrecision precision, - int ttl, long reqId) -``` - -### 数据订阅 - -#### 创建 Topic - -Native 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -#### 创建 Consumer - -Native 样例 - -```csharp -var cfg = new Dictionary() -{ - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - -WebSocket 样例 - -```csharp -var cfg = new Dictionary() -{ - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port", "6041" }, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - -consumer 支持的配置参数如下: -* td.connect.type: 连接类型,可选值为 Native 或 WebSocket,默认为 Native -* td.connect.ip: TDengine 或 taosadapter 运行实例的地址 -* td.connect.port: TDengine 或 taosadapter 运行实例的端口 - * 当 td.connect.type 为 WebSocket 且 useSSL 为 false 时,td.connect.port 默认为 6041 - * 当 td.connect.type 为 WebSocket 且 useSSL 为 true 时,td.connect.port 默认为 443 -* useSSL: 是否使用 SSL 连接,仅当 td.connect.type 为 WebSocket 时有效,默认为 false -* token: 连接 TDengine cloud 的 token,仅当 td.connect.type 为 WebSocket 时有效 -* td.connect.user: 连接 TDengine 的用户名 -* td.connect.pass: 连接 TDengine 的密码 -* group.id: 消费者组 ID -* client.id: 消费者 ID -* enable.auto.commit: 是否自动提交 offset,默认为 true -* auto.commit.interval.ms: 自动提交 offset 的间隔时间,默认为 5000 毫秒 -* auto.offset.reset: 当 offset 不存在时,从哪里开始消费,可选值为 earliest 或 latest,默认为 latest -* msg.with.table.name: 消息是否包含表名 -* ws.message.enableCompression: 是否启用 WebSocket 压缩(dotnet 版本 6 及以上,连接器版本 3.1.1 及以上生效),默认为 false -* ws.autoReconnect: 是否自动重连(连接器版本 3.1.3 及以上生效),默认为 false -* ws.reconnect.retry.count: 重连次数(连接器版本 3.1.3 及以上生效),默认为 3 -* ws.reconnect.interval.ms: 重连间隔时间(连接器版本 3.1.3 及以上生效),默认为 2000 +# 文档 -支持订阅结果集 `Dictionary` key 为列名,value 为列值。 +- 开发示例请见[开发指南](https://docs.taosdata.com/develop/) +- 版本历史、TDengine 对应版本以及 API 说明请见[参考手册](https://docs.taosdata.com/reference/connector/csharp/) -如果使用 object 接收列值,需要注意: -* 原始 C# 列类型与 TDengine 列类型的需要一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 -* 列名与 class 属性名一致,并可读写。 -* 明确设置 value 解析器`ConsumerBuilder.SetValueDeserializer(new ReferenceDeserializer());` +# 贡献 -样例如下 +鼓励每个人帮助改进这个项目,以下是这个项目的开发测试流程: -结果 class +## 前置条件 -```csharp - class Result - { - public DateTime ts { get; set; } - public float current { get; set; } - public int voltage { get; set; } - public float phase { get; set; } - } -``` - -设置解析器 - -```csharp -var tmqBuilder = new ConsumerBuilder(cfg); -tmqBuilder.SetValueDeserializer(new ReferenceDeserializer()); -var consumer = tmqBuilder.Build(); -``` - -也可实现自定义解析器,实现 `IDeserializer` 接口并通过`ConsumerBuilder.SetValueDeserializer`方法传入。 - -```csharp - public interface IDeserializer - { - T Deserialize(ITMQRows data, bool isNull, SerializationContext context); - } -``` - -#### 订阅消费数据 - -```csharp -consumer.Subscribe(new List() { "topic_meters" }); -while (true) -{ - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } -} -``` - -#### 指定订阅 Offset - -```csharp -consumer.Assignment.ForEach(a => -{ - Console.WriteLine($"{a}, seek to 0"); - consumer.Seek(new TopicPartitionOffset(a.Topic, a.Partition, 0)); - Thread.Sleep(TimeSpan.FromSeconds(1)); -}); -``` - -#### 提交 Offset - -```csharp -public void Commit(ConsumeResult consumerResult) -public List Commit() -public void Commit(IEnumerable offsets) -``` - -#### 关闭订阅 - -```csharp -consumer.Unsubscribe(); -consumer.Close(); -``` - -#### 完整示例 - -Native 样例 - -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` - -WebSocket 样例 - -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; - -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port", "6041" }, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` - -### ADO.NET - -C# 连接器支持 ADO.NET 接口,可以通过 ADO.NET 接口连接 TDengine 运行实例,进行数据写入、查询等操作。 - -Native 样例 +* 安装 [.NET SDK](https://dotnet.microsoft.com/download) +* [Nuget 客户端](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools) (可选安装) +* 安装 TDengine 客户端驱动,具体步骤请参考[安装客户端驱动](https://docs.taosdata.com/develop/connect/#%E5%AE%89%E8%A3%85%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%A9%B1%E5%8A%A8-taosc) -```csharp -using System; -using TDengine.Data.Client; +## 构建 -namespace NativeADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "host=localhost;port=6030;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` +1. `dotnet restore` 还原项目依赖。 +2. `dotnet build --no-restore` 构建项目。 -WebSocket 样例 +## 测试 -```csharp -using System; -using TDengine.Data.Client; +1. 执行测试前确保已经安装 TDengine 服务端,并且已经启动 taosd 与 taosAdapter,数据库干净无数据 +2. 项目目录下执行 `dotnet test` 运行测试,测试会连接到本地的 TDengine 服务器与 taosAdapter 进行测试 -namespace WSADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` +# 引用 -* 连接参数与[建立连接](#建立连接)中的连接参数一致。 -* TDengineParameter 的 name 需要以 @ 开头,如 @0、@1、@2 等,value 需要 C# 列类型与 TDengine - 列类型一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 +- [TDengine 官网](https://www.taosdata.com/) +- [TDengine GitHub](https://github.com/taosdata/TDengine) -### 更多示例程序 +# 许可证 -[示例程序](https://github.com/taosdata/taos-connector-dotnet/tree/3.0/examples) \ No newline at end of file +[MIT License](./LICENSE) \ No newline at end of file diff --git a/README.md b/README.md index d5de295..aefb51f 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,14 @@ -# C# Connector +# Introduction -[中文版](./README-CN.md) +| Github Action Tests | CodeCov | +|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![actions](https://github.com/taosdata/taos-connector/actions/workflows/linux.yml/badge.svg) | [![codecov](https://codecov.io/gh/taosdata/taos-connector-dotnet/graph/badge.svg?token=U30JZYDGMS)](https://codecov.io/gh/taosdata/taos-connector-dotnet) | -`TDengine.Connector` is the C# language connector provided by TDengine. C# developers can use it to develop C# application software that accesses TDengine cluster data. - -The `TDengine.Connector` connector supports establishing a connection with the TDengine running instance through the TDengine client driver (taosc), and provides functions such as data writing, query, data subscription, schemaless data writing, and parameter binding interface data writing. `TDengine.Connector` also supports WebSocket since v3.0.1, establishes WebSocket connection, and provides functions such as data writing, query, and parameter binding interface data writing. - -This article introduces how to install `TDengine.Connector` in a Linux or Windows environment, and connect to the TDengine cluster through `TDengine.Connector` to perform basic operations such as data writing and querying. - -**Notice**: - -* `TDengine.Connector` 3.x is not compatible with TDengine 2.x. If you need to use the C# connector in an environment running TDengine 2.x version, please use the 1.x version of TDengine.Connector. -* `TDengine.Connector` version 3.1.0 has been completely refactored and is no longer compatible with 3.0.2 and previous versions. For 3.0.2 documents, please refer to [nuget](https://www.nuget.org/packages/TDengine.Connector/3.0.2) - -The source code of `TDengine.Connector` is hosted on [GitHub](https://github.com/taosdata/taos-connector-dotnet/tree/3.0). - -## Supported platforms - -The supported platforms are the same as those supported by the TDengine client driver. - -Note TDengine no longer supports 32-bit Windows platforms. - -## Version support - -| **Connector version** | **TDengine version** | **major features** | -|-----------------------|--------------------------------------|----------------------------------------------------------------------| -| 3.1.5 | 3.3.2.0 and above/3.1.2.0 and above | fix the length calculation error when WebSocket sql contains Chinese | -| 3.1.4 | 3.3.2.0 and above/3.1.2.0 and above | WebSocket performance improvements | -| 3.1.3 | 3.2.1.0 and above/3.1.1.18 and above | support Websocket reconnect | -| 3.1.2 | 3.2.1.0 and above/3.1.1.18 and above | fix schemaless result release | -| 3.1.1 | 3.2.1.0 and above/3.1.1.18 and above | support varbinary and geometry | -| 3.1.0 | 3.2.1.0 and above/3.1.1.18 and above | WebSocket uses native implementation | - -## Handling exceptions - -`TDengine.Connector` will throw an exception and the application needs to handle the exception. The taosc exception type `TDengineError` contains error code and error information, and the application can handle it based on the error code and error information. - -## TDengine DataType vs. C# DataType - -| TDengine DataType | C# Type | -|-------------------|-------------------------| -| TIMESTAMP | DateTime | -| TINYINT | sbyte | -| SMALLINT | short | -| INT | int | -| BIGINT | long | -| TINYINT UNSIGNED | byte | -| SMALLINT UNSIGNED | ushort | -| INT UNSIGNED | uint | -| BIGINT UNSIGNED | ulong | -| FLOAT | float | -| DOUBLE | double | -| BOOL | bool | -| BINARY | byte[] | -| NCHAR | string (utf-8 encoding) | -| JSON | byte[] | -| VARBINARY | byte[] | -| GEOMETRY | byte[] | - -**Note**: JSON type is only supported in tag. - -## Installation Steps - -### Pre-installation preparation +English | [简体中文](README-CN.md) -* Install [.NET SDK](https://dotnet.microsoft.com/download) -* [Nuget Client](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools) (optional installation) -* Install the TDengine client driver. For specific steps, please refer to [Installing the client driver](https://docs.tdengine.com/develop/connect/#install-client-driver-taosc) +`TDengine.Connector` is the C# language connector provided by TDengine. C# developers can use it to develop C# application software that accesses TDengine cluster data. -### Install the connectors +# Get the Driver Nuget package `TDengine.Connector` can be added to the current project through dotnet CLI under the path of the current .NET project. @@ -84,1057 +24,40 @@ You can also modify the `.csproj` file of the current project and add the follow ``` -## Establishing a connection - -Native connection - -``` csharp -var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - -WebSocket connection - -```csharp -var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - -The parameters supported by `ConnectionStringBuilder` are as follows: -* protocol: connection protocol, optional value is Native or WebSocket, default is Native -* host: the address of the running instance of TDengine or taosadapter, -* port: The port of the running instance of TDengine or taosadapter. - * When using WebSocket without SSL, the default is 6041. - * When using WebSocket with SSL, the default is 443. -* useSSL: Whether to use SSL, the default is false, only valid when the protocol is WebSocket -* token: The token used to connect to TDengine Cloud, only valid when the protocol is WebSocket -* username: username to connect to TDengine -* password: password to connect to TDengine -* db: database connected to TDengine -* timezone: The time zone for parsing time results, the default is `TimeZoneInfo.Local`, use the `TimeZoneInfo.FindSystemTimeZoneById` method to parse the string into a `TimeZoneInfo` object. -* connTimeout: WebSocket connection timeout, only valid when the protocol is WebSocket, the default is 1 minute, use the `TimeSpan.Parse` method to parse the string into a `TimeSpan` object. -* readTimeout: WebSocket read timeout, only valid when the protocol is WebSocket, the default is 5 minutes, use the `TimeSpan.Parse` method to parse the string into a `TimeSpan` object. -* writeTimeout: WebSocket write timeout, only valid when the protocol is WebSocket, the default is 10 seconds, use the `TimeSpan.Parse` method to parse the string into a `TimeSpan` object. -* enableCompression: Whether to enable WebSocket compression (effective for dotnet version 6 and above, connector version 3.1.1 and above). The default is false. -* autoReconnect: Whether to enable WebSocket reconnect (connector version 3.1.3 and above). The default is false. -* reconnectRetryCount: The number of reconnection retries (connector version 3.1.3 and above). The default is 3. -* reconnectIntervalMs: The interval between reconnection retries (connector version 3.1.3 and above). The default is - 2000. - -### Specify the URL and Properties to get the connection - -The C# connector does not support this feature - -### Priority of configuration parameters - -The C# connector does not support this feature - -## Usage examples - -### Create database and tables - -Native Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### Insert data - -Native Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### Querying data - -Native Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### execute SQL with reqId - -Native Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -### Writing data via parameter binding - -Native Example - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeStmt -{ - internal abstract class NativeStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSStmt -{ - internal abstract class WSStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - -Note: When using BindRow, you need to pay attention to the one-to-one correspondence between the original C# column type and the TDengine column type. For the specific correspondence, please refer to [TDengine DataType and C# DataType](#tdengine-datatype-vs-c-datatype). - -### Schemaless Writing - -Native Example - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - -WebSocket Example - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - -### Schemaless with reqId - -```csharp -public void SchemalessInsert(string[] lines, TDengineSchemalessProtocol protocol, - TDengineSchemalessPrecision precision, - int ttl, long reqId) -``` - -### Data Subscription - -#### Create a Topic - -Native Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -WebSocket Example - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - -#### Create a Consumer - -Native Example - -```csharp -var cfg = new Dictionary() -{ - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - -WebSocket Example - -```csharp -var cfg = new Dictionary() -{ - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port","6041"}, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - -The configuration parameters supported by consumer are as follows: -* td.connect.type: connection type, optional value is Native or WebSocket, default is Native -* td.connect.ip: The address of the TDengine running instance or taosadapter -* td.connect.port: The port of the running instance of TDengine or taosadapter. - * When using WebSocket without SSL, the default is 6041. - * When using WebSocket with SSL, the default is 443. -* useSSL: Whether to use SSL, the default is false, only valid when the protocol is WebSocket -* token: The token used to connect to TDengine Cloud, only valid when the protocol is WebSocket -* td.connect.user: username to connect to TDengine -* td.connect.pass: Password for connecting to TDengine -* group.id: consumer group ID -* client.id: consumer ID -* enable.auto.commit: Whether to automatically commit offset, the default is true -* auto.commit.interval.ms: The interval for automatically submitting offsets, the default is 5000 milliseconds -* auto.offset.reset: When offset does not exist, where to start consumption, the optional value is earliest or latest, the default is latest -* msg.with.table.name: Whether the message contains the table name -* ws.message.enableCompression: Whether to enable WebSocket compression (effective for dotnet version 6 and above, connector version 3.1.1 and above). The default is false. -* ws.autoReconnect: Whether to enable WebSocket reconnect (connector version 3.1.3 and above). The default is false. -* ws.reconnect.retry.count: The number of reconnection retries (connector version 3.1.3 and above). The default is 3. -* ws.reconnect.interval.ms: The interval between reconnection retries (connector version 3.1.3 and above). The default - is 2000. - -Supports subscribing to the result set `Dictionary` where the key is the column name and the value is the column value. - -If you use object to receive column values, you need to pay attention to: -* There needs to be a one-to-one correspondence between the original C# column type and the TDengine column type. For specific correspondence, please refer to [TDengine DataType and C# DataType] (#tdengine-datatype-and-c-datatype). -* The column name is consistent with the class attribute name and can be get and set. -* Explicitly set the value parser `ConsumerBuilder.SetValueDeserializer(new ReferenceDeserializer());` - -An example is as follows - -Result class - -```csharp - class Result - { - public DateTime ts { get; set; } - public float current { get; set; } - public int voltage { get; set; } - public float phase { get; set; } - } -``` - -Set up parser - -```csharp -var tmqBuilder = new ConsumerBuilder(cfg); -tmqBuilder.SetValueDeserializer(new ReferenceDeserializer()); -var consumer = tmqBuilder.Build(); -``` - -You can also implement a custom deserializer, implement the `IDeserializer` interface and pass it in through the `ConsumerBuilder.SetValueDeserializer` method. - -```csharp - public interface IDeserializer - { - T Deserialize(ITMQRows data, bool isNull, SerializationContext context); - } -``` - -#### Subscribe to consume data - -```csharp -consumer.Subscribe(new List() { "topic_meters" }); -while (true) -{ - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } -} -``` - -#### Assignment subscription Offset - -```csharp -consumer.Assignment.ForEach(a => -{ - Console.WriteLine($"{a}, seek to 0"); - consumer.Seek(new TopicPartitionOffset(a.Topic, a.Partition, 0)); - Thread.Sleep(TimeSpan.FromSeconds(1)); -}); -``` - -#### Commit offset - -```csharp -public void Commit(ConsumeResult consumerResult) -public List Commit() -public void Commit(IEnumerable offsets) -``` - -#### Close subscriptions - -```csharp -consumer.Unsubscribe(); -consumer.Close(); -``` - -#### Full Sample Code - -Native Example - -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` - -WebSocket Example +# Documentation -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; +- For development examples, see the [Developer Guide](https://docs.tdengine.com/developer-guide/). +- For version history, TDengine version compatibility, and API documentation, see + the [Reference Manual](https://docs.tdengine.com/tdengine-reference/client-libraries/csharp/). -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port","6041"}, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` +# Contributing -### ADO.NET +We encourage everyone to help improve this project. Below is the development and testing process for this project: -The C# connector supports the ADO.NET interface, and you can connect to the TDengine running instance through the ADO.NET interface to perform operations such as data writing and querying. +## Prerequisites -Native Example +* Install [.NET SDK](https://dotnet.microsoft.com/download) +* [Nuget Client](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools) (optional installation) +* Install the TDengine client driver. For specific steps, please refer + to [Installing the client driver](https://docs.tdengine.com/develop/connect/#install-client-driver-taosc) -```csharp -using System; -using TDengine.Data.Client; +## Building -namespace NativeADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "host=localhost;port=6030;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` +1. `dotnet restore` Restore the project's dependencies. +2. `dotnet build --no-restore` Build the project. -WebSocket Example +## Testing -```csharp -using System; -using TDengine.Data.Client; +1. Before running tests, ensure that the TDengine server is installed and that `taosd` and `taosAdapter` are running. + The database should be empty. +2. In the project directory, run `dotnet test` to execute the tests. The tests will connect to the local TDengine + server and taosAdapter for testing. -namespace WSADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` +# References -* The connection parameters are consistent with those in [Establishing a connection](#establishing-a-connection). -* The name of TDengineParameter needs to start with @, such as @0, @1, @2, etc. The value needs to have a one-to-one correspondence between the C# column type and the TDengine column type. For the specific correspondence, please refer to [TDengine DataType and C# DataType](#tdengine-datatype-vs-c-datatype). +- [TDengine Official Website](https://tdengine.com/) +- [TDengine GitHub](https://github.com/taosdata/TDengine) -### More sample programs +# License -[sample program](https://github.com/taosdata/taos-connector-dotnet/tree/3.0/examples) \ No newline at end of file +[MIT License](./LICENSE) \ No newline at end of file