.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 Ignite.NET API library, which is located in the {IGNITE_HOME}/platforms/dotnet
directory of the Ignite 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 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 client can discover server nodes in the cluster automatically. This behavior is enabled when Partition Awareness is enabled.
Server discovery is an asynchronous process - it happens in the background. Additionally, thin client receives topology updates only when it performs some 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);
}
Warning
|
Server discovery may not work when servers are behind a NAT server or a proxy. Server nodes provide their addresses and ports to the client, but when the client is in a different subnet, those addresses won’t work. |
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.
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.
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 IIgniteClient.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 Ignite 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]);
}
Using Cluster API
The cluster APIs let you create a group of cluster nodes and run various operations against the group. The IClientCluster
interface is the entry-point to the APIs that can be used as follows:
-
Get or change the state of a cluster
-
Get a list of all cluster nodes
-
Create logical groups our of cluster nodes and use other Ignite APIs to perform certain operations on the group
Use the instance of IClientCluster
to obtain a reference to the IClientCluster
that comprises all cluster nodes, and
activate the whole cluster as well as write-ahead-logging for the my-cache
cache:
IIgniteClient client = Ignition.StartClient(cfg);
IClientCluster cluster = client.GetCluster();
cluster.SetActive(true);
cluster.EnableWal("my-cache");
Logical nodes grouping
You can use the IClientClusterGroup
interface of the cluster APIs to create various groups of cluster nodes. For instance,
one group can comprise all servers nodes, while the other group can include only those nodes that match a specific
TCP/IP address format. The example below shows how to create a group of server nodes located in the dc1
data center:
IIgniteClient client = Ignition.StartClient(cfg);
IClientClusterGroup serversInDc1 = client.GetCluster().ForServers().ForAttribute("dc", "dc1");
foreach (IClientClusterNode node in serversInDc1.GetNodes())
Console.WriteLine($"Node ID: {node.Id}");
Note, the IClientCluster
instance implements IClientClusterGroup
which is the root cluster group that includes all
nodes of the cluster.
Refer to the main cluster groups documentation page for more details on the capability.
Executing Compute Tasks
Presently, the .NET thin client supports basic compute capabilities by letting you execute those compute tasks that are already deployed in the cluster. You can either run a task across all cluster nodes or a specific cluster group.
By default, the execution of tasks, triggered by the thin client, is disabled on the cluster side. You need to set the
ThinClientConfiguration.MaxActiveComputeTasksPerConnection
parameter to a non-zero value in the configuration of your
server nodes and thick clients:
<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">
<property name="clientConnectorConfiguration">
<bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
<property name="thinClientConfiguration">
<bean class="org.apache.ignite.configuration.ThinClientConfiguration">
<property name="maxActiveComputeTasksPerConnection" value="100" />
</bean>
</property>
</bean>
</property>
</bean>
var igniteCfg = new IgniteConfiguration
{
ClientConnectorConfiguration = new ClientConnectorConfiguration
{
ThinClientConfiguration = new ThinClientConfiguration
{
MaxActiveComputeTasksPerConnection = 10
}
}
};
IIgnite ignite = Ignition.Start(igniteCfg);
The example below shows how to get access to the compute APIs via the IComputeClient
interface and execute the compute
task named org.foo.bar.AddOneTask
passing 1
as an input parameter:
IIgniteClient client = Ignition.StartClient(cfg);
IComputeClient compute = client.GetCompute();
int result = compute.ExecuteJavaTask<int>("org.foo.bar.AddOneTask", 1);
Executing Ignite Services
You can use the IServicesClient
API to invoke an Ignite Service that
is already deployed in the cluster. See Using Ignite Services for more information on service deployment.
The example below shows how to invoke the service named MyService
:
IIgniteClient client = Ignition.StartClient(cfg);
IServicesClient services = client.GetServices();
IMyService serviceProxy = services.GetServiceProxy<IMyService>("MyService");
serviceProxy.MyServiceMethod("hello");
The thin client allows to execute services implemented in Java or .NET.
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 = "ignite",
Password = "ignite"
};
using (var client = Ignition.StartClient(cfg))
{
//...
}
Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are either registered trademarks or trademarks of The Apache Software Foundation.