GridGain Developers Hub

.NET Thin Client

Prerequisites

  • Supported runtimes: .NET 4.0+, .NET Core 2.0+

  • Supported OS: Windows, Linux, macOS (any OS supported by .NET Core 2.0+)

Installation

The .NET thin client API is provided by the GridGain.NET API library, which is located in the {GRIDGAIN_HOME}/platforms/dotnet directory of the GridGain distribution package. The API is located in the Apache.Ignite.Core assembly.

Connecting to Cluster

The thin client API entry point is the Ignition.StartClient(IgniteClientConfiguration) method. The IgniteClientConfiguration.Endpoints property is mandatory; it must point to the host where the server node is running.

var cfg = new IgniteClientConfiguration
{
    Endpoints = new[] {"127.0.0.1:10800"}
};

using (var client = Ignition.StartClient(cfg))
{
    var cache = client.GetOrCreateCache<int, string>("cache");
    cache.Put(1, "Hello, World!");
}

Failover

You can provide multiple node addresses. In this case thin client connects to a random node in the list, and the failover mechanism is enabled: if a server node fails, client tries other known addresses and reconnects automatically. Note that IgniteClientException can be thrown if a server node fails while client operation is being performed - user code should handle this exception and implement retry logic accordingly.

Automatic Server Node Discovery

Thin clients connect to one or more servers. The set of endpoints is defined in ClientConfiguration and cannot change after a client starts. However, clusters can change their topology dynamically: nodes can start and stop, IP addresses can change, etc. To account for that, thin clients can discover server nodes automatically when connected to any of them, and maintain an up to date list of servers at all times.

The automatic node discovery is enabled by default. To disable this behavior, set the IgniteClientConfiguration.EnableClusterDiscovery property to "false".

The client performs the discovery as follows: . Connects to one or more endpoints from IgniteClientConfiguration.Endpoints. . Retrieves the current topology. . Connects to every server from Step 2 it hasn’t connected to before: .. Uses node UUID to make sure it doesn’t connect to the same node twice. .. Drops the connection in case of a UUID mismatch. . For every response to every operation, compares the topology version from the header to the topology version from Step 2. . Connects to the newly discovered servers, removes connections to the removed servers. . Repeats Step 4.

Server discovery is an asynchronous process - it happens in the background. Moreover, thin client receives topology updates only when it performs operations (to minimize server load and network traffic from idle connections).

You can observe the discovery process by enabling logging and/or calling IIgniteClient.GetConnections:

var cfg = new IgniteClientConfiguration
{
    Endpoints = new[] {"127.0.0.1:10800"},
    EnablePartitionAwareness = true,

    // Enable trace logging to observe discovery process.
    Logger = new ConsoleLogger { MinLevel = LogLevel.Trace }
};

var client = Ignition.StartClient(cfg);

// Perform any operation and sleep to let the client discover
// server nodes asynchronously.
client.GetCacheNames();
Thread.Sleep(1000);

foreach (IClientConnection connection in client.GetConnections())
{
    Console.WriteLine(connection.RemoteEndPoint);
}

Partition Awareness

Partition awareness allows the thin client to send query requests directly to the node that owns the queried data.

Without partition awareness, an application that is connected to the cluster via a thin client executes all queries and operations via a single server node that acts as a proxy for the incoming requests. These operations are then re-routed to the node that stores the data that is being requested. This results in a bottleneck that could prevent the application from scaling linearly.

Without Partition Awareness

Notice how queries must pass through the proxy server node, where they are routed to the correct node.

With partition awareness in place, the thin client can directly route queries and operations to the primary nodes that own the data required for the queries. This eliminates the bottleneck, allowing the application to scale more easily.

With Partition Awareness

To enable partition awareness, set the IgniteClientConfiguration.EnablePartitionAwareness property to true. This enables server discovery as well. If the client is behind a NAT or a proxy, automatic server discovery may not work. In this case provide addresses of all server nodes in the client’s connection configuration.

Using Key-Value API

Getting Cache Instance

The ICacheClient interface provides the key-value API. You can use the following methods to obtain an instance of ICacheClient:

  • GetCache(cacheName) — returns an instance of an existing cache.

  • CreateCache(cacheName) — creates a cache with the given name.

  • GetOrCreateCache(CacheClientConfiguration) — gets or creates a cache with the given configuration.

var cacheCfg = new CacheClientConfiguration
{
    Name = "References",
    CacheMode = CacheMode.Replicated,
    WriteSynchronizationMode = CacheWriteSynchronizationMode.FullSync
};
var cache = client.GetOrCreateCache<int, string>(cacheCfg);

Use IIgnite​Client.GetCacheNames() to obtain a list of all existing caches.

Basic Operations

The following code snippet demonstrates how to execute basic cache operations on a specific cache.

var data = Enumerable.Range(1, 100).ToDictionary(e => e, e => e.ToString());

cache.PutAll(data);

var replace = cache.Replace(1, "2", "3");
Console.WriteLine(replace); //false

var value = cache.Get(1);
Console.WriteLine(value); //1

replace = cache.Replace(1, "1", "3");
Console.WriteLine(replace); //true

value = cache.Get(1);
Console.WriteLine(value); //3

cache.Put(101, "101");

cache.RemoveAll(data.Keys);
var sizeIsOne = cache.GetSize() == 1;
Console.WriteLine(sizeIsOne); //true

value = cache.Get(101);
Console.WriteLine(value); //101

cache.RemoveAll();
var sizeIsZero = cache.GetSize() == 0;
Console.WriteLine(sizeIsZero); //true

Working With Binary Objects

The .NET thin client supports the Binary Object API described in the Working with Binary Objects section. Use ICacheClient.WithKeepBinary() to switch the cache to binary mode and start working directly with binary objects avoiding serialization/deserialization. Use IIgniteClient.GetBinary() to get an instance of IBinary and build an object from scratch.

var binary = client.GetBinary();

var val = binary.GetBuilder("Person")
    .SetField("id", 1)
    .SetField("name", "Joe")
    .Build();

var cache = client.GetOrCreateCache<int, object>("persons").WithKeepBinary<int, IBinaryObject>();

cache.Put(1, val);

var value = cache.Get(1);

Scan Queries

Use a scan query to get a set of entries that satisfy a given condition. The thin client sends the query to the cluster node where it is executed as a normal scan query.

The query condition is specified by an ICacheEntryFilter object that is passed to the query constructor as an argument.

Define a query filter as follows:

class NameFilter : ICacheEntryFilter<int, Person>
{
    public bool Invoke(ICacheEntry<int, Person> entry)
    {
        return entry.Value.Name.Contains("Smith");
    }
}

Then execute the scan query:

var cache = client.GetOrCreateCache<int, Person>("personCache");

cache.Put(1, new Person {Name = "John Smith"});
cache.Put(2, new Person {Name = "John Johnson"});

using (var cursor = cache.Query(new ScanQuery<int, Person>(new NameFilter())))
{
    foreach (var entry in cursor)
    {
        Console.WriteLine("Key = " + entry.Key + ", Name = " + entry.Value.Name);
    }
}

Executing SQL Statements

The thin client provides a SQL API to execute SQL statements. SQL statements are declared using SqlFieldsQuery objects and executed through the ICacheClient.Query(SqlFieldsQuery) method. Alternatively, SQL queries can be performed via GridGain LINQ provider.

var cache = client.GetOrCreateCache<int, Person>("Person");
cache.Query(new SqlFieldsQuery(
        $"CREATE TABLE IF NOT EXISTS Person (id INT PRIMARY KEY, name VARCHAR) WITH \"VALUE_TYPE={typeof(Person)}\"")
    {Schema = "PUBLIC"}).GetAll();

var key = 1;
var val = new Person {Id = key, Name = "Person 1"};

cache.Query(
    new SqlFieldsQuery("INSERT INTO Person(id, name) VALUES(?, ?)")
    {
        Arguments = new object[] {val.Id, val.Name},
        Schema = "PUBLIC"
    }
).GetAll();

var cursor = cache.Query(
    new SqlFieldsQuery("SELECT name FROM Person WHERE id = ?")
    {
        Arguments = new object[] {key},
        Schema = "PUBLIC"
    }
);

var results = cursor.GetAll();

var first = results.FirstOrDefault();
if (first != null)
{
    Console.WriteLine("name = " + first[0]);
}

Enabling Logging

You can enable logging of thin client’s events with the a logger implementation of your choice:

var cfg = new IgniteClientConfiguration("127.0.0.1:10800")
{
    Logger = new ConsoleLogger { MinLevel = LogLevel.Info },
};
using var client = Ignition.StartClient(cfg);

Security

SSL/TLS

To use encrypted communication between the thin client and the cluster, you have to enable SSL/TLS in both the cluster configuration and the client configuration. Refer to the Enabling SSL/TLS for Thin Clients section for the instruction on the cluster configuration.

The following code example demonstrates how to configure SSL parameters in the thin client.

var cfg = new IgniteClientConfiguration
{
    Endpoints = new[] {"127.0.0.1:10800"},
    SslStreamFactory = new SslStreamFactory
    {
        CertificatePath = ".../certs/client.pfx",
        CertificatePassword = "password",
    }
};
using (var client = Ignition.StartClient(cfg))
{
    //...
}

Authentication

Configure authentication on the cluster side and provide a valid user name and password in the client configuration.

var cfg = new IgniteClientConfiguration
{
    Endpoints = new[] {"127.0.0.1:10800"},
    UserName = "gridgain",
    Password = "gridgain"
};
using (var client = Ignition.StartClient(cfg))
{
    //...
}

Authorization

You can configure thin client authorization in the cluster. Refer to the Authorization page for details.

Data Center Replication

Sender Groups

Configure sender groups for sender nodes by using the ClientCacheDrSenderConfiguration.

The below example adds the node to the group1 sender group:

using IIgniteClient client = Ignition.StartClient(
    new IgniteClientConfiguration("localhost"));

var cacheCfg = new CacheClientConfiguration
{
    Name = "dr-cache",
    PluginConfigurations = new[]
    {
        new GridGainCacheClientPluginConfiguration
        {
            DrSenderConfiguration = new ClientCacheDrSenderConfiguration
            {
                SenderGroup = "group1"
            }
        }
    }
};

ICacheClient<int,int> cache = client.CreateCache<int, int>(cacheCfg);