This is an automated email from the ASF dual-hosted git repository.

ptupitsyn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 3123460  IGNITE-16025 .NET: Add thin client retry policy (#9786)
3123460 is described below

commit 312346035de8923188def37e2f9ba130f6b67d11
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Thu Feb 3 14:04:05 2022 +0300

    IGNITE-16025 .NET: Add thin client retry policy (#9786)
    
    * Add `IClientRetryPolicy` interface.
    * Add predefined policies: `ClientRetryAllPolicy`, `ClientRetryReadPolicy`.
    * Add `ClientConfiguration.retryPolicy` property, defaults to null (keep 
existing behavior - no retries by default).
    
    
https://cwiki.apache.org/confluence/display/IGNITE/IEP-82+Thin+Client+Retry+Policy
---
 .../apache/ignite/client/ClientOperationType.java  |   4 +-
 .../Client/ClientConnectionTest.cs                 | 211 ++++++++++++++++++++
 .../ClientProtocolCompatibilityTest.cs             |   2 +-
 .../Client/Compute/ComputeClientTests.cs           |   2 +-
 .../Client/IgniteClientConfigurationTest.cs        |   2 -
 .../Client/TestRetryPolicy.cs                      |  57 ++++++
 .../Client/ClientOperationType.cs                  | 219 +++++++++++++++++++++
 .../Client/ClientRetryAllPolicy.cs                 |  31 +++
 .../Client/ClientRetryReadPolicy.cs                |  55 ++++++
 .../Client/IClientRetryPolicy.cs                   |  36 ++++
 .../Client/IClientRetryPolicyContext.cs            |  47 +++++
 .../Client/IgniteClientConfiguration.cs            |  22 +++
 .../IgniteClientConfigurationSection.xsd           |  17 ++
 .../Impl/Client/ClientFailoverSocket.cs            | 172 +++++++++++++++-
 .../Impl/Client/ClientOpExtensions.cs              | 158 +++++++++++++++
 .../Impl/Client/ClientRetryPolicyContext.cs        |  59 ++++++
 .../Apache.Ignite.Core/Impl/Common/TypeCaster.cs   |   8 +-
 17 files changed, 1082 insertions(+), 20 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/ClientOperationType.java 
b/modules/core/src/main/java/org/apache/ignite/client/ClientOperationType.java
index f99b2e0..d5ac4b6 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/client/ClientOperationType.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/ClientOperationType.java
@@ -55,7 +55,7 @@ public enum ClientOperationType {
     CACHE_GET,
 
     /**
-     * Get value from cache ({@link ClientCache#get(Object)}).
+     * Put value to cache ({@link ClientCache#put(Object, Object)}).
      */
     CACHE_PUT,
 
@@ -106,7 +106,7 @@ public enum ClientOperationType {
     CACHE_REMOVE_MULTIPLE,
 
     /**
-     * Remove everyting from cache ({@link ClientCache#removeAll()}).
+     * Remove everything from cache ({@link ClientCache#removeAll()}).
      */
     CACHE_REMOVE_EVERYTHING,
 
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
index b7c65bb..92501b9 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -34,6 +34,7 @@ namespace Apache.Ignite.Core.Tests.Client
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Log;
     using Apache.Ignite.Core.Tests.Client.Cache;
+    using Apache.Ignite.Core.Tests.Client.Compute;
     using NUnit.Framework;
 
     /// <summary>
@@ -643,6 +644,216 @@ namespace Apache.Ignite.Core.Tests.Client
         }
 
         /// <summary>
+        /// Tests automatic retry with one server.
+        /// </summary>
+        [Test]
+        public void TestFailoverWithRetryPolicyReconnectsToNewNode()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1" },
+                RetryPolicy = new ClientRetryReadPolicy()
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                var restartTask = Task.Run(() =>
+                {
+                    Ignition.StopAll(true);
+                    Thread.Sleep(100);
+                    Ignition.Start(TestUtils.GetTestConfiguration());
+                });
+
+                while (!restartTask.IsCompleted)
+                {
+                    // Operations do not fail while the only node is being 
restarted.
+                    Assert.AreEqual(0, client.GetCacheNames().Count);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Tests that operation fails with an exception when retry limit is 
reached.
+        /// </summary>
+        [Test]
+        public void TestFailoverWithRetryPolicyThrowsOnRetryCountExceeded()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+
+            var retryLimit = 4;
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1" },
+                RetryPolicy = new ClientRetryAllPolicy(),
+                RetryLimit = retryLimit
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                Assert.AreEqual(0, client.GetCacheNames().Count);
+
+                Ignition.StopAll(true);
+
+                var ex = Assert.Throws<IgniteClientException>(() => 
client.GetCacheNames());
+                StringAssert.StartsWith($"Operation failed after {retryLimit} 
retries", ex.Message);
+
+                Assert.IsNotNull(ex.InnerException);
+                Assert.IsInstanceOf<AggregateException>(ex.InnerException);
+                Assert.AreEqual(retryLimit, 
((AggregateException)ex.InnerException).InnerExceptions.Count);
+            }
+        }
+
+        /// <summary>
+        /// Tests that failed operations not related to connection issues are 
not retried.
+        /// </summary>
+        [Test]
+        public void TestFailoverWithRetryPolicyDoesNotRetryUnrelatedErrors()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1" },
+                RetryPolicy = new ClientRetryAllPolicy()
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                var ex = Assert.Catch<Exception>(() =>
+                    
client.GetCompute().ExecuteJavaTask<object>(ComputeClientTests.TestTask, null));
+
+                StringAssert.StartsWith(
+                    "Compute grid functionality is disabled for thin clients", 
ex.GetInnermostException().Message);
+            }
+        }
+
+        /// <summary>
+        /// Tests automatic retry with multiple servers.
+        /// </summary>
+        [Test]
+        public void 
TestFailoverWithRetryPolicyCompletesOperationWithoutException(
+            [Values(true, false)] bool async,
+            [Values(true, false)] bool partitionAware)
+        {
+            // Start 3 nodes.
+            Func<string, IgniteConfiguration> getConfig = name =>
+                new IgniteConfiguration(TestUtils.GetTestConfiguration(name: 
name))
+                {
+                    ClientConnectorConfiguration = new 
ClientConnectorConfiguration
+                    {
+                        ThinClientConfiguration = new ThinClientConfiguration
+                        {
+                            MaxActiveComputeTasksPerConnection = 1
+                        }
+                    }
+                };
+
+            Ignition.Start(getConfig("0"));
+            Ignition.Start(getConfig("1"));
+            Ignition.Start(getConfig("2"));
+
+            // Connect client.
+            var port = IgniteClientConfiguration.DefaultPort;
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[]
+                {
+                    "localhost",
+                    string.Format("127.0.0.1:{0}..{1}", port + 1, port + 2)
+                },
+                RetryPolicy = new ClientRetryAllPolicy(),
+                RetryLimit = 3,
+                EnablePartitionAwareness = partitionAware
+            };
+
+            // ReSharper disable AccessToDisposedClosure
+            using (var client = Ignition.StartClient(cfg))
+            {
+                var cache = client.GetOrCreateCache<int, int>("c");
+
+                // Check all DoOp overloads.
+                Action checkOperation = partitionAware
+                    ? async
+                        ? (Action)(() => 
Assert.IsFalse(cache.ContainsKeyAsync(1).Result))
+                        : () => Assert.IsFalse(cache.ContainsKey(1))
+                    : async
+                        ? (Action)(() => 
Assert.IsNotNull(client.GetCompute().ExecuteJavaTaskAsync<object>(
+                            ComputeClientTests.TestTask, null).Result))
+                        : () => Assert.AreEqual(1, 
client.GetCacheNames().Count);
+
+                checkOperation();
+
+                // Stop first node.
+                var nodeId = ((IPEndPoint) client.RemoteEndPoint).Port - port;
+                Ignition.Stop(nodeId.ToString(), true);
+
+                checkOperation();
+
+                // Stop second node.
+                nodeId = ((IPEndPoint) client.RemoteEndPoint).Port - port;
+                Ignition.Stop(nodeId.ToString(), true);
+
+                checkOperation();
+
+                // Stop all nodes.
+                Ignition.StopAll(true);
+
+                Assert.IsNotNull(GetSocketException(Assert.Catch(() => 
client.GetCacheNames())));
+                Assert.IsNotNull(GetSocketException(Assert.Catch(() => 
client.GetCacheNames())));
+            }
+        }
+
+        /// <summary>
+        /// Tests custom retry policy.
+        /// </summary>
+        [Test]
+        public void TestCustomRetryPolicyIsInvokedWithCorrectContext()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+
+            var retryPolicy = new 
TestRetryPolicy(ClientOperationType.CacheGetNames);
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1" },
+                RetryPolicy = retryPolicy,
+                RetryLimit = 2
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                Assert.AreEqual(0, client.GetCacheNames().Count);
+
+                Ignition.StopAll(true);
+
+                var errorWithoutRetry = GetSocketException(Assert.Catch(() => 
client.GetCluster().GetNodes()));
+                var errorWithRetry = Assert.Throws<IgniteClientException>(() 
=> client.GetCacheNames());
+
+                Assert.IsNotNull(errorWithoutRetry);
+                StringAssert.StartsWith("Operation failed after 2 retries", 
errorWithRetry.Message);
+
+                Assert.AreEqual(3, retryPolicy.Invocations.Count);
+
+                Assert.AreEqual(ClientOperationType.ClusterGroupGetNodes, 
retryPolicy.Invocations[0].Operation);
+                Assert.AreEqual(0, retryPolicy.Invocations[0].Iteration);
+                Assert.AreSame(retryPolicy, 
retryPolicy.Invocations[0].Configuration.RetryPolicy);
+                Assert.AreEqual(2, 
retryPolicy.Invocations[0].Configuration.RetryLimit);
+                
Assert.IsInstanceOf<SocketException>(retryPolicy.Invocations[0].Exception.GetBaseException());
+
+                Assert.AreEqual(ClientOperationType.CacheGetNames, 
retryPolicy.Invocations[1].Operation);
+                Assert.AreEqual(0, retryPolicy.Invocations[1].Iteration);
+                
Assert.IsInstanceOf<SocketException>(retryPolicy.Invocations[1].Exception.GetBaseException());
+
+                Assert.AreEqual(ClientOperationType.CacheGetNames, 
retryPolicy.Invocations[2].Operation);
+                Assert.AreEqual(1, retryPolicy.Invocations[2].Iteration);
+                
Assert.IsInstanceOf<SocketException>(retryPolicy.Invocations[2].Exception.GetBaseException());
+            }
+        }
+
+        /// <summary>
         /// Tests that client stops it's receiver thread upon disposal.
         /// </summary>
         [Test]
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compatibility/ClientProtocolCompatibilityTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compatibility/ClientProtocolCompatibilityTest.cs
index 6fa058c..e6ca434 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compatibility/ClientProtocolCompatibilityTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compatibility/ClientProtocolCompatibilityTest.cs
@@ -201,7 +201,7 @@ namespace Apache.Ignite.Core.Tests.Client.Compatibility
         /// </summary>
         internal static void AssertNotSupportedFeatureOperation(Action action, 
ClientBitmaskFeature feature, ClientOp op)
         {
-            var ex = Assert.Throws<IgniteClientException>(() => action());
+            var ex = Assert.Catch<Exception>(() => 
action()).GetBaseException();
 
             var expectedMessage = string.Format(
                 "Operation {0} is not supported by the server. " +
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compute/ComputeClientTests.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compute/ComputeClientTests.cs
index adce7b0..3efdd46 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compute/ComputeClientTests.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Compute/ComputeClientTests.cs
@@ -40,7 +40,7 @@ namespace Apache.Ignite.Core.Tests.Client.Compute
     public class ComputeClientTests : ClientTestBase
     {
         /** */
-        private const string TestTask = 
"org.apache.ignite.internal.client.thin.TestTask";
+        public const string TestTask = 
"org.apache.ignite.internal.client.thin.TestTask";
 
         /** */
         private const string TestResultCacheTask = 
"org.apache.ignite.internal.client.thin.TestResultCacheTask";
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
index 1aacaf2..3a09e4b 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
@@ -300,7 +300,6 @@ namespace Apache.Ignite.Core.Tests.Client
             }
         }
 
-#if !NETCOREAPP
         /// <summary>
         /// Tests the schema validation.
         /// </summary>
@@ -324,7 +323,6 @@ namespace Apache.Ignite.Core.Tests.Client
                 "IgniteClientConfigurationSection.xsd", 
"igniteClientConfiguration",
                 typeof(IgniteClientConfiguration));
         }
-#endif
 
         /// <summary>
         /// Tests <see cref="TransactionClientConfiguration"/> copy ctor.
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/TestRetryPolicy.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/TestRetryPolicy.cs
new file mode 100644
index 0000000..5f0c75d
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/TestRetryPolicy.cs
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client
+{
+    using System.Collections.Generic;
+    using System.Linq;
+    using Apache.Ignite.Core.Client;
+
+    /// <summary>
+    /// Test policy.
+    /// </summary>
+    public class TestRetryPolicy : IClientRetryPolicy
+    {
+        /** */
+        private readonly IReadOnlyCollection<ClientOperationType> 
_allowedOperations;
+
+        /** */
+        private readonly List<IClientRetryPolicyContext> _invocations = new 
List<IClientRetryPolicyContext>();
+
+        /// <summary>
+        /// Initializes a new instance of <see cref="TestRetryPolicy"/> class.
+        /// </summary>
+        /// <param name="allowedOperations">A list of operation types to 
retry.</param>
+        public TestRetryPolicy(params ClientOperationType[] allowedOperations)
+        {
+            _allowedOperations = allowedOperations.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the invocations.
+        /// </summary>
+        public IReadOnlyList<IClientRetryPolicyContext> Invocations => 
_invocations;
+
+        /** <inheritDoc /> */
+        public bool ShouldRetry(IClientRetryPolicyContext context)
+        {
+            _invocations.Add(context);
+
+            return _allowedOperations.Contains(context.Operation);
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientOperationType.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientOperationType.cs
new file mode 100644
index 0000000..51aeb70
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientOperationType.cs
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Client.Compute;
+    using Apache.Ignite.Core.Client.Services;
+    using Apache.Ignite.Core.Client.Transactions;
+
+    /// <summary>
+    /// Client operation type.
+    /// </summary>
+    public enum ClientOperationType
+    {
+        /// <summary>
+        /// Create cache <see 
cref="IIgniteClient.CreateCache{TK,TV}(string)"/>,
+        /// <see 
cref="IIgniteClient.CreateCache{TK,TV}(CacheClientConfiguration)"/>.
+        /// </summary>
+        CacheCreate,
+
+        /// <summary>
+        /// Get or create cache <see 
cref="IIgniteClient.GetOrCreateCache{TK,TV}(string)"/>,
+        /// <see 
cref="IIgniteClient.GetOrCreateCache{TK,TV}(CacheClientConfiguration)"/>.
+        /// </summary>
+        CacheGetOrCreate,
+
+        /// <summary>
+        /// Get cache names <see cref="IIgniteClient.GetCacheNames"/>.
+        /// </summary>
+        CacheGetNames,
+
+        /// <summary>
+        /// Destroy cache <see cref="IIgniteClient.DestroyCache"/>.
+        /// </summary>
+        CacheDestroy,
+
+        /// <summary>
+        /// Get value from cache <see cref="ICacheClient{TK,TV}.Get"/>.
+        /// </summary>
+        CacheGet,
+
+        /// <summary>
+        /// Put value to cache <see cref="ICacheClient{TK,TV}.Put"/>.
+        /// </summary>
+        CachePut,
+
+        /// <summary>
+        /// Determines if the cache contains a key <see 
cref="ICacheClient{TK,TV}.Put"/>.
+        /// </summary>
+        CacheContainsKey,
+
+        /// <summary>
+        /// Determines if the cache contains multiple keys (<see 
cref="ICacheClient{TK,TV}.ContainsKeys"/>).
+        /// </summary>
+        CacheContainsKeys,
+
+        /// <summary>
+        /// Get cache configuration (<see 
cref="ICacheClient{TK,TV}.GetConfiguration"/>).
+        /// </summary>
+        CacheGetConfiguration,
+
+        /// <summary>
+        /// Get cache size (<see cref="ICacheClient{TK,TV}.GetSize"/>).
+        /// </summary>
+        CacheGetSize,
+
+        /// <summary>
+        /// Put values to cache (<see cref="ICacheClient{TK,TV}.PutAll"/>).
+        /// </summary>
+        CachePutAll,
+
+        /// <summary>
+        /// Get values from cache (<see cref="ICacheClient{TK,TV}.GetAll"/>).
+        /// </summary>
+        CacheGetAll,
+
+        /// <summary>
+        /// Replace cache value (<see 
cref="ICacheClient{TK,TV}.Replace(TK,TV)"/>,
+        /// <see cref="ICacheClient{TK,TV}.Replace(TK,TV,TV)"/>).
+        /// </summary>
+        CacheReplace,
+
+        /// <summary>
+        /// Remove entry from cache (<see 
cref="ICacheClient{TK,TV}.Remove(TK)" />,
+        /// <see cref="ICacheClient{TK,TV}.Remove(TK,TV)"/>).
+        /// </summary>
+        CacheRemoveOne,
+
+        /// <summary>
+        /// Remove entries from cache (<see 
cref="ICacheClient{TK,TV}.RemoveAll(System.Collections.Generic.IEnumerable{TK})"/>).
+        /// </summary>
+        CacheRemoveMultiple,
+
+        /// <summary>
+        /// Remove everything from cache (<see 
cref="ICacheClient{TK,TV}.RemoveAll()"/>).
+        /// </summary>
+        CacheRemoveEverything,
+
+        /// <summary>
+        /// Clear cache entry (<see cref="ICacheClient{TK,TV}.Clear(TK)"/>).
+        /// </summary>
+        CacheClearOne,
+
+        /// <summary>
+        /// Clear multiple cache entries (<see 
cref="ICacheClient{TK,TV}.ClearAll"/>).
+        /// </summary>
+        CacheClearMultiple,
+
+        /// <summary>
+        /// Clear entire cache (<see cref="ICacheClient{TK,TV}.Clear()"/>).
+        /// </summary>
+        CacheClearEverything,
+
+        /// <summary>
+        /// Get and put (<see cref="ICacheClient{TK,TV}.GetAndPut(TK, TV)"/>).
+        /// </summary>
+        CacheGetAndPut,
+
+        /// <summary>
+        /// Get and remove (<see 
cref="ICacheClient{TK,TV}.GetAndRemove(TK)"/>).
+        /// </summary>
+        CacheGetAndRemove,
+
+        /// <summary>
+        /// Get and replace (<see cref="ICacheClient{TK,TV}.GetAndReplace(TK, 
TV)"/>).
+        /// </summary>
+        CacheGetAndReplace,
+
+        /// <summary>
+        /// Put if absent (<see cref="ICacheClient{TK,TV}.PutIfAbsent(TK, 
TV)"/>).
+        /// </summary>
+        CachePutIfAbsent,
+
+        /// <summary>
+        /// Get and put if absent (<see 
cref="ICacheClient{TK,TV}.GetAndPutIfAbsent(TK, TV)"/>).
+        /// </summary>
+        CacheGetAndPutIfAbsent,
+
+        /// <summary>
+        /// Scan query (<see 
cref="ICacheClient{TK,TV}.Query(Apache.Ignite.Core.Cache.Query.ScanQuery{TK,TV})"/>).
+        /// </summary>
+        QueryScan,
+
+        /// <summary>
+        /// SQL query (<see 
cref="ICacheClient{TK,TV}.Query(Apache.Ignite.Core.Cache.Query.SqlFieldsQuery)"/>).
+        /// </summary>
+        QuerySql,
+
+        /// <summary>
+        /// Continuous query (<see 
cref="ICacheClient{TK,TV}.QueryContinuous"/>).
+        /// </summary>
+        QueryContinuous,
+
+        /// <summary>
+        /// Start transaction (<see cref="ITransactionsClient.TxStart()"/>).
+        /// </summary>
+        TransactionStart,
+
+        /// <summary>
+        /// Get cluster state (<see cref="IClientCluster.IsActive"/>).
+        /// </summary>
+        ClusterGetState,
+
+        /// <summary>
+        /// Change cluster state (<see cref="IClientCluster.SetActive"/>).
+        /// </summary>
+        ClusterChangeState,
+
+        /// <summary>
+        /// Get cluster WAL state (<see cref="IClientCluster.IsWalEnabled"/>).
+        /// </summary>
+        ClusterGetWalState,
+
+        /// <summary>
+        /// Change cluster WAL state (<see cref="IClientCluster.EnableWal"/>, 
<see cref="IClientCluster.DisableWal"/>).
+        /// </summary>
+        ClusterChangeWalState,
+
+        /// <summary>
+        /// Get cluster nodes (<see cref="IClientClusterGroup.GetNodes"/>).
+        /// </summary>
+        ClusterGroupGetNodes,
+
+        /// <summary>
+        /// Execute compute task (<see 
cref="IComputeClient.ExecuteJavaTask{TRes}"/>).
+        /// </summary>
+        ComputeTaskExecute,
+
+        /// <summary>
+        /// Invoke service.
+        /// </summary>
+        ServiceInvoke,
+
+        /// <summary>
+        /// Get service descriptors (<see 
cref="IServicesClient.GetServiceDescriptors"/>).
+        /// </summary>
+        ServiceGetDescriptors,
+
+        /// <summary>
+        /// Get service descriptor (<see 
cref="IServicesClient.GetServiceDescriptor"/>).
+        /// </summary>
+        ServiceGetDescriptor
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryAllPolicy.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryAllPolicy.cs
new file mode 100644
index 0000000..78c901c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryAllPolicy.cs
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    /// <summary>
+    /// Retry policy that always returns <c>true</c>.
+    /// </summary>
+    public class ClientRetryAllPolicy : IClientRetryPolicy
+    {
+        /** <inheritDoc /> */
+        public bool ShouldRetry(IClientRetryPolicyContext context)
+        {
+            return true;
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryReadPolicy.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryReadPolicy.cs
new file mode 100644
index 0000000..63834ac
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/ClientRetryReadPolicy.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Retry policy that returns true for all read-only operations that do 
not modify data.
+    /// </summary>
+    public sealed class ClientRetryReadPolicy : IClientRetryPolicy
+    {
+        /** <inheritDoc /> */
+        public bool ShouldRetry(IClientRetryPolicyContext context)
+        {
+            IgniteArgumentCheck.NotNull(context, nameof(context));
+
+            switch (context.Operation)
+            {
+                case ClientOperationType.CacheGetNames:
+                case ClientOperationType.CacheGet:
+                case ClientOperationType.CacheContainsKey:
+                case ClientOperationType.CacheContainsKeys:
+                case ClientOperationType.CacheGetConfiguration:
+                case ClientOperationType.CacheGetSize:
+                case ClientOperationType.CacheGetAll:
+                case ClientOperationType.QueryScan:
+                case ClientOperationType.QueryContinuous:
+                case ClientOperationType.ClusterGetState:
+                case ClientOperationType.ClusterGetWalState:
+                case ClientOperationType.ClusterGroupGetNodes:
+                case ClientOperationType.ServiceGetDescriptors:
+                case ClientOperationType.ServiceGetDescriptor:
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicy.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicy.cs
new file mode 100644
index 0000000..a4e2fd0
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicy.cs
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    /// <summary>
+    /// Client retry policy determines whether client operations that have 
failed due to a connection issue
+    /// should be retried.
+    /// </summary>
+    public interface IClientRetryPolicy
+    {
+        /// <summary>
+        /// Gets a value indicating whether a client operation that has failed 
due to a connection issue
+        /// should be retried.
+        /// </summary>
+        /// <param name="context">Operation context.</param>
+        /// <returns>
+        /// <c>true</c> if the operation should be retried on another 
connection, <c>false</c> otherwise.
+        /// </returns>
+        bool ShouldRetry(IClientRetryPolicyContext context);
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicyContext.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicyContext.cs
new file mode 100644
index 0000000..692ef1c
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientRetryPolicyContext.cs
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    using System;
+
+    /// <summary>
+    /// Retry policy context. See <see cref="IClientRetryPolicy.ShouldRetry"/>.
+    /// </summary>
+    public interface IClientRetryPolicyContext
+    {
+        /// <summary>
+        /// Gets the client configuration.
+        /// </summary>
+        IgniteClientConfiguration Configuration { get; }
+
+        /// <summary>
+        /// Gets the operation type.
+        /// </summary>
+        ClientOperationType Operation { get; }
+
+        /// <summary>
+        /// Gets the current iteration.
+        /// </summary>
+        int Iteration { get; }
+
+        /// <summary>
+        /// Gets the exception that caused current retry iteration.
+        /// </summary>
+        Exception Exception { get; }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
index cb38b72..3692f2f7 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
@@ -131,6 +131,9 @@ namespace Apache.Ignite.Core.Client
             {
                 TransactionConfiguration = new 
TransactionClientConfiguration(cfg.TransactionConfiguration);
             }
+
+            RetryLimit = cfg.RetryLimit;
+            RetryPolicy = cfg.RetryPolicy;
         }
 
         /// <summary>
@@ -245,6 +248,25 @@ namespace Apache.Ignite.Core.Client
         public TransactionClientConfiguration TransactionConfiguration { get; 
set; }
 
         /// <summary>
+        /// Gets or sets the retry policy. When a request fails due to a 
connection error,
+        /// Ignite will retry the request if the specified policy allows it.
+        /// <para />
+        /// Default is null: operations won't be retried.
+        /// <para />
+        /// See also <see cref="ClientRetryAllPolicy"/>, <see 
cref="ClientRetryReadPolicy"/>, <see cref="RetryLimit"/>.
+        /// </summary>
+        public IClientRetryPolicy RetryPolicy { get; set; }
+
+        /// <summary>
+        /// Gets or sets the retry limit. When a request fails due to a 
connection error,
+        /// Ignite will retry the request if the specified <see 
cref="RetryPolicy"/> allows it. When this property is
+        /// greater than <c>0</c>, Ignite will limit the number of retries.
+        /// <para />
+        /// Default is <c>0</c>: no limit on retries.
+        /// </summary>
+        public int RetryLimit { get; set; }
+
+        /// <summary>
         /// Gets or sets custom binary processor. Internal property for tests.
         /// </summary>
         internal IBinaryProcessor BinaryProcessor { get; set; }
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
 
b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
index b610318..4c3e26f 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
@@ -282,6 +282,18 @@
                         </xs:attribute>
                     </xs:complexType>
                 </xs:element>
+                <xs:element name="retryPolicy" minOccurs="0">
+                    <xs:annotation>
+                        <xs:documentation>Retry policy for failed 
operations.</xs:documentation>
+                    </xs:annotation>
+                    <xs:complexType>
+                        <xs:attribute name="type" type="xs:string" 
use="required">
+                            <xs:annotation>
+                                <xs:documentation>Assembly-qualified type 
name.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                    </xs:complexType>
+                </xs:element>
             </xs:all>
             <xs:attribute name="host" type="xs:string" use="required">
                 <xs:annotation>
@@ -333,6 +345,11 @@
                     <xs:documentation>Password to be used to connect to 
secured cluster.</xs:documentation>
                 </xs:annotation>
             </xs:attribute>
+            <xs:attribute name="retryLimit" type="xs:int">
+                <xs:annotation>
+                    <xs:documentation>Operation retry limit when RetryPolicy 
is set.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
 </xs:schema>
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
index d23bd72..263f4f6 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
@@ -142,7 +142,23 @@ namespace Apache.Ignite.Core.Impl.Client
             Func<ClientResponseContext, T> readFunc,
             Func<ClientStatusCode, string, T> errorFunc = null)
         {
-            return GetSocket().DoOutInOp(opId, writeAction, readFunc, 
errorFunc);
+            var attempt = 0;
+            List<Exception> errors = null;
+
+            while (true)
+            {
+                try
+                {
+                    return GetSocket().DoOutInOp(opId, writeAction, readFunc, 
errorFunc);
+                }
+                catch (Exception e)
+                {
+                    if (!HandleOpError(e, opId, ref attempt, ref errors))
+                    {
+                        throw;
+                    }
+                }
+            }
         }
 
         /// <summary>
@@ -156,15 +172,31 @@ namespace Apache.Ignite.Core.Impl.Client
             TKey key,
             Func<ClientStatusCode, string, T> errorFunc = null)
         {
-            var socket = GetAffinitySocket(cacheId, key) ?? GetSocket();
+            var attempt = 0;
+            List<Exception> errors = null;
 
-            return socket.DoOutInOp(opId, writeAction, readFunc, errorFunc);
+            while (true)
+            {
+                try
+                {
+                    var socket = GetAffinitySocket(cacheId, key) ?? 
GetSocket();
+
+                    return socket.DoOutInOp(opId, writeAction, readFunc, 
errorFunc);
+                }
+                catch (Exception e)
+                {
+                    if (!HandleOpError(e, opId, ref attempt, ref errors))
+                    {
+                        throw;
+                    }
+                }
+            }
         }
 
         /// <summary>
         /// Performs an async send-receive operation with partition awareness.
         /// </summary>
-        public Task<T> DoOutInOpAffinityAsync<T, TKey>(
+        public async Task<T> DoOutInOpAffinityAsync<T, TKey>(
             ClientOp opId,
             Action<ClientRequestContext> writeAction,
             Func<ClientResponseContext, T> readFunc,
@@ -172,18 +204,51 @@ namespace Apache.Ignite.Core.Impl.Client
             TKey key,
             Func<ClientStatusCode, string, T> errorFunc = null)
         {
-            var socket = GetAffinitySocket(cacheId, key) ?? GetSocket();
+            var attempt = 0;
+            List<Exception> errors = null;
 
-            return socket.DoOutInOpAsync(opId, writeAction, readFunc, 
errorFunc);
+            while (true)
+            {
+                try
+                {
+                    var socket = GetAffinitySocket(cacheId, key) ?? 
GetSocket();
+
+                    return await socket.DoOutInOpAsync(opId, writeAction, 
readFunc, errorFunc).ConfigureAwait(false);
+                }
+                catch (Exception e)
+                {
+                    if (!HandleOpError(e, opId, ref attempt, ref errors))
+                    {
+                        throw;
+                    }
+                }
+            }
         }
 
         /// <summary>
         /// Performs an async send-receive operation.
         /// </summary>
-        public Task<T> DoOutInOpAsync<T>(ClientOp opId, 
Action<ClientRequestContext> writeAction,
+        public async Task<T> DoOutInOpAsync<T>(ClientOp opId, 
Action<ClientRequestContext> writeAction,
             Func<ClientResponseContext, T> readFunc, Func<ClientStatusCode, 
string, T> errorFunc = null)
         {
-            return GetSocket().DoOutInOpAsync(opId, writeAction, readFunc, 
errorFunc);
+            var attempt = 0;
+            List<Exception> errors = null;
+
+            while (true)
+            {
+                try
+                {
+                    return await GetSocket().DoOutInOpAsync(opId, writeAction, 
readFunc, errorFunc)
+                        .ConfigureAwait(false);
+                }
+                catch (Exception e)
+                {
+                    if (!HandleOpError(e, opId, ref attempt, ref errors))
+                    {
+                        throw;
+                    }
+                }
+            }
         }
 
         /// <summary>
@@ -338,7 +403,7 @@ namespace Apache.Ignite.Core.Impl.Client
             Justification = "There is no finalizer.")]
         public void Dispose()
         {
-            // Lock order: same as in OnAffinityTopologyVersionChange. 
+            // Lock order: same as in OnAffinityTopologyVersionChange.
             lock (_topologyUpdateLock)
             lock (_socketLock)
             {
@@ -924,5 +989,94 @@ namespace Apache.Ignite.Core.Impl.Client
                     ? BinaryNameMapperMode.BasicSimple
                     : BinaryNameMapperMode.BasicFull;
         }
+
+        /// <summary>
+        /// Gets a value indicating whether a failed operation should be 
retried.
+        /// </summary>
+        /// <param name="exception">Exception that caused the operation to 
fail.</param>
+        /// <param name="op">Operation code.</param>
+        /// <param name="attempt">Current attempt.</param>
+        /// <returns>
+        /// <c>true</c> if the operation should be retried on another 
connection, <c>false</c> otherwise.
+        /// </returns>
+        private bool ShouldRetry(Exception exception, ClientOp op, int attempt)
+        {
+            var e = exception;
+
+            while (e != null && !(e is SocketException))
+            {
+                e = e.InnerException;
+            }
+
+            if (e == null)
+            {
+                // Only retry socket exceptions.
+                return false;
+            }
+
+            if (_config.RetryPolicy == null)
+            {
+                return false;
+            }
+
+            if (_config.RetryLimit > 0 && attempt >= _config.RetryLimit)
+            {
+                return false;
+            }
+
+            var publicOpType = op.ToPublicOperationsType();
+
+            if (publicOpType == null)
+            {
+                // System operation.
+                return true;
+            }
+
+            var ctx = new ClientRetryPolicyContext(_config, 
publicOpType.Value, attempt, exception);
+
+            return _config.RetryPolicy.ShouldRetry(ctx);
+        }
+
+        /// <summary>
+        /// Handles operation error.
+        /// </summary>
+        /// <param name="exception">Error.</param>
+        /// <param name="op">Operation code.</param>
+        /// <param name="attempt">Current attempt.</param>
+        /// <param name="errors">Previous errors.</param>
+        /// <returns>True if the error was handled, false otherwise.</returns>
+        private bool HandleOpError(
+            Exception exception,
+            ClientOp op,
+            ref int attempt,
+            ref List<Exception> errors)
+        {
+            if (!ShouldRetry(exception, op, attempt))
+            {
+                if (errors == null)
+                {
+                    return false;
+                }
+
+                var inner = new AggregateException(errors);
+
+                throw new IgniteClientException(
+                    $"Operation failed after {attempt} retries, examine 
InnerException for details.",
+                    inner);
+            }
+
+            if (errors == null)
+            {
+                errors = new List<Exception> { exception };
+            }
+            else
+            {
+                errors.Add(exception);
+            }
+
+            attempt++;
+
+            return true;
+        }
     }
 }
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs
new file mode 100644
index 0000000..91357cc
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client
+{
+    using Apache.Ignite.Core.Client;
+
+    /// <summary>
+    /// Extensions for <see cref="ClientOp"/>.
+    /// </summary>
+    internal static class ClientOpExtensions
+    {
+        /// <summary>
+        /// Converts the internal op code to a public operation type.
+        /// </summary>
+        /// <param name="op">Operation code.</param>
+        /// <returns>Operation type.</returns>
+        public static ClientOperationType? ToPublicOperationsType(this 
ClientOp op)
+        {
+            switch (op)
+            {
+                case ClientOp.CacheGetOrCreateWithName:
+                case ClientOp.CacheGetOrCreateWithConfiguration:
+                    return ClientOperationType.CacheGetOrCreate;
+
+                case ClientOp.CacheCreateWithConfiguration:
+                case ClientOp.CacheCreateWithName:
+                    return ClientOperationType.CacheCreate;
+
+                case ClientOp.CachePut:
+                    return ClientOperationType.CachePut;
+
+                case ClientOp.CacheGet:
+                    return ClientOperationType.CacheGet;
+
+                case ClientOp.CacheGetNames:
+                    return ClientOperationType.CacheGetNames;
+
+                case ClientOp.CacheDestroy:
+                    return ClientOperationType.CacheDestroy;
+
+                case ClientOp.CacheContainsKey:
+                    return ClientOperationType.CacheContainsKey;
+
+                case ClientOp.CacheContainsKeys:
+                    return ClientOperationType.CacheContainsKeys;
+
+                case ClientOp.CacheGetConfiguration:
+                    return ClientOperationType.CacheGetConfiguration;
+
+                case ClientOp.CacheGetSize:
+                    return ClientOperationType.CacheGetSize;
+
+                case ClientOp.CachePutAll:
+                    return ClientOperationType.CachePutAll;
+
+                case ClientOp.CacheGetAll:
+                    return ClientOperationType.CacheGetAll;
+
+                case ClientOp.CacheReplaceIfEquals:
+                case ClientOp.CacheReplace:
+                    return ClientOperationType.CacheReplace;
+
+                case ClientOp.CacheRemoveKey:
+                case ClientOp.CacheRemoveIfEquals:
+                    return ClientOperationType.CacheRemoveOne;
+
+                case ClientOp.CacheRemoveKeys:
+                    return ClientOperationType.CacheRemoveMultiple;
+
+                case ClientOp.CacheRemoveAll:
+                    return ClientOperationType.CacheRemoveEverything;
+
+                case ClientOp.CacheGetAndPut:
+                    return ClientOperationType.CacheGetAndPut;
+
+                case ClientOp.CacheGetAndRemove:
+                    return ClientOperationType.CacheGetAndRemove;
+
+                case ClientOp.CacheGetAndReplace:
+                    return ClientOperationType.CacheGetAndReplace;
+
+                case ClientOp.CachePutIfAbsent:
+                    return ClientOperationType.CachePutIfAbsent;
+
+                case ClientOp.CacheGetAndPutIfAbsent:
+                    return ClientOperationType.CacheGetAndPutIfAbsent;
+
+                case ClientOp.CacheClear:
+                    return ClientOperationType.CacheClearEverything;
+
+                case ClientOp.CacheClearKey:
+                    return ClientOperationType.CacheClearOne;
+
+                case ClientOp.CacheClearKeys:
+                    return ClientOperationType.CacheClearMultiple;
+
+                case ClientOp.QueryScan:
+                    return ClientOperationType.QueryScan;
+
+                case ClientOp.QuerySql:
+                case ClientOp.QuerySqlFields:
+                    return ClientOperationType.QuerySql;
+
+                case ClientOp.QueryContinuous:
+                    return ClientOperationType.QueryContinuous;
+
+                case ClientOp.TxStart:
+                    return ClientOperationType.TransactionStart;
+
+                case ClientOp.ClusterIsActive:
+                    return ClientOperationType.ClusterGetState;
+
+                case ClientOp.ClusterChangeState:
+                    return ClientOperationType.ClusterChangeState;
+
+                case ClientOp.ClusterGetWalState:
+                    return ClientOperationType.ClusterGetWalState;
+
+                case ClientOp.ClusterChangeWalState:
+                    return ClientOperationType.ClusterChangeWalState;
+
+                case ClientOp.ClusterGroupGetNodeIds:
+                case ClientOp.ClusterGroupGetNodesInfo:
+                    return ClientOperationType.ClusterGroupGetNodes;
+
+                case ClientOp.ComputeTaskExecute:
+                    return ClientOperationType.ComputeTaskExecute;
+
+                case ClientOp.ServiceInvoke:
+                    return ClientOperationType.ServiceInvoke;
+
+                case ClientOp.ServiceGetDescriptors:
+                    return ClientOperationType.ServiceGetDescriptors;
+
+                case ClientOp.ServiceGetDescriptor:
+                    return ClientOperationType.ServiceGetDescriptor;
+
+                default:
+                    return null;
+            }
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRetryPolicyContext.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRetryPolicyContext.cs
new file mode 100644
index 0000000..a1463df
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRetryPolicyContext.cs
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client
+{
+    using System;
+    using Apache.Ignite.Core.Client;
+
+    /// <summary>
+    /// Retry policy context.
+    /// </summary>
+    internal sealed class ClientRetryPolicyContext : IClientRetryPolicyContext
+    {
+        /// <summary>
+        /// Initializes a new instance of <see 
cref="ClientRetryPolicyContext"/> class.
+        /// </summary>
+        /// <param name="configuration">Configuration.</param>
+        /// <param name="operation">Operation.</param>
+        /// <param name="iteration">Iteration.</param>
+        /// <param name="exception">Exception.</param>
+        public ClientRetryPolicyContext(
+            IgniteClientConfiguration configuration,
+            ClientOperationType operation,
+            int iteration,
+            Exception exception)
+        {
+            Configuration = configuration;
+            Operation = operation;
+            Iteration = iteration;
+            Exception = exception;
+        }
+
+        /** <inheritDoc /> */
+        public IgniteClientConfiguration Configuration { get; }
+
+        /** <inheritDoc /> */
+        public ClientOperationType Operation { get; }
+
+        /** <inheritDoc /> */
+        public int Iteration { get; }
+
+        /** <inheritDoc /> */
+        public Exception Exception { get; }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
index c957d93..e5d4c34 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
@@ -18,13 +18,11 @@
 namespace Apache.Ignite.Core.Impl.Common
 {
     using System;
-    using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
     using System.Linq.Expressions;
-    using System.Reflection;
 
     /// <summary>
-    /// Does type casts without extra boxing. 
+    /// Does type casts without extra boxing.
     /// Should be used when casting compile-time incompatible value types 
instead of "(T)(object)x".
     /// </summary>
     /// <typeparam name="T">Target type</typeparam>
@@ -64,7 +62,7 @@ namespace Apache.Ignite.Core.Impl.Common
             /// <summary>
             /// Compiled caster delegate.
             /// </summary>
-            [SuppressMessage("Microsoft.Performance", 
"CA1823:AvoidUnusedPrivateFields", 
+            [SuppressMessage("Microsoft.Performance", 
"CA1823:AvoidUnusedPrivateFields",
                 Justification = "Incorrect warning")]
             [SuppressMessage("Microsoft.Design", 
"CA1000:DoNotDeclareStaticMembersOnGenericTypes",
                 Justification = "Intended usage to leverage compiler 
caching.")]
@@ -125,4 +123,4 @@ namespace Apache.Ignite.Core.Impl.Common
             }
         }
     }
-}
\ No newline at end of file
+}

Reply via email to