ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [2/2] ignite git commit: IGNITE-6368: Initial .NET part of thin client. This closes #2670.
Date Fri, 15 Sep 2017 11:06:03 GMT
IGNITE-6368: Initial .NET part of thin client. This closes #2670.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a00052e9
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a00052e9
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a00052e9

Branch: refs/heads/master
Commit: a00052e94531528c5df0dc4485d8882514b40af4
Parents: 8741acc
Author: Pavel Tupitsyn <ptupitsyn@apache.org>
Authored: Fri Sep 15 14:05:53 2017 +0300
Committer: devozerov <vozerov@gridgain.com>
Committed: Fri Sep 15 14:05:53 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.csproj             |   6 +
 .../Binary/BinaryFooterTest.cs                  |   2 +-
 .../Client/CacheTest.cs                         | 201 ++++++++++++++
 .../Client/CacheTestNoMeta.cs                   | 159 +++++++++++
 .../Client/ClientConnectionTest.cs              | 146 ++++++++++
 .../Client/IgniteClientConfigurationTest.cs     |  42 +++
 .../Apache.Ignite.Core.Tests/Client/Person.cs   |  48 ++++
 .../Client/RawSocketTest.cs                     | 164 ++++++++++++
 .../IgniteConfigurationTest.cs                  |   2 +
 .../Apache.Ignite.Core.csproj                   |   9 +
 .../dotnet/Apache.Ignite.Core/Cache/ICache.cs   |   9 +-
 .../Client/Cache/ICacheClient.cs                |  59 +++++
 .../Apache.Ignite.Core/Client/IIgniteClient.cs  |  44 ++++
 .../Client/IgniteClientConfiguration.cs         | 104 ++++++++
 .../dotnet/Apache.Ignite.Core/IIgnite.cs        |   4 +-
 .../dotnet/Apache.Ignite.Core/Ignition.cs       |  17 ++
 .../Impl/Binary/BinaryProcessorClient.cs        | 113 ++++++++
 .../Impl/Binary/BinaryUtils.cs                  |  16 +-
 .../Apache.Ignite.Core/Impl/Cache/CacheImpl.cs  |   4 +-
 .../Impl/Client/Cache/CacheClient.cs            | 160 +++++++++++
 .../Apache.Ignite.Core/Impl/Client/ClientOp.cs  |  32 +++
 .../Impl/Client/ClientProtocolVersion.cs        | 119 +++++++++
 .../Impl/Client/ClientSocket.cs                 | 263 +++++++++++++++++++
 .../Impl/Client/IgniteClient.cs                 | 152 +++++++++++
 .../Impl/Cluster/ClusterGroupImpl.cs            |   2 +-
 .../Impl/Compute/ComputeJobHolder.cs            |   2 +-
 .../Impl/Deployment/PeerAssemblyResolver.cs     |   4 +-
 .../Impl/Deployment/PeerLoadingObjectHolder.cs  |   2 +-
 .../Apache.Ignite.Core/Impl/ExceptionUtils.cs   |   7 +-
 .../Apache.Ignite.Core/Impl/IIgniteInternal.cs  |  13 +-
 .../dotnet/Apache.Ignite.Core/Impl/Ignite.cs    |  10 +-
 31 files changed, 1891 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index 3f5f9b3..31e95fb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -92,6 +92,12 @@
     <Compile Include="Cache\Query\Linq\CacheLinqTest.Contains.cs" />
     <Compile Include="Cache\Store\CacheStoreSessionTestCodeConfig.cs" />
     <Compile Include="Cache\Store\CacheStoreSessionTestSharedFactory.cs" />
+    <Compile Include="Client\CacheTestNoMeta.cs" />
+    <Compile Include="Client\Person.cs" />
+    <Compile Include="Client\RawSocketTest.cs" />
+    <Compile Include="Client\CacheTest.cs" />
+    <Compile Include="Client\ClientConnectionTest.cs" />
+    <Compile Include="Client\IgniteClientConfigurationTest.cs" />
     <Compile Include="Deployment\CacheGetFunc.cs" />
     <Compile Include="Deployment\GetAddressFunc.cs" />
     <Compile Include="Deployment\PeerAssemblyLoadingAllApisTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
index 5088e5a..9fa4538 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
@@ -137,7 +137,7 @@ namespace Apache.Ignite.Core.Tests.Binary
                 return;
             }
 
-            var cache = ignite.GetOrCreateCache<int, OffsetTest>(
+            var cache = ignite.GetIgnite().GetOrCreateCache<int, OffsetTest>(
                     new CacheConfiguration("offs", new QueryEntity(typeof(int), typeof(OffsetTest))));
 
             // Cache operation.

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
new file mode 100644
index 0000000..2831e57
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
@@ -0,0 +1,201 @@
+/*
+ * 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;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Net;
+    using System.Threading;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Client;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Thin client cache test.
+    /// </summary>
+    public sealed class CacheTest
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+        }
+
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests the cache put / get with primitive data types.
+        /// </summary>
+        [Test]
+        public void TestPutGetPrimitives()
+        {
+            using (var client = GetClient())
+            {
+                GetCache<string>().Put(1, "foo");
+
+                var clientCache = client.GetCache<int?, string>(CacheName);
+
+                clientCache.Put(2, "bar");
+                clientCache[3] = "baz";
+
+                // Existing key.
+                Assert.AreEqual("foo", clientCache.Get(1));
+                Assert.AreEqual("foo", clientCache[1]);
+                Assert.AreEqual("bar", clientCache[2]);
+                Assert.AreEqual("baz", clientCache[3]);
+
+                // Missing key.
+                Assert.Throws<KeyNotFoundException>(() => clientCache.Get(-1));
+
+                // Null key.
+                Assert.Throws<ArgumentNullException>(() => clientCache.Get(null));
+            }
+        }
+
+        /// <summary>
+        /// Tests the cache put / get with user data types.
+        /// </summary>
+        [Test]
+        public void TestPutGetUserObjects([Values(true, false)] bool compactFooter)
+        {
+            var cfg = GetClientConfiguration();
+
+            cfg.BinaryConfiguration = new BinaryConfiguration
+            {
+                CompactFooter = compactFooter
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                var person = new Person {Id = 100, Name = "foo"};
+                var person2 = new Person2 {Id = 200, Name = "bar"};
+                
+                var serverCache = GetCache<Person>();
+                var clientCache = client.GetCache<int?, Person>(CacheName);
+
+                Assert.AreEqual(CacheName, clientCache.Name);
+
+                // Put through server cache.
+                serverCache.Put(1, person);
+
+                // Put through client cache.
+                clientCache.Put(2, person2);
+                clientCache[3] = person2;
+
+                // Read from client cache.
+                Assert.AreEqual("foo", clientCache.Get(1).Name);
+                Assert.AreEqual(100, clientCache[1].Id);
+                Assert.AreEqual(200, clientCache[2].Id);
+                Assert.AreEqual(200, clientCache[3].Id);
+
+                // Read from server cache.
+                Assert.AreEqual("foo", serverCache.Get(1).Name);
+                Assert.AreEqual(100, serverCache[1].Id);
+                Assert.AreEqual(200, serverCache[2].Id);
+                Assert.AreEqual(200, serverCache[3].Id);
+
+                // Null key or value.
+                Assert.Throws<ArgumentNullException>(() => clientCache.Put(10, null));
+                Assert.Throws<ArgumentNullException>(() => clientCache.Put(null, person));
+            }
+        }
+
+        /// <summary>
+        /// Tests client get in multiple threads with a single client.
+        /// </summary>
+        [Test]
+        [Category(TestUtils.CategoryIntensive)]
+        public void TestGetMultithreadedSingleClient()
+        {
+            GetCache<string>().Put(1, "foo");
+
+            using (var client = GetClient())
+            {
+                var clientCache = client.GetCache<int, string>(CacheName);
+
+                TestUtils.RunMultiThreaded(() => Assert.AreEqual("foo", clientCache.Get(1)),
+                    Environment.ProcessorCount, 5);
+            }
+        }
+
+        /// <summary>
+        /// Tests client get in multiple threads with multiple clients.
+        /// </summary>
+        [Test]
+        [Category(TestUtils.CategoryIntensive)]
+        public void TestGetMultithreadedMultiClient()
+        {
+            GetCache<string>().Put(1, "foo");
+
+            // One client per thread.
+            var clients = new ConcurrentDictionary<int, IIgniteClient>();
+
+            TestUtils.RunMultiThreaded(() =>
+                {
+                    var client = clients.GetOrAdd(Thread.CurrentThread.ManagedThreadId, _ => GetClient());
+
+                    var clientCache = client.GetCache<int, string>(CacheName);
+
+                    Assert.AreEqual("foo", clientCache.Get(1));
+                },
+                Environment.ProcessorCount, 5);
+
+            clients.ToList().ForEach(x => x.Value.Dispose());
+        }
+
+        /// <summary>
+        /// Gets the cache.
+        /// </summary>
+        private static ICache<int, T> GetCache<T>()
+        {
+            return Ignition.GetIgnite().GetOrCreateCache<int, T>(CacheName);
+        }
+
+        /// <summary>
+        /// Gets the client.
+        /// </summary>
+        private static IIgniteClient GetClient()
+        {
+            return Ignition.StartClient(GetClientConfiguration());
+        }
+
+        /// <summary>
+        /// Gets the client configuration.
+        /// </summary>
+        private static IgniteClientConfiguration GetClientConfiguration()
+        {
+            return new IgniteClientConfiguration {Host = "127.0.0.1"};
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
new file mode 100644
index 0000000..a011583
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
@@ -0,0 +1,159 @@
+/*
+ * 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 System.Net;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.Metadata;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Client cache test without metadata (no-op binary processor).
+    /// </summary>
+    public class CacheTestNoMeta
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+        }
+
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests the cache put / get with user data types.
+        /// </summary>
+        [Test]
+        public void TestPutGetUserObjects()
+        {
+            var cfg = new IgniteClientConfiguration
+            {
+                BinaryProcessor = new NoopBinaryProcessor(),
+                BinaryConfiguration = new BinaryConfiguration
+                {
+                    CompactFooter = false
+                },
+                Host = IPAddress.Loopback.ToString()
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                var serverCache = Ignition.GetIgnite().GetOrCreateCache<int?, Person>(
+                    new CacheConfiguration(CacheName, new QueryEntity
+                    {
+                        KeyType = typeof(int),
+                        ValueType = typeof(Person),
+                        Fields = new[]
+                        {
+                            new QueryField("id", typeof(int)),
+                            new QueryField("name", typeof(string))
+                        }
+                    }));
+
+                var clientCache = client.GetCache<int?, Person>(CacheName);
+
+                // Put through client cache.
+                clientCache.Put(1, new Person { Id = 100, Name = "foo" });
+                clientCache[2] = new Person { Id = 200, Name = "bar" };
+
+                // Read from client cache.
+                Assert.AreEqual("foo", clientCache.Get(1).Name);
+                Assert.AreEqual(100, clientCache[1].Id);
+                Assert.AreEqual(200, clientCache[2].Id);
+
+                // Read from server cache.
+                Assert.AreEqual("foo", serverCache.Get(1).Name);
+                Assert.AreEqual(100, serverCache[1].Id);
+                Assert.AreEqual(200, serverCache[2].Id);
+
+                // SQL from server cache.
+                var sqlRes = serverCache.Query(new SqlQuery(typeof(Person), "where id = 100")).GetAll().Single();
+                Assert.AreEqual(1, sqlRes.Key);
+                Assert.AreEqual(100, sqlRes.Value.Id);
+                Assert.AreEqual("foo", sqlRes.Value.Name);
+            }
+        }
+
+        /// <summary>
+        /// No-op binary processor (does not send meta to cluster).
+        /// </summary>
+        private class NoopBinaryProcessor : IBinaryProcessor
+        {
+            /** <inheritdoc /> */
+            public BinaryType GetBinaryType(int typeId)
+            {
+                return null;
+            }
+
+            /** <inheritdoc /> */
+            public List<IBinaryType> GetBinaryTypes()
+            {
+                return null;
+            }
+
+            /** <inheritdoc /> */
+            public int[] GetSchema(int typeId, int schemaId)
+            {
+                return null;
+            }
+
+            /** <inheritdoc /> */
+            public void PutBinaryTypes(ICollection<BinaryType> types)
+            {
+                // No-op.
+            }
+
+            /** <inheritdoc /> */
+            public bool RegisterType(int id, string typeName)
+            {
+                return false;
+            }
+
+            /** <inheritdoc /> */
+            public BinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values)
+            {
+                return null;
+            }
+
+            /** <inheritdoc /> */
+            public string GetTypeName(int id)
+            {
+                return null;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
new file mode 100644
index 0000000..8874bb5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -0,0 +1,146 @@
+/*
+ * 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;
+    using System.Linq;
+    using System.Net;
+    using System.Net.Sockets;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Configuration;
+    using Apache.Ignite.Core.Impl.Client;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests client connection: port ranges, version checks, etc.
+    /// </summary>
+    public class ClientConnectionTest
+    {
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests that missing server yields connection refused error.
+        /// </summary>
+        [Test]
+        public void TestNoServerConnectionRefused()
+        {
+            var ex = Assert.Throws<AggregateException>(() => StartClient());
+            var socketEx = ex.InnerExceptions.OfType<SocketException>().First();
+            Assert.AreEqual(SocketError.ConnectionRefused, socketEx.SocketErrorCode);
+        }
+
+        /// <summary>
+        /// Tests that multiple clients can connect to one server.
+        /// </summary>
+        [Test]
+        public void TestMultipleClients()
+        {
+            using (Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var client1 = StartClient();
+                var client2 = StartClient();
+                var client3 = StartClient();
+
+                client1.Dispose();
+                client2.Dispose();
+                client3.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Tests custom connector and client configuration.
+        /// </summary>
+        [Test]
+        [Category(TestUtils.CategoryIntensive)]
+        public void TestCustomConfig()
+        {
+            var servCfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SqlConnectorConfiguration = new SqlConnectorConfiguration
+                {
+                    Host = "localhost",
+                    Port = 2000,
+                    PortRange = 1
+                }
+            };
+
+            var clientCfg = new IgniteClientConfiguration
+            {
+                Host = "localhost",
+                Port = 2000
+            };
+
+            using (Ignition.Start(servCfg))
+            using (Ignition.StartClient(clientCfg))
+            {
+                // No-op.
+            }
+        }
+
+        /// <summary>
+        /// Tests that default configuration throws.
+        /// </summary>
+        [Test]
+        public void TestDefaultConfigThrows()
+        {
+            Assert.Throws<ArgumentNullException>(() => Ignition.StartClient(new IgniteClientConfiguration()));
+        }
+
+        /// <summary>
+        /// Tests the incorrect protocol version error.
+        /// </summary>
+        [Test]
+        [Category(TestUtils.CategoryIntensive)]
+        public void TestIncorrectProtocolVersionError()
+        {
+            using (Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                // ReSharper disable once ObjectCreationAsStatement
+                var ex = Assert.Throws<IgniteException>(() => new ClientSocket(GetClientConfiguration(),
+                    new ClientProtocolVersion(-1, -1, -1)));
+
+                Assert.AreEqual("Client handhsake failed: 'Unsupported version.'. " +
+                                "Client version: -1.-1.-1. Server version: 1.0.0", ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// Starts the client.
+        /// </summary>
+        private static IIgniteClient StartClient()
+        {
+            return Ignition.StartClient(GetClientConfiguration());
+        }
+
+        /// <summary>
+        /// Gets the client configuration.
+        /// </summary>
+        private static IgniteClientConfiguration GetClientConfiguration()
+        {
+            return new IgniteClientConfiguration { Host = IPAddress.Loopback.ToString() };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
new file mode 100644
index 0000000..0734f42
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
@@ -0,0 +1,42 @@
+/*
+ * 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 Apache.Ignite.Core.Client;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests for <see cref="IgniteClientConfiguration"/>.
+    /// </summary>
+    public class IgniteClientConfigurationTest
+    {
+        /// <summary>
+        /// Tests the defaults.
+        /// </summary>
+        [Test]
+        public void TestDefaults()
+        {
+            var cfg = new IgniteClientConfiguration();
+
+            Assert.AreEqual(IgniteClientConfiguration.DefaultPort, cfg.Port);
+            Assert.AreEqual(IgniteClientConfiguration.DefaultSocketBufferSize, cfg.SocketReceiveBufferSize);
+            Assert.AreEqual(IgniteClientConfiguration.DefaultSocketBufferSize, cfg.SocketSendBufferSize);
+            Assert.AreEqual(IgniteClientConfiguration.DefaultTcpNoDelay, cfg.TcpNoDelay);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
new file mode 100644
index 0000000..7f0309f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
@@ -0,0 +1,48 @@
+/*
+ * 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
+{
+    /// <summary>
+    /// Test person.
+    /// </summary>
+    public class Person
+    {
+        /// <summary>
+        /// Gets or sets the identifier.
+        /// </summary>
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the parent.
+        /// </summary>
+        public Person Parent { get;set; }
+    }
+
+    /// <summary>
+    /// Test person 2.
+    /// </summary>
+    public class Person2 : Person
+    {
+        // No-op.
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
new file mode 100644
index 0000000..9e2200f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
@@ -0,0 +1,164 @@
+/*
+ * 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;
+    using System.Net;
+    using System.Net.Sockets;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Configuration;
+    using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests the thin client mode with a raw socket.
+    /// </summary>
+    public class RawSocketTest
+    {
+        /// <summary>
+        /// Tests the socket handshake connection.
+        /// </summary>
+        [Test]
+        public void TestCacheGet()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SqlConnectorConfiguration = new SqlConnectorConfiguration()
+            };
+
+            using (var ignite = Ignition.Start(cfg))
+            {
+                var marsh = ((Ignite) ignite).Marshaller;
+
+                // Create cache.
+                var cacheCfg = new CacheConfiguration("foo", new QueryEntity(typeof(int), typeof(string)));
+                var cache = ignite.CreateCache<int, string>(cacheCfg);
+                cache[1] = "bar";
+
+                // Connect socket.
+                var sock = GetSocket(SqlConnectorConfiguration.DefaultPort);
+                Assert.IsTrue(sock.Connected);
+
+                DoHandshake(sock);
+
+                // Cache get.
+                SendRequest(sock, stream =>
+                {
+                    stream.WriteShort(1);  // OP_GET
+                    stream.WriteLong(1);  // Request id.
+                    var cacheId = BinaryUtils.GetStringHashCode(cache.Name);
+                    stream.WriteInt(cacheId);
+                    stream.WriteByte(0);  // Flags (withSkipStore, etc)
+
+                    var writer = marsh.StartMarshal(stream);
+
+                    writer.WriteObject(1);  // Key
+                });
+
+                var msg = ReceiveMessage(sock);
+                
+                using (var stream = new BinaryHeapStream(msg))
+                {
+                    var reader = marsh.StartUnmarshal(stream);
+
+                    var requestId = reader.ReadLong();
+                    Assert.AreEqual(1, requestId);
+
+                    var res = reader.ReadObject<string>();
+                    Assert.AreEqual(cache[1], res);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Does the handshake.
+        /// </summary>
+        /// <param name="sock">The sock.</param>
+        private static void DoHandshake(Socket sock)
+        {
+            var sentBytes = SendRequest(sock, stream =>
+            {
+                // Handshake.
+                stream.WriteByte(1);
+
+                // Protocol version.
+                stream.WriteShort(1);
+                stream.WriteShort(0);
+                stream.WriteShort(0);
+
+                // Client type: platform.
+                stream.WriteByte(2);
+            });
+
+            Assert.AreEqual(12, sentBytes);
+
+            // ACK.
+            var ack = ReceiveMessage(sock);
+
+            Assert.AreEqual(1, ack.Length);
+            Assert.AreEqual(1, ack[0]);
+        }
+
+        /// <summary>
+        /// Receives the message.
+        /// </summary>
+        private static byte[] ReceiveMessage(Socket sock)
+        {
+            var buf = new byte[4];
+            sock.Receive(buf);
+
+            using (var stream = new BinaryHeapStream(buf))
+            {
+                var size = stream.ReadInt();
+                buf = new byte[size];
+                sock.Receive(buf);
+                return buf;
+            }
+        }
+
+        /// <summary>
+        /// Sends the request.
+        /// </summary>
+        private static int SendRequest(Socket sock, Action<BinaryHeapStream> writeAction)
+        {
+            using (var stream = new BinaryHeapStream(128))
+            {
+                stream.WriteInt(0);  // Reserve message size.
+
+                writeAction(stream);
+
+                stream.WriteInt(0, stream.Position - 4);  // Write message size.
+
+                return sock.Send(stream.GetArray(), stream.Position, SocketFlags.None);
+            }
+        }
+
+        /// <summary>
+        /// Gets the socket.
+        /// </summary>
+        private static Socket GetSocket(int port)
+        {
+            var endPoint = new IPEndPoint(IPAddress.Loopback, port);
+            var sock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+            sock.Connect(endPoint);
+            return sock;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 93d6af3..950f36d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -26,6 +26,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Cache.Affinity.Rendezvous;
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Eviction;
+    using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Communication.Tcp;
     using Apache.Ignite.Core.Configuration;
@@ -87,6 +88,7 @@ namespace Apache.Ignite.Core.Tests
             CheckDefaultValueAttributes(new MemoryPolicyConfiguration());
             CheckDefaultValueAttributes(new SqlConnectorConfiguration());
             CheckDefaultValueAttributes(new PersistentStoreConfiguration());
+            CheckDefaultValueAttributes(new IgniteClientConfiguration());
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 65b8372..615ce90 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -97,12 +97,21 @@
     <Compile Include="Cache\Configuration\MemoryPolicyConfiguration.cs" />
     <Compile Include="Cache\Configuration\PartitionLossPolicy.cs" />
     <Compile Include="Cache\IMemoryMetrics.cs" />
+    <Compile Include="Client\Cache\ICacheClient.cs" />
+    <Compile Include="Client\IgniteClientConfiguration.cs" />
+    <Compile Include="Client\IIgniteClient.cs" />
     <Compile Include="Common\ExceptionFactory.cs" />
     <Compile Include="Configuration\Package-Info.cs" />
     <Compile Include="Impl\Binary\BinaryTypeId.cs" />
     <Compile Include="Impl\Cache\Query\PlatformQueryQursorBase.cs" />
+    <Compile Include="Impl\Binary\BinaryProcessorClient.cs" />
     <Compile Include="Impl\Binary\IBinaryProcessor.cs" />
     <Compile Include="Impl\IIgniteInternal.cs" />
+    <Compile Include="Impl\Client\Cache\CacheClient.cs" />
+    <Compile Include="Impl\Client\ClientOp.cs" />
+    <Compile Include="Impl\Client\ClientProtocolVersion.cs" />
+    <Compile Include="Impl\Client\ClientSocket.cs" />
+    <Compile Include="Impl\Client\IgniteClient.cs" />
     <Compile Include="Impl\IPlatformTargetInternal.cs" />
     <Compile Include="Impl\PersistentStore\PersistentStoreMetrics.cs" />
     <Compile Include="Impl\PlatformDisposableTargetAdapter.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
index 8c7fcf9..f83f279 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
@@ -251,32 +251,33 @@ namespace Apache.Ignite.Core.Cache
         /// </summary>
         /// <param name="key">Key.</param>
         /// <returns>Cache value with the specified key.</returns>
+        /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
         TV this[TK key] { get; set; }
 
         /// <summary>
-        /// Retrieves value mapped to the specified key from cache. Throws an exception if t
+        /// Retrieves value mapped to the specified key from cache.
         ///
         /// If the value is not present in cache, then it will be looked up from swap storage. If
         /// it's not present in swap, or if swap is disable, and if read-through is allowed, value
         /// will be loaded from persistent store.
         /// This method is transactional and will enlist the entry into ongoing transaction if there is one.
-        /// If key is not present in cache, KeyNotFoundException will be thrown.
         /// </summary>
         /// <param name="key">Key.</param>
         /// <returns>Value.</returns>
+        /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
         TV Get(TK key);
 
         /// <summary>
-        /// Retrieves value mapped to the specified key from cache. Throws an exception if t
+        /// Retrieves value mapped to the specified key from cache.
         ///
         /// If the value is not present in cache, then it will be looked up from swap storage. If
         /// it's not present in swap, or if swap is disable, and if read-through is allowed, value
         /// will be loaded from persistent store.
         /// This method is transactional and will enlist the entry into ongoing transaction if there is one.
-        /// If key is not present in cache, KeyNotFoundException will be thrown.
         /// </summary>
         /// <param name="key">Key.</param>
         /// <returns>Value.</returns>
+        /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
         Task<TV> GetAsync(TK key);
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
new file mode 100644
index 0000000..b4cd3c5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.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.Client.Cache
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Client cache API. See <see cref="IIgniteClient.GetCache{K, V}"/>.
+    /// </summary>
+    public interface ICacheClient<TK, TV>
+    {
+        /// <summary>
+        /// Name of this cache (<c>null</c> for default cache).
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Associates the specified value with the specified key in the cache.
+        /// <para />
+        /// If the cache previously contained a mapping for the key,
+        /// the old value is replaced by the specified value.
+        /// </summary>
+        /// <param name="key">Key with which the specified value is to be associated.</param>
+        /// <param name="val">Value to be associated with the specified key.</param>
+        void Put(TK key, TV val);
+
+        /// <summary>
+        /// Retrieves value mapped to the specified key from cache.
+        /// </summary>
+        /// <param name="key">Key.</param>
+        /// <returns>Value.</returns>
+        /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
+        TV Get(TK key);
+
+        /// <summary>
+        /// Gets or sets a cache value with the specified key.
+        /// Shortcut to <see cref="Get"/> and <see cref="Put"/>
+        /// </summary>
+        /// <param name="key">Key.</param>
+        /// <returns>Cache value with the specified key.</returns>
+        /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
+        TV this[TK key] { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
new file mode 100644
index 0000000..ceb8f26
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
@@ -0,0 +1,44 @@
+/*
+ * 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;
+    using Apache.Ignite.Core.Client.Cache;
+
+    /// <summary>
+    /// Main entry point for Ignite Thin Client APIs.
+    /// You can obtain an instance of <see cref="IIgniteClient"/> through <see cref="Ignition.StartClient"/>.
+    /// </summary>
+    public interface IIgniteClient : IDisposable
+    {
+        /// <summary>
+        /// Gets the cache instance for the given name to work with keys and values of specified types.
+        /// <para/>
+        /// You can get instances of <see cref="ICacheClient{TK,TV}"/> of the same name,
+        /// but with different key/value types.
+        /// These will use the same named cache, but only allow working with entries of specified types.
+        /// Attempt to retrieve an entry of incompatible type will result in <see cref="InvalidCastException"/>.
+        /// Use <see cref="GetCache{TK,TV}"/> in order to work with entries of arbitrary types.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        /// <returns>Cache instance for given name.</returns>
+        /// <typeparam name="TK">Cache key type.</typeparam>
+        /// <typeparam name="TV">Cache value type.</typeparam>
+        ICacheClient<TK, TV> GetCache<TK, TV>(string name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
new file mode 100644
index 0000000..3339c65
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
@@ -0,0 +1,104 @@
+/*
+ * 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.ComponentModel;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary;
+
+    /// <summary>
+    /// Ignite thin client configuration.
+    /// <para />
+    /// Ignite thin client connects to a specific Ignite node with a socket and does not start JVM in process.
+    /// This configuration should correspond to <see cref="IgniteConfiguration.SqlConnectorConfiguration"/>
+    /// on a target node.
+    /// </summary>
+    public class IgniteClientConfiguration
+    {
+        /// <summary>
+        /// Default port.
+        /// </summary>
+        public const int DefaultPort = 10800;
+
+        /// <summary>
+        /// Default socket buffer size.
+        /// </summary>
+        public const int DefaultSocketBufferSize = 0;
+
+        /// <summary>
+        /// Default value of <see cref="TcpNoDelay" /> property.
+        /// </summary>
+        public const bool DefaultTcpNoDelay = true;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IgniteClientConfiguration"/> class.
+        /// </summary>
+        public IgniteClientConfiguration()
+        {
+            Port = DefaultPort;
+            SocketSendBufferSize = DefaultSocketBufferSize;
+            SocketReceiveBufferSize = DefaultSocketBufferSize;
+            TcpNoDelay = DefaultTcpNoDelay;
+        }
+
+        /// <summary>
+        /// Gets or sets the host. Should not be null.
+        /// </summary>
+        public string Host { get; set; }
+
+        /// <summary>
+        /// Gets or sets the port.
+        /// </summary>
+        [DefaultValue(DefaultPort)]
+        public int Port { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the socket send buffer. When set to 0, operating system default is used.
+        /// </summary>
+        [DefaultValue(DefaultSocketBufferSize)]
+        public int SocketSendBufferSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the socket receive buffer. When set to 0, operating system default is used.
+        /// </summary>
+        [DefaultValue(DefaultSocketBufferSize)]
+        public int SocketReceiveBufferSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the value for <c>TCP_NODELAY</c> socket option. Each
+        /// socket will be opened using provided value.
+        /// <para />
+        /// Setting this option to <c>true</c> disables Nagle's algorithm
+        /// for socket decreasing latency and delivery time for small messages.
+        /// <para />
+        /// For systems that work under heavy network load it is advisable to set this value to <c>false</c>.
+        /// </summary>
+        [DefaultValue(DefaultTcpNoDelay)]
+        public bool TcpNoDelay { get; set; }
+
+        /// <summary>
+        /// Gets or sets the binary configuration.
+        /// </summary>
+        public BinaryConfiguration BinaryConfiguration { get; set; }
+
+        /// <summary>
+        /// Gets or sets custom binary processor. Internal property for tests.
+        /// </summary>
+        internal IBinaryProcessor BinaryProcessor { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index bf061db..9548aca 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -39,9 +39,9 @@ namespace Apache.Ignite.Core
 
     /// <summary>
     /// Main entry point for all Ignite APIs.
-    /// You can obtain an instance of <c>IGrid</c> through <see cref="Ignition.GetIgnite()"/>,
+    /// You can obtain an instance of <see cref="IIgnite"/> through <see cref="Ignition.GetIgnite()"/>,
     /// or for named grids you can use <see cref="Ignition.GetIgnite(string)"/>. Note that you
-    /// can have multiple instances of <c>IGrid</c> running in the same process by giving
+    /// can have multiple instances of <see cref="IIgnite"/> running in the same process by giving
     /// each instance a different name.
     /// <para/>
     /// All members are thread-safe and may be used concurrently from multiple threads.

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
index 568eea7..1bb6b3d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
@@ -28,11 +28,13 @@ namespace Apache.Ignite.Core
     using System.Threading;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache.Affinity;
+    using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Cache.Affinity;
+    using Apache.Ignite.Core.Impl.Client;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Impl.Handle;
     using Apache.Ignite.Core.Impl.Log;
@@ -730,6 +732,21 @@ namespace Apache.Ignite.Core
         }
 
         /// <summary>
+        /// Connects Ignite lightweight (thin) client to an Ignite node.
+        /// <para />
+        /// Thin client connects to an existing Ignite node with a socket and does not start JVM in process.
+        /// </summary>
+        /// <param name="clientConfiguration">The client configuration.</param>
+        /// <returns>Ignite instance.</returns>
+        public static IIgniteClient StartClient(IgniteClientConfiguration clientConfiguration)
+        {
+            IgniteArgumentCheck.NotNull(clientConfiguration, "clientConfiguration");
+            IgniteArgumentCheck.NotNull(clientConfiguration.Host, "clientConfiguration.Host");
+
+            return new IgniteClient(clientConfiguration);
+        }
+
+        /// <summary>
         /// Handles the DomainUnload event of the CurrentDomain control.
         /// </summary>
         /// <param name="sender">The source of the event.</param>

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
new file mode 100644
index 0000000..26a8e9b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
@@ -0,0 +1,113 @@
+/*
+ * 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.Binary
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary.Metadata;
+    using Apache.Ignite.Core.Impl.Client;
+
+    /// <summary>
+    /// Thin client binary processor.
+    /// </summary>
+    internal class BinaryProcessorClient : IBinaryProcessor
+    {
+        /** Type registry platform id. See org.apache.ignite.internal.MarshallerPlatformIds in Java. */
+        private const byte DotNetPlatformId = 1;
+
+        /** Socket. */
+        private readonly ClientSocket _socket;
+
+        /** Marshaller. */
+        private readonly Marshaller _marsh = BinaryUtils.Marshaller;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryProcessorClient"/> class.
+        /// </summary>
+        /// <param name="socket">The socket.</param>
+        public BinaryProcessorClient(ClientSocket socket)
+        {
+            Debug.Assert(socket != null);
+
+            _socket = socket;
+        }
+
+        /** <inheritdoc /> */
+        public BinaryType GetBinaryType(int typeId)
+        {
+            return _socket.DoOutInOp(ClientOp.BinaryTypeGet, s => s.WriteInt(typeId),
+                s => new BinaryType(_marsh.StartUnmarshal(s), true));
+        }
+
+        /** <inheritdoc /> */
+        public List<IBinaryType> GetBinaryTypes()
+        {
+            throw new NotImplementedException();
+        }
+
+        /** <inheritdoc /> */
+        public int[] GetSchema(int typeId, int schemaId)
+        {
+            return GetBinaryType(typeId).Schema.Get(schemaId);
+        }
+
+        /** <inheritdoc /> */
+        public void PutBinaryTypes(ICollection<BinaryType> types)
+        {
+            Debug.Assert(types != null);
+
+            foreach (var binaryType in types)
+            {
+                var type = binaryType;  // Access to modified closure.
+
+                _socket.DoOutInOp<object>(ClientOp.BinaryTypePut,
+                    s => BinaryProcessor.WriteBinaryType(_marsh.StartMarshal(s), type), null);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public bool RegisterType(int id, string typeName)
+        {
+            return _socket.DoOutInOp(ClientOp.BinaryTypeNamePut, s =>
+            {
+                s.WriteByte(DotNetPlatformId);
+                s.WriteInt(id);
+                _marsh.StartMarshal(s).WriteString(typeName);
+            }, s => s.ReadBool());
+        }
+
+        /** <inheritdoc /> */
+        public BinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values)
+        {
+            throw new NotImplementedException();
+        }
+
+        /** <inheritdoc /> */
+        public string GetTypeName(int id)
+        {
+            return _socket.DoOutInOp(ClientOp.BinaryTypeNameGet, s =>
+                {
+                    s.WriteByte(DotNetPlatformId);
+                    s.WriteInt(id);
+                },
+                s => _marsh.StartUnmarshal(s).ReadString());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
index 1146f35..46e6752 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -1330,11 +1330,9 @@ namespace Apache.Ignite.Core.Impl.Binary
             return res;
         }
 
-        /**
-         * <summary>Get string hash code.</summary>
-         * <param name="val">Value.</param>
-         * <returns>Hash code.</returns>
-         */
+        /// <summary>
+        /// Gets the string hash code using Java algorithm.
+        /// </summary>
         public static int GetStringHashCode(string val)
         {
             if (val == null)
@@ -1353,6 +1351,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Gets the cache identifier.
+        /// </summary>
+        public static int GetCacheId(string cacheName)
+        {
+            return string.IsNullOrEmpty(cacheName) ? 1 : GetStringHashCode(cacheName);
+        }
+
+        /// <summary>
         /// Cleans the name of the field.
         /// </summary>
         public static string CleanFieldName(string fieldName)

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
index 921b5e0..9d45f50 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
@@ -84,7 +84,7 @@ namespace Apache.Ignite.Core.Impl.Cache
             _flagPartitionRecover = flagPartitionRecover;
 
             _txManager = GetConfiguration().AtomicityMode == CacheAtomicityMode.Transactional
-                ? new CacheTransactionManager(_ignite.GetTransactions())
+                ? new CacheTransactionManager(_ignite.GetIgnite().GetTransactions())
                 : null;
 
             _readException = stream => ReadException(Marshaller.StartUnmarshal(stream));
@@ -93,7 +93,7 @@ namespace Apache.Ignite.Core.Impl.Cache
         /** <inheritDoc /> */
         public IIgnite Ignite
         {
-            get { return _ignite; }
+            get { return _ignite.GetIgnite(); }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
new file mode 100644
index 0000000..affa815
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
@@ -0,0 +1,160 @@
+/*
+ * 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.Cache
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.IO;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Client;
+    using Apache.Ignite.Core.Impl.Common;
+    using BinaryWriter = Apache.Ignite.Core.Impl.Binary.BinaryWriter;
+
+    /// <summary>
+    /// Client cache implementation.
+    /// </summary>
+    internal class CacheClient<TK, TV> : ICacheClient<TK, TV>
+    {
+        /** Cache name. */
+        private readonly string _name;
+
+        /** Cache id. */
+        private readonly int _id;
+
+        /** Ignite. */
+        private readonly IgniteClient _ignite;
+
+        /** Marshaller. */
+        private readonly Marshaller _marsh;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheClient{TK, TV}" /> class.
+        /// </summary>
+        /// <param name="ignite">Ignite.</param>
+        /// <param name="name">Cache name.</param>
+        public CacheClient(IgniteClient ignite, string name)
+        {
+            Debug.Assert(ignite != null);
+            Debug.Assert(name != null);
+
+            _name = name;
+            _ignite = ignite;
+            _marsh = _ignite.Marshaller;
+            _id = BinaryUtils.GetCacheId(name);
+        }
+
+        /** <inheritDoc /> */
+        public string Name
+        {
+            get { return _name; }
+        }
+
+        /** <inheritDoc /> */
+        public IIgniteClient Ignite
+        {
+            get { return _ignite; }
+        }
+
+        /** <inheritDoc /> */
+        public TV this[TK key]
+        {
+            get { return Get(key); }
+            set { Put(key, value); }
+        }
+
+        /** <inheritDoc /> */
+        public TV Get(TK key)
+        {
+            IgniteArgumentCheck.NotNull(key, "key");
+
+            return DoOutInOp(ClientOp.CacheGet, w => w.WriteObject(key), UnmarshalNotNull<TV>);
+        }
+
+        /** <inheritDoc /> */
+        public void Put(TK key, TV val)
+        {
+            IgniteArgumentCheck.NotNull(key, "key");
+            IgniteArgumentCheck.NotNull(val, "val");
+
+            DoOutOp(ClientOp.CachePut, w =>
+            {
+                w.WriteObjectDetached(key);
+                w.WriteObjectDetached(val);
+            });
+        }
+
+        /// <summary>
+        /// Does the out in op.
+        /// </summary>
+        private T DoOutInOp<T>(ClientOp opId, Action<BinaryWriter> writeAction,
+            Func<IBinaryStream, T> readFunc)
+        {
+            return _ignite.Socket.DoOutInOp(opId, stream =>
+            {
+                stream.WriteInt(_id);
+                stream.WriteByte(0);  // Flags (skipStore, etc).
+
+                if (writeAction != null)
+                {
+                    var writer = _marsh.StartMarshal(stream);
+
+                    writeAction(writer);
+
+                    _marsh.FinishMarshal(writer);
+                }
+            }, readFunc);
+        }
+
+        /// <summary>
+        /// Does the out op.
+        /// </summary>
+        private void DoOutOp(ClientOp opId, Action<BinaryWriter> writeAction)
+        {
+            DoOutInOp<object>(opId, writeAction, null);
+        }
+
+        /// <summary>
+        /// Unmarshals the value, throwing an exception for nulls.
+        /// </summary>
+        private T UnmarshalNotNull<T>(IBinaryStream stream)
+        {
+            var hdr = stream.ReadByte();
+
+            if (hdr == BinaryUtils.HdrNull)
+            {
+                throw GetKeyNotFoundException();
+            }
+
+            stream.Seek(-1, SeekOrigin.Current);
+
+            return _marsh.Unmarshal<T>(stream);
+        }
+
+        /// <summary>
+        /// Gets the key not found exception.
+        /// </summary>
+        private static KeyNotFoundException GetKeyNotFoundException()
+        {
+            return new KeyNotFoundException("The given key was not present in the cache.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
new file mode 100644
index 0000000..79d7c9e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
@@ -0,0 +1,32 @@
+/*
+ * 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
+{
+    /// <summary>
+    /// Client op code.
+    /// </summary>
+    internal enum ClientOp : short
+    {
+        CacheGet = 1,
+        BinaryTypeNameGet = 2,
+        BinaryTypeGet = 3,
+        CachePut = 4,
+        BinaryTypeNamePut = 5,
+        BinaryTypePut = 6
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
new file mode 100644
index 0000000..bfdf5a3
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+    /// <summary>
+    /// Client protocol version.
+    /// </summary>
+    internal struct ClientProtocolVersion : IEquatable<ClientProtocolVersion>
+    {
+        /** */
+        private readonly short _major;
+
+        /** */
+        private readonly short _minor;
+
+        /** */
+        private readonly short _maintenance;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ClientProtocolVersion"/> struct.
+        /// </summary>
+        public ClientProtocolVersion(short major, short minor, short maintenance)
+        {
+            _major = major;
+            _minor = minor;
+            _maintenance = maintenance;
+        }
+
+        /// <summary>
+        /// Gets the major part.
+        /// </summary>
+        public short Major
+        {
+            get { return _major; }
+        }
+
+        /// <summary>
+        /// Gets the minor part.
+        /// </summary>
+        public short Minor
+        {
+            get { return _minor; }
+        }
+
+        /// <summary>
+        /// Gets the maintenance part.
+        /// </summary>
+        public short Maintenance
+        {
+            get { return _maintenance; }
+        }
+
+        /// <summary>
+        /// Returns a value indicating whether specified instance equals to current.
+        /// </summary>
+        public bool Equals(ClientProtocolVersion other)
+        {
+            return _major == other._major && _minor == other._minor && _maintenance == other._maintenance;
+        }
+
+        /** <inheritdoc /> */
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj))
+            {
+                return false;
+            }
+
+            return obj is ClientProtocolVersion && Equals((ClientProtocolVersion) obj);
+        }
+
+        /** <inheritdoc /> */
+        public static bool operator ==(ClientProtocolVersion left, ClientProtocolVersion right)
+        {
+            return left.Equals(right);
+        }
+
+        /** <inheritdoc /> */
+        public static bool operator !=(ClientProtocolVersion left, ClientProtocolVersion right)
+        {
+            return !left.Equals(right);
+        }
+
+        /** <inheritdoc /> */
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hashCode = _major.GetHashCode();
+                hashCode = (hashCode * 397) ^ _minor.GetHashCode();
+                hashCode = (hashCode * 397) ^ _maintenance.GetHashCode();
+                return hashCode;
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override string ToString()
+        {
+            return string.Format("{0}.{1}.{2}", Major, Minor, Maintenance);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
new file mode 100644
index 0000000..0204ef8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
@@ -0,0 +1,263 @@
+/*
+ * 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 System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
+    using System.Net;
+    using System.Net.Sockets;
+    using System.Threading;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+
+    /// <summary>
+    /// Wrapper over framework socket for Ignite thin client operations.
+    /// </summary>
+    internal class ClientSocket : IDisposable
+    {
+        /** Current version. */
+        private static readonly ClientProtocolVersion CurrentProtocolVersion = new ClientProtocolVersion(1, 0, 0);
+
+        /** Handshake opcode. */
+        private const byte OpHandshake = 1;
+
+        /** Client type code. */
+        private const byte ClientType = 2;
+
+        /** Unerlying socket. */
+        private readonly Socket _socket;
+
+        /** */
+        private long _requestId;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ClientSocket" /> class.
+        /// </summary>
+        /// <param name="clientConfiguration">The client configuration.</param>
+        /// <param name="version">Protocol version.</param>
+        public ClientSocket(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion? version = null)
+        {
+            Debug.Assert(clientConfiguration != null);
+
+            _socket = Connect(clientConfiguration);
+
+            Handshake(_socket, version ?? CurrentProtocolVersion);
+        }
+
+        /// <summary>
+        /// Performs a send-receive operation.
+        /// </summary>
+        public T DoOutInOp<T>(ClientOp opId, Action<IBinaryStream> writeAction,
+            Func<IBinaryStream, T> readFunc)
+        {
+            var requestId = Interlocked.Increment(ref _requestId);
+
+            var resBytes = SendReceive(_socket, stream =>
+            {
+                stream.WriteShort((short) opId);
+                stream.WriteLong(requestId);
+
+                if (writeAction != null)
+                {
+                    writeAction(stream);
+                }
+            });
+
+            using (var stream = new BinaryHeapStream(resBytes))
+            {
+                var resRequestId = stream.ReadLong();
+                Debug.Assert(requestId == resRequestId);
+
+                if (readFunc != null)
+                {
+                    return readFunc(stream);
+                }
+            }
+
+            return default(T);
+        }
+
+        /// <summary>
+        /// Performs client protocol handshake.
+        /// </summary>
+        private static void Handshake(Socket sock, ClientProtocolVersion version)
+        {
+            var res = SendReceive(sock, stream =>
+            {
+                // Handshake.
+                stream.WriteByte(OpHandshake);
+
+                // Protocol version.
+                stream.WriteShort(version.Major);
+                stream.WriteShort(version.Minor);
+                stream.WriteShort(version.Maintenance);
+
+                // Client type: platform.
+                stream.WriteByte(ClientType);
+            }, 20);
+
+            using (var stream = new BinaryHeapStream(res))
+            {
+                var success = stream.ReadBool();
+
+                if (success)
+                {
+                    return;
+                }
+
+                var serverVersion =
+                    new ClientProtocolVersion(stream.ReadShort(), stream.ReadShort(), stream.ReadShort());
+
+                var errMsg = BinaryUtils.Marshaller.Unmarshal<string>(stream);
+
+                throw new IgniteException(string.Format(
+                    "Client handhsake failed: '{0}'. Client version: {1}. Server version: {2}",
+                    errMsg, version, serverVersion));
+            }
+        }
+
+        /// <summary>
+        /// Sends the request and receives a response.
+        /// </summary>
+        private static byte[] SendReceive(Socket sock, Action<IBinaryStream> writeAction, int bufSize = 128)
+        {
+            int messageLen;
+            var buf = WriteMessage(writeAction, bufSize, out messageLen);
+
+            lock (sock)
+            {
+                var sent = sock.Send(buf, messageLen, SocketFlags.None);
+                Debug.Assert(sent == messageLen);
+
+                buf = new byte[4];
+                var received = sock.Receive(buf);
+                Debug.Assert(received == buf.Length);
+
+                using (var stream = new BinaryHeapStream(buf))
+                {
+                    var size = stream.ReadInt();
+                    
+                    buf = new byte[size];
+                    received = sock.Receive(buf);
+                    Debug.Assert(received == buf.Length);
+
+                    return buf;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Writes the message to a byte array.
+        /// </summary>
+        private static byte[] WriteMessage(Action<IBinaryStream> writeAction, int bufSize, out int messageLen)
+        {
+            using (var stream = new BinaryHeapStream(bufSize))
+            {
+                stream.WriteInt(0); // Reserve message size.
+
+                writeAction(stream);
+
+                stream.WriteInt(0, stream.Position - 4); // Write message size.
+
+                messageLen = stream.Position;
+
+                return stream.GetArray();
+            }
+        }
+
+        /// <summary>
+        /// Connects the socket.
+        /// </summary>
+        private static Socket Connect(IgniteClientConfiguration cfg)
+        {
+            List<Exception> errors = null;
+
+            foreach (var ipEndPoint in GetEndPoints(cfg))
+            {
+                try
+                {
+                    var socket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
+                    {
+                        SendBufferSize = cfg.SocketSendBufferSize,
+                        ReceiveBufferSize = cfg.SocketReceiveBufferSize,
+                        NoDelay = cfg.TcpNoDelay
+                    };
+
+                    socket.Connect(ipEndPoint);
+
+                    return socket;
+                }
+                catch (SocketException e)
+                {
+                    if (errors == null)
+                    {
+                        errors = new List<Exception>();
+                    }
+
+                    errors.Add(e);
+                }
+            }
+
+            if (errors == null)
+            {
+                throw new IgniteException("Failed to resolve client host: " + cfg.Host);
+            }
+
+            throw new AggregateException("Failed to establish Ignite thin client connection, " +
+                                         "examine inner exceptions for details.", errors);
+        }
+
+        /// <summary>
+        /// Gets the endpoints: all combinations of IP addresses and ports according to configuration.
+        /// </summary>
+        private static IEnumerable<IPEndPoint> GetEndPoints(IgniteClientConfiguration cfg)
+        {
+            var host = cfg.Host;
+
+            if (host == null)
+            {
+                throw new IgniteException("IgniteClientConfiguration.Host cannot be null.");
+            }
+
+            // GetHostEntry accepts IPs, but TryParse is a more efficient shortcut.
+            IPAddress ip;
+
+            if (IPAddress.TryParse(host, out ip))
+            {
+                return new[] {new IPEndPoint(ip, cfg.Port)};
+            }
+
+            return Dns.GetHostEntry(host).AddressList.Select(x => new IPEndPoint(x, cfg.Port));
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
+            Justification = "There is no finalizer.")]
+        public void Dispose()
+        {
+            _socket.Dispose();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
new file mode 100644
index 0000000..29b8a2c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
@@ -0,0 +1,152 @@
+/*
+ * 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 System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Datastream;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Client.Cache;
+    using Apache.Ignite.Core.Impl.Cluster;
+    using Apache.Ignite.Core.Impl.Common;
+    using Apache.Ignite.Core.Impl.Handle;
+    using Apache.Ignite.Core.Impl.Plugin;
+
+    /// <summary>
+    /// Thin client implementation
+    /// </summary>
+    internal class IgniteClient : IIgniteInternal, IIgniteClient
+    {
+        /** Socket. */
+        private readonly ClientSocket _socket;
+
+        /** Marshaller. */
+        private readonly Marshaller _marsh;
+
+        /** Binary processor. */
+        private readonly IBinaryProcessor _binProc;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IgniteClient"/> class.
+        /// </summary>
+        /// <param name="clientConfiguration">The client configuration.</param>
+        public IgniteClient(IgniteClientConfiguration clientConfiguration)
+        {
+            Debug.Assert(clientConfiguration != null);
+
+            _socket = new ClientSocket(clientConfiguration);
+
+            _marsh = new Marshaller(clientConfiguration.BinaryConfiguration)
+            {
+                Ignite = this
+            };
+
+            _binProc = clientConfiguration.BinaryProcessor ?? new BinaryProcessorClient(_socket);
+        }
+
+        /// <summary>
+        /// Gets the socket.
+        /// </summary>
+        public ClientSocket Socket
+        {
+            get { return _socket; }
+        }
+
+        /** <inheritDoc /> */
+        [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
+            Justification = "There is no finalizer.")]
+        public void Dispose()
+        {
+            _socket.Dispose();
+        }
+
+        /** <inheritDoc /> */
+        public ICacheClient<TK, TV> GetCache<TK, TV>(string name)
+        {
+            IgniteArgumentCheck.NotNull(name, "name");
+
+            return new CacheClient<TK, TV>(this, name);
+        }
+
+        /** <inheritDoc /> */
+        public IIgnite GetIgnite()
+        {
+            throw GetClientNotSupportedException();
+        }
+
+        /** <inheritDoc /> */
+        public IBinary GetBinary()
+        {
+            throw GetClientNotSupportedException();
+        }
+
+        /** <inheritDoc /> */
+        public IBinaryProcessor BinaryProcessor
+        {
+            get { return _binProc; }
+        }
+
+        /** <inheritDoc /> */
+        public IgniteConfiguration Configuration
+        {
+            get { throw GetClientNotSupportedException(); }
+        }
+
+        /** <inheritDoc /> */
+        public HandleRegistry HandleRegistry
+        {
+            get { throw GetClientNotSupportedException(); }
+        }
+
+        /** <inheritDoc /> */
+        public ClusterNodeImpl GetNode(Guid? id)
+        {
+            throw GetClientNotSupportedException();
+        }
+
+        /** <inheritDoc /> */
+        public Marshaller Marshaller
+        {
+            get { return _marsh; }
+        }
+
+        /** <inheritDoc /> */
+        public PluginProcessor PluginProcessor
+        {
+            get { throw GetClientNotSupportedException(); }
+        }
+
+        /** <inheritDoc /> */
+        public IDataStreamer<TK, TV> GetDataStreamer<TK, TV>(string cacheName, bool keepBinary)
+        {
+            throw GetClientNotSupportedException();
+        }
+
+        /// <summary>
+        /// Gets the client not supported exception.
+        /// </summary>
+        private static NotSupportedException GetClientNotSupportedException()
+        {
+            return new NotSupportedException("Operation is not supported in thin client mode.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
index 6d6756f..b32d331 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
@@ -190,7 +190,7 @@ namespace Apache.Ignite.Core.Impl.Cluster
         /** <inheritDoc /> */
         public IIgnite Ignite
         {
-            get { return _ignite; }
+            get { return _ignite.GetIgnite(); }
         }
 
         /** <inheritDoc /> */

http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
index 945f2ab..1489f59 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
@@ -86,7 +86,7 @@ namespace Apache.Ignite.Core.Impl.Compute
                 success ? null : new IgniteException("Compute job has failed on local node, " +
                                                      "examine InnerException for details.", (Exception) res), 
                 _job, 
-                _ignite.GetCluster().GetLocalNode().Id, 
+                _ignite.GetIgnite().GetCluster().GetLocalNode().Id, 
                 cancel
             );
         }


Mime
View raw message