• Articles
  • Api Documentation

ETCD V3 Client

base code all Generate by grpc tools.

Quick start

Install package

  • Package Manager
Install-Package etcd.v3 -Version 0.0.2
Install-Package etcd.v3.Configuration -Version 0.0.2
  • .NET CLI
dotnet add package etcd.v3 --version 0.0.2
dotnet add package etcd.v3.Configuration --version 0.0.2

new client

new client with DI

 ServiceCollection services = new();
 services.UseEtcdClient();
 services.AddEtcdClient("test", new EtcdClientOptions() { Address = ["http://xxx:2379"] });
 var p = services.BuildServiceProvider();

 var client = p.GetRequiredKeyedService<IEtcdClient>("test");

 // you also can create client by factory
 var factory = p.GetRequiredService<IEtcdClientFactory>();
var client2 = factory.CreateClient(new EtcdClientOptions() { Address = ["http://xxx:2379"] });


// get all config
foreach (var i in await client.GetRangeValueUtf8Async("/ReverseProxy/"))
{
   Console.WriteLine($"{i.Key} : {i.Value}");
}

// OR get client in ctor
public class Testt
{
    private readonly IEtcdClient client;

    public Testt([FromKeyedServices("test")] IEtcdClient client)
    {
        this.client = client;
    }
}


new client without DI

 var factory = EtcdClientFactory.Create();
var client = factory.CreateClient(new EtcdClientOptions() { Address = ["http://xxx:2379"] });

// get all config
foreach (var i in await client.GetRangeValueUtf8Async("/ReverseProxy/"))
{
   Console.WriteLine($"{i.Key} : {i.Value}");
}

use with Configuration

var b = new ConfigurationBuilder();
b.UseEtcd(new Etcd.Configuration.EtcdConfigurationOptions()
{
    Prefix = "/ReverseProxy/",
    RemovePrefix = true,
    EtcdClientOptions = new EtcdClientOptions() { Address = ["http://xxx:2379"] }
});
var c = b.Build();

// test watch change
Test(c);

private static void Test(IConfigurationRoot c)
{
    foreach (var i in c.GetChildren())
    {
        Console.WriteLine($"{i.Key} : {i.Value}");
    }
    c.GetReloadToken().RegisterChangeCallback(i =>
    {
        Test(i as IConfigurationRoot);
    }, c);
}

Address

Address just parse by GrpcChannel.ForAddress, so support

  • http://xxx:port
  • https://xxx:port
  • dns://xxx:port

KV

get one by key

string v = await client.GetValueUtf8Async("/ReverseProxy/");
//or 
string v = (await client.GetAsync("/ReverseProxy/")).Kvs?.First().Value.ToStrUtf8();
//or
string v = (await client.RangeAsync(new RangeRequest() { Key = ByteString.CopyFromUtf8("/ReverseProxy/") })).Kvs?.First().Value.ToStrUtf8();
get all IDictionary<string, string>
foreach (var i in await client.GetRangeValueUtf8Async("/ReverseProxy/"))
{
    Console.WriteLine($"{i.Key} : {i.Value}");
}
//or
foreach (var i in (await client.GetRangeAsync("/ReverseProxy/")).Kvs)
{
    Console.WriteLine($"{i.Key.ToStrUtf8()} : {i.Value.ToStrUtf8()}");
}
//or
foreach (var i in (await client.RangeAsync(new RangeRequest() { Key = ByteString.CopyFromUtf8("/ReverseProxy/"), RangeEnd = ByteString.CopyFromUtf8("/ReverseProxy/".GetRangeEnd()) })).Kvs)
{
    Console.WriteLine($"{i.Key.ToStrUtf8()} : {i.Value.ToStrUtf8()}");
}

Put

await client.PutAsync("/ReverseProxy/test", "1");
//or
await client.PutAsync(new PutRequest() { Key = ByteString.CopyFromUtf8("/ReverseProxy/test"), Value = ByteString.CopyFromUtf8("1") });

Delete one

await client.DeleteAsync("/ReverseProxy/test");
//or
await client.DeleteRangeAsync(new DeleteRangeRequest() { Key = ByteString.CopyFromUtf8("/ReverseProxy/test") });

Delete all

await client.DeleteRangeAsync("/ReverseProxy/test");
//or
await client.DeleteRangeAsync(new DeleteRangeRequest() { Key = ByteString.CopyFromUtf8("/ReverseProxy/test"), RangeEnd = ByteString.CopyFromUtf8("/ReverseProxy/test".GetRangeEnd())) });

Watch

 await client.WatchRangeBackendAsync("/ReverseProxy/", i =>
 {
     if (i.Events.Count > 0)
     {
         foreach (var item in i.Events)
         {
             Console.WriteLine($"{item.Type} {item.Kv.Key.ToStrUtf8()}");
         }
     }
     return Task.CompletedTask;
 }, startRevision: 6, reWatchWhenException: true);

 // or
await Task.Factory.StartNew(async () =>
{
    long startRevision = 6;
    while (true)
    {
        try
        {
            using var watcher = await client.WatchRangeAsync("/ReverseProxy/", startRevision: startRevision);
            await watcher.ForAllAsync(i =>
            {
                startRevision = i.FindRevision(startRevision);
                foreach (var item in i.Events)
                {
                    Console.WriteLine($"{item.Type} {item.Kv.Key.ToStrUtf8()}");
                }
                return Task.CompletedTask;
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception: {ex.Message}");
        }
    }
});

all grpc client

if IEtcdClient Missing some grpc method , you can just use grpc client to do

public partial interface IEtcdClient
{
    public AuthClient AuthClient { get; }
    public Cluster.ClusterClient ClusterClient { get; }
    public ElectionClient ElectionClient { get; }
    public KV.KVClient KVClient { get; }
    public LeaseClient LeaseClient { get; }
    public LockClient LockClient { get; }
    public MaintenanceClient MaintenanceClient { get; }
    public Watch.WatchClient WatchClient { get; }
}

api doc

Main api doc please see

https://fs7744.github.io/etcdcsharp/api/Etcd.html https://fs7744.github.io/etcdcsharp/api/Microsoft.Extensions.Configuration.EtcdConfigurationExtensions.html

All api doc ( include code generate by grpc tool ) please see

https://fs7744.github.io/etcdcsharp/api/index.html

  • Edit this page
In this article
Back to top Generated by DocFX