// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
= .NET Thin Client

:sourceCodeFile: code-snippets/dotnet/ThinClient.cs

== 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.

[source, csharp]
----
include::{sourceCodeFile}[tag=connecting,indent=0]
----

=== 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.

[[discovery]]
=== Automatic Server Node Discovery

Thin client can discover server nodes in the cluster automatically.
This behavior is enabled when link:#partition_awareness[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`:

[source, csharp]
----
include::{sourceCodeFile}[tag=discovery,indent=0]
----

[WARNING]
====
[discrete]
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

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.

image::images/partitionawareness01.png[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.

image::images/partitionawareness02.png[With Partition Awareness]

To enable partition awareness, set the `IgniteClientConfiguration.EnablePartitionAwareness` property to `true`.
This enables link:#discovery[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.

[source, csharp]
----
include::{sourceCodeFile}[tag=createCache,indent=0]
----

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.

[source, csharp]
----
include::{sourceCodeFile}[tag=basicOperations,indent=0]
----

////
=== Asynchronous Execution
////


=== Working With Binary Objects
The .NET thin client supports the Binary Object API described in the link:key-value-api/binary-objects[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.

[source, csharp]
----
include::{sourceCodeFile}[tag=binaryObj,indent=0]
----

== 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:
[source, csharp]
----
include::{sourceCodeFile}[tag=scanQry,indent=0]
----

Then execute the scan query:
[source, csharp]
----
include::{sourceCodeFile}[tag=scanQry2,indent=0]
----


== 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.

[source, csharp]
----
include::{sourceCodeFile}[tag=executingSql,indent=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:
[source, csharp]
-------------------------------------------------------------------------------
include::{sourceCodeFile}[tag=client-cluster,indent=0]
-------------------------------------------------------------------------------

=== 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:

[source, csharp]
-------------------------------------------------------------------------------
include::{sourceCodeFile}[tag=client-cluster-groups,indent=0]
-------------------------------------------------------------------------------

Note, the `IClientCluster` instance implements `IClientClusterGroup` which is the root cluster group that includes all
nodes of the cluster.

Refer to the main link:distributed-computing/cluster-groups[cluster groups] documentation page for more details on the capability.

== Executing Compute Tasks

Presently, the .NET thin client supports basic link:distributed-computing/distributed-computing[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 link:thin-clients/dotnet-thin-client#logical-nodes-grouping[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:

[tabs]
--
tab:Spring XML[]
[source,xml]
----
<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>
----
tab:C#[]
[source,csharp]
----
include::{sourceCodeFile}[tag=client-compute-setup,indent=0]
----
--

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:
[source, csharp]
-------------------------------------------------------------------------------
include::{sourceCodeFile}[tag=client-compute-task,indent=0]
-------------------------------------------------------------------------------

== Executing Ignite Services

You can use the `IServicesClient` API to invoke an link:services/services[Ignite Service] that
is *already deployed* in the cluster. See link:services/services[Using Ignite Services] for more information on service deployment.

The example below shows how to invoke the service named `MyService`:
[source, csharp]
-------------------------------------------------------------------------------
include::{sourceCodeFile}[tag=client-services,indent=0]
-------------------------------------------------------------------------------

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 link:thin-clients/getting-started-with-thin-clients#enabling-ssltls-for-thin-clients[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.
[source, csharp]
----
include::{sourceCodeFile}[tag=ssl,indent=0]
----


=== Authentication


Configure link:security/authentication[authentication on the cluster side] and provide a valid user name and password in the client configuration.

[source, csharp]
----
include::{sourceCodeFile}[tag=auth,indent=0]
----
