http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
index d660b62..8278365 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
@@ -16,6 +16,10 @@
     <NoWarn>1701;1702;1705;NU1701</NoWarn>
   </PropertyGroup>
 
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
   <ItemGroup>
     <Compile 
Include="..\Apache.Ignite.Core.Tests\ApiParity\BinaryParityTest.cs" 
Link="ApiParity\BinaryParityTest.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\ApiParity\CacheAffinityParityTest.cs" 
Link="ApiParity\CacheAffinityParityTest.cs" />
@@ -42,7 +46,12 @@
     <Compile 
Include="..\Apache.Ignite.Core.Tests\ApiParity\TransactionsParityTest.cs" 
Link="ApiParity\TransactionsParityTest.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\AssertExtensions.cs" 
Link="Common\AssertExtensions.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\BinaryConfigurationTest.cs" 
Link="Binary\BinaryConfigurationTest.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\BinaryBuilderSelfTest.cs" 
Link="Binary\BinaryBuilderSelfTest.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\BinaryBuilderSelfTestDynamicRegistration.cs"
 Link="Binary\BinaryBuilderSelfTestDynamicRegistration.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\BinaryDateTimeTest.cs" 
Link="Binary\BinaryDateTimeTest.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Binary\BinarySelfTest.cs" 
Link="Binary\BinarySelfTest.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Binary\EnumsTest.cs" 
Link="Binary\EnumsTest.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Binary\EnumsTestOnline.cs" 
Link="Binary\EnumsTestOnline.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\JavaBinaryInteropTest.cs" 
Link="Binary\JavaBinaryInteropTest.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\Serializable\AdvancedSerializationTest.cs"
 Link="Binary\Serializable\AdvancedSerializationTest.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Binary\Serializable\CallbacksTest.cs" 
Link="Binary\Serializable\CallbacksTest.cs" />
@@ -98,6 +107,7 @@
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientTestBase.cs" 
Link="ThinClient\ClientTestBase.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Client\IgniteClientConfigurationTest.cs" 
Link="ThinClient\IgniteClientConfigurationTest.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Compute\ComputeApiTest.cs" 
Link="Compute\ComputeApiTest.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Compute\ComputeApiTest.JavaTask.cs" 
Link="Compute\ComputeApiTest.JavaTask.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\DataStructures\AtomicLongTest.cs" 
Link="DataStructures\AtomicLongTest.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\DataStructures\AtomicReferenceTest.cs" 
Link="DataStructures\AtomicReferenceTest.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\DataStructures\AtomicSequenceTest.cs" 
Link="DataStructures\AtomicSequenceTest.cs" />
@@ -112,6 +122,10 @@
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Plugin\TestIgnitePluginException.cs" 
Link="Plugin\TestIgnitePluginException.cs" />
     <Compile 
Include="..\Apache.Ignite.Core.Tests\Plugin\TestIgnitePluginProvider.cs" 
Link="Plugin\TestIgnitePluginProvider.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Query\BinarizablePerson.cs" 
Link="Cache\Query\BinarizablePerson.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Services\ServiceProxyTest.cs" 
Link="Services\ServiceProxyTest.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Services\ServicesAsyncWrapper.cs" 
Link="Services\ServicesAsyncWrapper.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Services\ServicesTest.cs" 
Link="Services\ServicesTest.cs" />
+    <Compile 
Include="..\Apache.Ignite.Core.Tests\Services\ServicesTestAsync.cs" 
Link="Services\ServicesTestAsync.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\TaskExtensions.cs" 
Link="Common\TaskExtensions.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\TestUtils.Common.cs" 
Link="Common\TestUtils.Common.cs" />
   </ItemGroup>
@@ -168,6 +182,7 @@
     <Folder Include="DataStructures\" />
     <Folder Include="ApiParity\" />
     <Folder Include="Plugin\" />
+    <Folder Include="Services\" />
     <Folder Include="ThinClient\Cache\" />
   </ItemGroup>
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
index 5837ab1..f03a77a 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
@@ -50,8 +50,6 @@ namespace Apache.Ignite.Core.Tests.Binary
         [TestFixtureSetUp]
         public void SetUp()
         {
-            TestUtils.KillProcesses();
-
             var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
             {
                 BinaryConfiguration = new BinaryConfiguration

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
index fcce021..afe0a9a 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
@@ -30,9 +30,7 @@ namespace Apache.Ignite.Core.Tests.Cache
     using Apache.Ignite.Core.Cache.Expiry;
     using Apache.Ignite.Core.Cluster;
     using Apache.Ignite.Core.Common;
-#if !NETCOREAPP2_0
     using Apache.Ignite.Core.Impl.Cache;
-#endif
     using Apache.Ignite.Core.Tests.Query;
     using Apache.Ignite.Core.Transactions;
     using NUnit.Framework;
@@ -2225,7 +2223,6 @@ namespace Apache.Ignite.Core.Tests.Cache
             }
         }
 
-#if !NETCOREAPP2_0
         /// <summary>
         /// Test skip-store semantics.
         /// </summary>
@@ -2252,7 +2249,6 @@ namespace Apache.Ignite.Core.Tests.Cache
             // Ensure other flags are preserved.
             Assert.IsTrue(((CacheImpl<int, int>) cache.WithKeepBinary<int, 
int>().WithSkipStore()).IsKeepBinary);
         }
-#endif
 
         [Test]
         public void TestRebalance()

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
index 77ae8fe..7a60e9a 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
@@ -556,8 +556,12 @@ namespace Apache.Ignite.Core.Tests.Cache
 
             // Increment keys within tx in different order to cause a deadlock.
             var aex = Assert.Throws<AggregateException>(() =>
-                Task.WaitAll(Task.Factory.StartNew(() => increment(keys0)),
-                             Task.Factory.StartNew(() => 
increment(keys0.Reverse().ToArray()))));
+                Task.WaitAll(new[]
+                    {
+                        Task.Factory.StartNew(() => increment(keys0)),
+                        Task.Factory.StartNew(() => 
increment(keys0.Reverse().ToArray()))
+                    },
+                    TimeSpan.FromSeconds(40)));
 
             Assert.AreEqual(2, aex.InnerExceptions.Count);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
index 92804be..047fc2b 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
@@ -22,10 +22,8 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
     using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Client.Cache;
     using Apache.Ignite.Core.Configuration;
-#if !NETCOREAPP2_0
     using Apache.Ignite.Core.Impl.Client.Cache;
     using Apache.Ignite.Core.Impl.Client;
-#endif
     using Apache.Ignite.Core.Tests.Cache;
     using NUnit.Framework;
 
@@ -152,7 +150,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
             AssertClientConfigsAreEqual(cfg, cache.GetConfiguration());
         }
 
-#if !NETCOREAPP2_0
         /// <summary>
         /// Tests cache creation from partial configuration.
         /// </summary>
@@ -184,7 +181,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
 
             AssertExtensions.ReflectionEqual(cfg, cache.GetConfiguration());
         }
-#endif
 
         /// <summary>
         /// Tests cache creation from configuration.

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/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
index 0bf3c37..1da60b1 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -114,7 +114,6 @@ namespace Apache.Ignite.Core.Tests.Client
             Assert.Throws<ArgumentNullException>(() => 
Ignition.StartClient(new IgniteClientConfiguration()));
         }
 
-#if !NETCOREAPP2_0
         /// <summary>
         /// Tests the incorrect protocol version error.
         /// </summary>
@@ -135,7 +134,6 @@ namespace Apache.Ignite.Core.Tests.Client
                                 "Client version: -1.-1.-1. Server version: 
1.0.0", ex.Message);
             }
         }
-#endif
 
         /// <summary>
         /// Tests that connector can be disabled.

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
index 6c4c00a..cf0ad40 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
@@ -784,19 +784,12 @@ namespace Apache.Ignite.Core.Tests.Compute
                 _grid1.GetCluster().ForRemotes().GetCompute().Broadcast(new 
ExceptionalComputeAction()));
 
             Assert.IsNotNull(ex.InnerException);
-#if NETCOREAPP2_0
-            // Exceptions can't be serialized on .NET Core
-            Assert.AreEqual("Operation is not supported on this platform.",
-                ex.InnerException.Message);
-#else
             Assert.AreEqual("Compute job has failed on remote node, examine 
InnerException for details.",
                 ex.InnerException.Message);
             Assert.IsNotNull(ex.InnerException.InnerException);
             Assert.AreEqual(ExceptionalComputeAction.ErrorText, 
ex.InnerException.InnerException.Message);
-#endif
         }
 
-#if !NETCOREAPP2_0
         /// <summary>
         /// Tests the footer setting.
         /// </summary>
@@ -808,7 +801,6 @@ namespace Apache.Ignite.Core.Tests.Compute
             foreach (var g in new[] {_grid1, _grid2, _grid3})
                 Assert.AreEqual(CompactFooter, 
g.GetConfiguration().BinaryConfiguration.CompactFooter);
         }
-#endif
 
         /// <summary>
         /// Create configuration.

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
index 50d2dbf..543287e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
@@ -119,7 +119,6 @@ namespace Apache.Ignite.Core.Tests.Log
             Assert.IsInstanceOf<ArithmeticException>(err.Exception);
         }
 
-#if !NETCOREAPP2_0  // Exception serialization is not supported in .NET Core
         /// <summary>
         /// Tests that .NET exception propagates through Java to the log.
         /// </summary>
@@ -145,7 +144,6 @@ namespace Apache.Ignite.Core.Tests.Log
                     ((ArithmeticException) 
errFromJava.Exception.InnerException).Message);
             }
         }
-#endif
 
         /// <summary>
         /// Tests the <see cref="QueryEntity"/> validation.

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
index eb6192d..133ffdf 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
@@ -190,6 +190,9 @@ namespace Apache.Ignite.Core.Tests.Services
                             "can't resolve ambiguity.", ex.Message);
         }
 
+        /// <summary>
+        /// Tests the exception.
+        /// </summary>
         [Test]
         public void TestException()
         {
@@ -261,7 +264,7 @@ namespace Apache.Ignite.Core.Tests.Services
         {
             _svc = new TestIgniteService(Binary);
 
-            var prx = new 
ServiceProxy<T>(InvokeProxyMethod).GetTransparentProxy();
+            var prx = ServiceProxyFactory<T>.CreateProxy(InvokeProxyMethod);
 
             Assert.IsFalse(ReferenceEquals(_svc, prx));
 
@@ -315,7 +318,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Test service interface.
         /// </summary>
-        protected interface ITestIgniteServiceProperties
+        public interface ITestIgniteServiceProperties
         {
             /** */
             int IntProp { get; set; }
@@ -330,7 +333,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Test service interface to check ambiguity handling.
         /// </summary>
-        protected interface ITestIgniteServiceAmbiguity
+        public interface ITestIgniteServiceAmbiguity
         {
             /** */
             int AmbiguousMethod(int arg);
@@ -339,7 +342,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Test service interface.
         /// </summary>
-        protected interface ITestIgniteService : ITestIgniteServiceProperties
+        public interface ITestIgniteService : ITestIgniteServiceProperties
         {
             /** */
             void VoidMethod();
@@ -390,7 +393,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Test service interface. Does not derive from actual interface, but 
has all the same method signatures.
         /// </summary>
-        protected interface ITestIgniteServiceProxyInterface
+        public interface ITestIgniteServiceProxyInterface
         {
             /** */
             int IntProp { get; set; }
@@ -570,6 +573,7 @@ namespace Apache.Ignite.Core.Tests.Services
             /** <inheritdoc /> */
             public override int GetHashCode()
             {
+                // ReSharper disable once NonReadonlyMemberInGetHashCode
                 return IntProp.GetHashCode();
             }
 
@@ -653,7 +657,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Binarizable object for method argument/result.
         /// </summary>
-        protected class TestBinarizableClass : IBinarizable
+        public class TestBinarizableClass : IBinarizable
         {
             /** */
             public string Prop { get; set; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
index d3dd9b0..b8f4cdf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
@@ -30,7 +30,6 @@ namespace Apache.Ignite.Core.Tests.Services
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Resource;
     using Apache.Ignite.Core.Services;
-    using Apache.Ignite.Core.Tests.Compute;
     using NUnit.Framework;
 
     /// <summary>
@@ -72,7 +71,6 @@ namespace Apache.Ignite.Core.Tests.Services
         public void SetUp()
         {
             StartGrids();
-            EventsTestHelper.ListenResult = true;
         }
 
         /// <summary>
@@ -96,8 +94,6 @@ namespace Apache.Ignite.Core.Tests.Services
             }
             finally
             {
-                EventsTestHelper.AssertFailures();
-
                 if 
(TestContext.CurrentContext.Test.Name.StartsWith("TestEventTypes"))
                     StopGrids(); // clean events for other tests
             }
@@ -292,7 +288,6 @@ namespace Apache.Ignite.Core.Tests.Services
 
             // Check proxy properties
             Assert.IsNotNull(prx);
-            Assert.AreEqual(prx.GetType(), svc.GetType());
             Assert.AreEqual(prx.ToString(), svc.ToString());
             Assert.AreEqual(17, prx.TestProperty);
             Assert.IsTrue(prx.Initialized);
@@ -352,8 +347,7 @@ namespace Apache.Ignite.Core.Tests.Services
 
             // .. but setter does not
             var ex = Assert.Throws<ServiceInvocationException>(() => { 
prx.TestProperty = new object(); });
-            Assert.IsNotNull(ex.InnerException);
-            Assert.AreEqual("Specified cast is not valid.", 
ex.InnerException.Message);
+            Assert.IsInstanceOf<InvalidCastException>(ex.InnerException);
         }
 
         /// <summary>
@@ -375,7 +369,6 @@ namespace Apache.Ignite.Core.Tests.Services
             Assert.AreEqual(1, desc.AffinityKey);
             Assert.AreEqual(1, desc.MaxPerNodeCount);
             Assert.AreEqual(1, desc.TotalCount);
-            Assert.AreEqual(typeof(TestIgniteServiceSerializable), desc.Type);
             Assert.AreEqual(Grid1.GetCluster().GetLocalNode().Id, 
desc.OriginNodeId);
 
             var top = desc.TopologySnapshot;
@@ -747,11 +740,6 @@ namespace Apache.Ignite.Core.Tests.Services
             // Verify decriptor
             var descriptor = Services.GetServiceDescriptors().Single(x => 
x.Name == javaSvcName);
             Assert.AreEqual(javaSvcName, descriptor.Name);
-            Assert.Throws<ServiceInvocationException>(() =>
-            {
-                // ReSharper disable once UnusedVariable
-                var type = descriptor.Type;
-            });
 
             var svc = Services.GetServiceProxy<IJavaService>(javaSvcName, 
false);
             var binSvc = Services.WithKeepBinary().WithServerKeepBinary()
@@ -833,9 +821,7 @@ namespace Apache.Ignite.Core.Tests.Services
         {
             foreach (var grid in Grids)
             {
-#if !NETCOREAPP2_0
                 Assert.AreEqual(CompactFooter, ((Impl.Ignite) 
grid).Marshaller.CompactFooter);
-#endif
                 Assert.AreEqual(CompactFooter, 
grid.GetConfiguration().BinaryConfiguration.CompactFooter);
             }
         }
@@ -848,9 +834,9 @@ namespace Apache.Ignite.Core.Tests.Services
             if (Grid1 != null)
                 return;
 
-            Grid1 = 
Ignition.Start(GetConfiguration("config\\compute\\compute-grid1.xml"));
-            Grid2 = 
Ignition.Start(GetConfiguration("config\\compute\\compute-grid2.xml"));
-            Grid3 = 
Ignition.Start(GetConfiguration("config\\compute\\compute-grid3.xml"));
+            Grid1 = 
Ignition.Start(GetConfiguration("Config\\Compute\\compute-grid1.xml"));
+            Grid2 = 
Ignition.Start(GetConfiguration("Config\\Compute\\compute-grid2.xml"));
+            Grid3 = 
Ignition.Start(GetConfiguration("Config\\Compute\\compute-grid3.xml"));
 
             Grids = new[] { Grid1, Grid2, Grid3 };
         }
@@ -895,14 +881,16 @@ namespace Apache.Ignite.Core.Tests.Services
         /// </summary>
         private IgniteConfiguration GetConfiguration(string springConfigUrl)
         {
+#if !NETCOREAPP2_0
             if (!CompactFooter)
-                springConfigUrl = 
ComputeApiTestFullFooter.ReplaceFooterSetting(springConfigUrl);
+            {
+                springConfigUrl = 
Compute.ComputeApiTestFullFooter.ReplaceFooterSetting(springConfigUrl);
+            }
+#endif
 
-            return new IgniteConfiguration
+            return new IgniteConfiguration(TestUtils.GetTestConfiguration())
             {
                 SpringConfigUrl = springConfigUrl,
-                JvmClasspath = TestUtils.CreateTestClasspath(),
-                JvmOptions = TestUtils.TestJavaOptions(),
                 BinaryConfiguration = new BinaryConfiguration(
                     typeof (TestIgniteServiceBinarizable),
                     typeof (TestIgniteServiceBinarizableErr),
@@ -952,7 +940,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Test service interface for proxying.
         /// </summary>
-        private interface ITestIgniteService
+        public interface ITestIgniteService
         {
             int TestProperty { get; set; }
 
@@ -982,7 +970,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// Test service interface for proxy usage.
         /// Has some of the original interface members with different 
signatures.
         /// </summary>
-        private interface ITestIgniteServiceProxyInterface
+        public interface ITestIgniteServiceProxyInterface
         {
             /** */
             Guid NodeId { get; }
@@ -1199,7 +1187,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// Java service proxy interface.
         /// </summary>
         [SuppressMessage("ReSharper", "InconsistentNaming")]
-        private interface IJavaService
+        public interface IJavaService
         {
             /** */
             bool isCancelled();
@@ -1315,7 +1303,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Interop class.
         /// </summary>
-        private class PlatformComputeBinarizable
+        public class PlatformComputeBinarizable
         {
             /** */
             public int Field { get; set; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
index 2d735e9..c00ca49 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Common.cs
@@ -26,10 +26,8 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Cluster;
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Static;
-#if !NETCOREAPP2_0
     using Apache.Ignite.Core.Impl;
     using Apache.Ignite.Core.Impl.Binary;
-#endif
     using NUnit.Framework;
 
     /// <summary>
@@ -320,7 +318,6 @@ namespace Apache.Ignite.Core.Tests
         /// <param name="timeout">Timeout, in milliseconds.</param>
         public static void AssertHandleRegistryHasItems(IIgnite grid, int 
expectedCount, int timeout)
         {
-#if !NETCOREAPP2_0
             var handleRegistry = ((Ignite)grid).HandleRegistry;
 
             expectedCount++;  // Skip default lifecycle bean
@@ -336,7 +333,6 @@ namespace Apache.Ignite.Core.Tests
                     grid.Name, expectedCount, handleRegistry.Count,
                     items.Select(x => x.ToString()).Aggregate((x, y) => x + 
"\n" + y));
             }
-#endif
         }
 
         /// <summary>
@@ -349,24 +345,9 @@ namespace Apache.Ignite.Core.Tests
                 Serializer = raw ? new BinaryReflectiveSerializer {RawMode = 
true} : null
             };
 
-#if NETCOREAPP2_0
-            var marshType = 
typeof(IIgnite).Assembly.GetType("Apache.Ignite.Core.Impl.Binary.Marshaller");
-            var marsh = Activator.CreateInstance(marshType, new object[] { 
cfg, null });
-            marshType.GetProperty("CompactFooter").SetValue(marsh, false);
-
-            var bytes = 
marshType.GetMethod("Marshal").MakeGenericMethod(typeof(object))
-                .Invoke(marsh, new object[] { obj });
-
-            var res = marshType.GetMethods().Single(mi =>
-                    mi.Name == "Unmarshal" && 
mi.GetParameters().First().ParameterType == typeof(byte[]))
-                .MakeGenericMethod(typeof(object)).Invoke(marsh, new[] { 
bytes, 0 });
-
-            return (T)res;
-#else
             var marsh = new Marshaller(cfg) { CompactFooter = false };
 
             return marsh.Unmarshal<T>(marsh.Marshal(obj));
-#endif
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/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 cdde538..9a6aeb9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -142,6 +142,9 @@
     <Compile Include="Impl\IPlatformTargetInternal.cs" />
     <Compile Include="Impl\DataRegionMetrics.cs" />
     <Compile Include="Impl\PersistentStore\PersistentStoreMetrics.cs" />
+    <Compile Include="Impl\Services\ServiceMethodHelper.cs" />
+    <Compile Include="Impl\Services\ServiceProxyFactory.cs" />
+    <Compile Include="Impl\Services\ServiceProxyTypeGenerator.cs" />
     <Compile Include="Impl\Shell.cs" />
     <Compile Include="Impl\Unmanaged\Jni\DllLoader.cs" />
     <Compile Include="Impl\Unmanaged\Jni\AppDomains.cs" />
@@ -519,7 +522,6 @@
     <Compile Include="Impl\Resource\ResourceTypeDescriptor.cs" />
     <Compile Include="Impl\Services\ServiceContext.cs" />
     <Compile Include="Impl\Services\ServiceDescriptor.cs" />
-    <Compile Include="Impl\Services\ServiceProxy.cs" />
     <Compile Include="Impl\Services\ServiceProxyInvoker.cs" />
     <Compile Include="Impl\Services\ServiceProxySerializer.cs" />
     <Compile Include="Impl\Services\Services.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceMethodHelper.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceMethodHelper.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceMethodHelper.cs
new file mode 100644
index 0000000..e6fb2c0
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceMethodHelper.cs
@@ -0,0 +1,61 @@
+/*
+ * 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.Services
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Reflection;
+
+    /// <summary>
+    /// Provides reflection information about types.
+    /// This class used by ServiceProxyTypeGenerator and by generated proxy 
(to initialize static field).
+    /// </summary>
+    internal static class ServiceMethodHelper
+    {
+        /// <summary>
+        /// Provides information about virtual methods of the type
+        /// </summary>
+        /// <param name="type">Type to inspect.</param>
+        /// <returns>List of virtual methods.</returns>
+        public static MethodInfo[] GetVirtualMethods(Type type)
+        {
+            Debug.Assert(type != null);
+            var methods = new List<MethodInfo>();
+
+            foreach (var method in type.GetMethods(BindingFlags.Instance | 
BindingFlags.Public |
+                                                   BindingFlags.NonPublic | 
BindingFlags.DeclaredOnly))
+            {
+                if (method.IsVirtual)
+                    methods.Add(method);
+            }
+
+            if (type.IsInterface)
+            {
+                foreach (var method in typeof(object).GetMethods(
+                    BindingFlags.Instance | BindingFlags.Public | 
BindingFlags.DeclaredOnly))
+                {
+                    if (method.IsVirtual)
+                        methods.Add(method);
+                }
+            }
+
+            return methods.ToArray();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxy.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxy.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxy.cs
deleted file mode 100644
index 7952865..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxy.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-#if !NETCOREAPP2_0
-namespace Apache.Ignite.Core.Impl.Services
-{
-    using System;
-    using System.Diagnostics;
-    using System.Diagnostics.CodeAnalysis;
-    using System.Reflection;
-    using System.Runtime.Remoting.Messaging;
-    using System.Runtime.Remoting.Proxies;
-
-    /// <summary>
-    /// Service proxy: user works with a remote service as if it is a local 
object.
-    /// </summary>
-    /// <typeparam name="T">User type to be proxied.</typeparam>
-    internal class ServiceProxy<T> : RealProxy
-    {
-        /** Services. */
-        private readonly Func<MethodBase, object[], object> _invokeAction;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ServiceProxy{T}" /> 
class.
-        /// </summary>
-        /// <param name="invokeAction">Method invoke action.</param>
-        public ServiceProxy(Func<MethodBase, object[], object> invokeAction)
-            : base(typeof (T))
-        {
-            Debug.Assert(invokeAction != null);
-
-            _invokeAction = invokeAction;
-        }
-
-        /** <inheritdoc /> */
-        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of 
public methods")]
-        public override IMessage Invoke(IMessage msg)
-        {
-            var methodCall = msg as IMethodCallMessage;
-
-            if (methodCall == null)
-                throw new NotSupportedException("Service proxy operation type 
not supported: " + msg.GetType() +
-                                                ". Only method and property 
calls are supported.");
-
-            if (methodCall.InArgCount != methodCall.ArgCount)
-                throw new NotSupportedException("Service proxy does not 
support out arguments: "
-                                                + methodCall.MethodBase);
-
-            var result = _invokeAction(methodCall.MethodBase, methodCall.Args);
-
-            return new ReturnMessage(result, null, 0, 
methodCall.LogicalCallContext, methodCall);
-        }
-
-        /** <inheritdoc /> */
-        public new T GetTransparentProxy()
-        {
-            return (T) base.GetTransparentProxy();
-        }
-    }
-}
-#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyFactory.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyFactory.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyFactory.cs
new file mode 100644
index 0000000..a32f10e
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyFactory.cs
@@ -0,0 +1,68 @@
+/*
+ * 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.Services
+{
+    using System;
+    using System.Diagnostics;
+    using System.Linq.Expressions;
+    using System.Reflection;
+    using ProxyAction = System.Func<System.Reflection.MethodBase, object[], 
object>;
+
+    /// <summary>
+    /// Factory for proxy creation.
+    /// </summary>
+    /// <typeparam name="T">User type to be proxied.</typeparam>
+    internal static class ServiceProxyFactory<T>
+    {
+        /** */
+        private static readonly Func<ProxyAction, T> Factory = 
GenerateFactory();
+
+        /// <summary>
+        /// Creates proxy which methods call provided function.
+        /// </summary>
+        /// <param name="action">Action to call.</param>
+        /// <returns>Proxy.</returns>
+        public static T CreateProxy(ProxyAction action)
+        {
+            Debug.Assert(action != null);
+
+            return Factory(action);
+        }
+
+        /// <summary>
+        /// Generates the proxy factory.
+        /// </summary>
+        private static Func<ProxyAction, T> GenerateFactory()
+        {
+            // Generate proxy class
+            var result = ServiceProxyTypeGenerator.Generate(typeof(T));
+            var typeCtr = result.Item1.GetConstructor(new[] { 
typeof(ProxyAction), typeof(MethodInfo[]) });
+            Debug.Assert(typeCtr != null);
+
+            // Generate method that creates proxy class instance.
+            // Single parameter of method
+            var action = Expression.Parameter(typeof(ProxyAction));
+
+            // Call constructor and pass action parameter and array of methods.
+            var ctr = Expression.New(typeCtr, action, 
Expression.Constant(result.Item2));
+            var lambda = Expression.Lambda<Func<ProxyAction, T>>(ctr, action);
+
+            return lambda.Compile();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyTypeGenerator.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyTypeGenerator.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyTypeGenerator.cs
new file mode 100644
index 0000000..97de9c7
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxyTypeGenerator.cs
@@ -0,0 +1,281 @@
+/*
+ * 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.Services
+{
+    using System;
+    using System.Diagnostics;
+    using System.Reflection;
+    using System.Reflection.Emit;
+    using ProxyAction = System.Func<System.Reflection.MethodBase, object[], 
object>;
+
+    /// <summary>
+    /// Emits service proxy type.
+    /// </summary>
+    internal static class ServiceProxyTypeGenerator
+    {
+        /** */
+        private static readonly Type ActionType = typeof(ProxyAction);
+
+        /** */
+        private static readonly MethodInfo InvokeMethod = 
ActionType.GetMethod("Invoke");
+
+        /** */
+        private static readonly ModuleBuilder ModuleBuilder = 
CreateModuleBuilder();
+
+        /// <summary>
+        /// Generates the proxy for specified service type.
+        /// </summary>
+        public static Tuple<Type, MethodInfo[]> Generate(Type serviceType)
+        {
+            Debug.Assert(serviceType != null);
+            Debug.Assert(serviceType.FullName != null);
+
+            var isClass = serviceType.IsClass;
+            var proxyType = ModuleBuilder.DefineType(serviceType.FullName,
+                TypeAttributes.Class, isClass ? serviceType : null);
+
+            var buildContext = new ProxyBuildContext(proxyType, serviceType);
+            if (!isClass)
+            {
+                proxyType.AddInterfaceImplementation(serviceType);
+            }
+
+            GenerateFields(buildContext);
+            GenerateStaticConstructor(buildContext);
+            GenerateConstructor(buildContext);
+
+            buildContext.Methods = 
ServiceMethodHelper.GetVirtualMethods(buildContext.ServiceType);
+            for (var i = 0; i < buildContext.Methods.Length; i++)
+            {
+                GenerateMethod(buildContext, i);
+            }
+
+            var type = proxyType.CreateType();
+            return Tuple.Create(type, buildContext.Methods);
+        }
+
+        /// <summary>
+        /// Creates a builder for a temporary module.
+        /// </summary>
+        private static ModuleBuilder CreateModuleBuilder()
+        {
+            var name = Guid.NewGuid().ToString("N");
+
+#if !NETCOREAPP2_0
+            var assemblyBuilder =
+                AppDomain.CurrentDomain.DefineDynamicAssembly(new 
AssemblyName(name),
+                    AssemblyBuilderAccess.RunAndCollect);
+#else
+            var assemblyBuilder =
+                AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name),
+                    AssemblyBuilderAccess.RunAndCollect);
+#endif
+
+            return assemblyBuilder.DefineDynamicModule(name);
+        }
+
+        /// <summary>
+        /// Generates readonly fields: action and method array.
+        /// </summary>
+        private static void GenerateFields(ProxyBuildContext buildContext)
+        {
+            // Static field - empty object array to optimize calls without 
parameters.
+            buildContext.EmptyParametersField = 
buildContext.ProxyType.DefineField("_emptyParameters",
+                typeof(object[]), FieldAttributes.Static | 
FieldAttributes.Private | FieldAttributes.InitOnly);
+            
+            // Instance field for function to invoke.
+            buildContext.ActionField = 
buildContext.ProxyType.DefineField("_action", ActionType,
+                FieldAttributes.Private | FieldAttributes.InitOnly);
+
+            // Field - array with methods of service's type.
+            buildContext.MethodsField = 
buildContext.ProxyType.DefineField("_methods", typeof(MethodInfo[]),
+                FieldAttributes.Private | FieldAttributes.InitOnly);
+        }
+
+        /// <summary>
+        /// Generates the static constructor (type initializer).
+        /// </summary>
+        private static void GenerateStaticConstructor(ProxyBuildContext 
buildContext)
+        {
+            var cb = buildContext.ProxyType.DefineConstructor(
+                MethodAttributes.Static | MethodAttributes.Private | 
MethodAttributes.HideBySig,
+                CallingConventions.Standard, new Type[0]);
+            var gen = cb.GetILGenerator();
+            //fill _emptyParameters field
+            gen.Emit(OpCodes.Ldc_I4_0);
+            gen.Emit(OpCodes.Newarr, typeof(object));
+            gen.Emit(OpCodes.Stsfld, buildContext.EmptyParametersField);
+
+            gen.Emit(OpCodes.Ret);
+        }
+
+        /// <summary>
+        /// Generates the constructor which calls base class (when necessary) 
and initializes fields.
+        /// </summary>
+        private static void GenerateConstructor(ProxyBuildContext buildContext)
+        {
+            var baseType = buildContext.ServiceType;
+            var isClass = baseType.IsClass;
+
+            ConstructorInfo baseCtr = null;
+            if (isClass)
+            {
+                baseCtr = baseType.GetConstructor(BindingFlags.Instance | 
BindingFlags.NonPublic | BindingFlags.Public,
+                    null, new Type[0], null);
+                if (baseCtr == null)
+                    throw new NotSupportedException(
+                        "Service proxy does not support base types without 
parameterless constructor: " +
+                        baseType.FullName);
+            }
+
+            var cb = 
buildContext.ProxyType.DefineConstructor(MethodAttributes.Public, 
CallingConventions.HasThis,
+                new[] {ActionType, typeof(MethodInfo[])});
+            var gen = cb.GetILGenerator();
+
+            if (isClass)
+            {
+                // Load "this".
+                gen.Emit(OpCodes.Ldarg_0);
+                // Call base constructor.
+                gen.Emit(OpCodes.Call, baseCtr);
+            }
+
+            // Assign parameters to fields.
+            gen.Emit(OpCodes.Ldarg_0);
+            gen.Emit(OpCodes.Ldarg_1);
+            gen.Emit(OpCodes.Stfld, buildContext.ActionField);
+
+            gen.Emit(OpCodes.Ldarg_0);
+            gen.Emit(OpCodes.Ldarg_2);
+            gen.Emit(OpCodes.Stfld, buildContext.MethodsField);
+
+            gen.Emit(OpCodes.Ret);
+        }
+
+        /// <summary>
+        /// Generates the overriding method which delegates to ProxyAction.
+        /// </summary>
+        private static void GenerateMethod(ProxyBuildContext buildContext, int 
methodIndex)
+        {
+            var method = buildContext.Methods[methodIndex];
+            Debug.Assert(method.DeclaringType != null);
+            var parameters = method.GetParameters();
+            var parameterTypes = new Type[parameters.Length];
+            for (var i = 0; i < parameters.Length; i++)
+                parameterTypes[i] = parameters[i].ParameterType;
+
+            var attributes = MethodAttributes.Public | 
MethodAttributes.Virtual | MethodAttributes.HideBySig;
+            if (method.DeclaringType.IsInterface)
+                attributes |= MethodAttributes.Final | 
MethodAttributes.NewSlot;
+            if ((method.Attributes & MethodAttributes.SpecialName) == 
MethodAttributes.SpecialName)
+                attributes |= MethodAttributes.SpecialName;
+            var methodBuilder =
+                buildContext.ProxyType.DefineMethod(method.Name, attributes, 
method.ReturnType, parameterTypes);
+            var gen = methodBuilder.GetILGenerator();
+
+            // Prepare arguments for action invocation.
+
+            // Load action field.
+            gen.Emit(OpCodes.Ldarg_0);
+            gen.Emit(OpCodes.Ldfld, buildContext.ActionField);
+
+            // Load methods array field.
+            gen.Emit(OpCodes.Ldarg_0);
+            gen.Emit(OpCodes.Ldfld, buildContext.MethodsField);
+            
+            // Load index of method.
+            gen.Emit(OpCodes.Ldc_I4, methodIndex);
+            
+            // Load array element.
+            gen.Emit(OpCodes.Ldelem_Ref);
+
+            if (parameters.Length > 0)
+            {
+                // Create array for action's parameters.
+                gen.Emit(OpCodes.Ldc_I4, parameters.Length);
+                gen.Emit(OpCodes.Newarr, typeof(object));
+
+                // Fill array.
+                // Load call arguments.
+                for (var i = 0; i < parameters.Length; i++)
+                {
+                    gen.Emit(OpCodes.Dup);
+                    
+                    // Parameter's index in array.
+                    gen.Emit(OpCodes.Ldc_I4, i);
+                    
+                    // Parameter's value.
+                    gen.Emit(OpCodes.Ldarg, i + 1);
+                    if (parameterTypes[i].IsValueType)
+                    {
+                        gen.Emit(OpCodes.Box, parameterTypes[i]);
+                    }
+
+                    // Set array's element
+                    gen.Emit(OpCodes.Stelem_Ref);
+                }
+            }
+            else
+            {
+                // Load static empty parameters field.
+                gen.Emit(OpCodes.Ldsfld, buildContext.EmptyParametersField);
+            }
+
+            // Call action method.
+            gen.Emit(OpCodes.Callvirt, InvokeMethod);
+
+            // Load result.
+            if (method.ReturnType != typeof(void))
+            {
+                if (method.ReturnType.IsValueType)
+                    gen.Emit(OpCodes.Unbox_Any, method.ReturnType);
+            }
+            else
+            {
+                // Method should not return result, so remove result from 
stack.
+                gen.Emit(OpCodes.Pop);
+            }
+            //exit
+            gen.Emit(OpCodes.Ret);
+        }
+
+        /// <summary>
+        /// Proxy build state.
+        /// </summary>
+        private class ProxyBuildContext
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see 
cref="ProxyBuildContext"/> class.
+            /// </summary>
+            public ProxyBuildContext(TypeBuilder proxyType, Type serviceType)
+            {
+                ProxyType = proxyType;
+                ServiceType = serviceType;
+            }
+
+            /** */ public TypeBuilder ProxyType { get; private set; }
+            /** */ public Type ServiceType { get; private set; }
+
+            /** */ public FieldBuilder MethodsField { get; set; }
+            /** */ public FieldBuilder EmptyParametersField { get; set; }
+            /** */ public FieldBuilder ActionField { get; set; }
+
+            /** */ public MethodInfo[] Methods { get; set; }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
index ce8332b..0360f97 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
@@ -366,7 +366,6 @@ namespace Apache.Ignite.Core.Impl.Services
         /** <inheritDoc /> */
         public T GetServiceProxy<T>(string name, bool sticky) where T : class
         {
-#if !NETCOREAPP2_0
             IgniteArgumentCheck.NotNullOrEmpty(name, "name");
             IgniteArgumentCheck.Ensure(typeof(T).IsInterface, "T", "Service 
proxy type should be an interface: " + typeof(T));
 
@@ -385,11 +384,8 @@ namespace Apache.Ignite.Core.Impl.Services
 
             var platform = 
GetServiceDescriptors().Cast<ServiceDescriptor>().Single(x => x.Name == 
name).Platform;
 
-            return new ServiceProxy<T>((method, args) =>
-                InvokeProxyMethod(javaProxy, method, args, 
platform)).GetTransparentProxy();
-#else
-            throw new Apache.Ignite.Core.Common.IgniteException("Service 
proxies are not supported on .NET Core: IGNITE-7281");
-#endif
+            return ServiceProxyFactory<T>.CreateProxy((method, args) =>
+                InvokeProxyMethod(javaProxy, method, args, platform));
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
index 7dc615c..0c0f44c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
@@ -44,5 +44,7 @@ using System.Runtime.InteropServices;
 [assembly: InternalsVisibleTo("Apache.Ignite.Core.Tests, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100a5bf8e0062a26bde53ccf0f8c42ef5b122a22052f99aecacb7028adcc163050324ee3c75ff40eb0cbe2d0426fa20eca03726cad90d7eb882ff47f5361567a82b676a27565f88b2479d7b9354ae0a1e526ee781b6e11de943d8f4a49efb53765f8c954022bede0fca86c133fab038af8dc88b67d6b6e5b9796d6ca490e699efab")]
 [assembly: InternalsVisibleTo("Apache.Ignite.Benchmarks, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100a3e0c1df4cbedbd4ed0e88808401c69b69ec12575ed1c056ac9f448e018fb29af19d236b7b03563aad66c48ab2045e72971ed098d4f65d4cdd38d65abcb39b4f84c626b22ccab2754375f0e8c97dc304fa146f0eddad5cc40a71803a8f15b0b0bb0bff0d4bf0ff6a64bb1044e0d71e6e2405b83fd4c1f7b3e2cfc2e9d50823d4")]
 [assembly: InternalsVisibleTo("Apache.Ignite.AspNet.Tests, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9380ce05eb74bd7c531f72e9ea615c59d7eceb09bd9795cb3dff1fcf638fd799c2a58a9be42fff156efe1c8cdebb751e27763f6c9a7c80cdc1dc1bbf44283608ef18ccd5017fd57b2b026503637c89c2537f361807f3bdd49265f4d444716159d989342561d324b1a0961640338bb32eaf67f4ae0c95f1b210f65404b0909c6")]
-
+#if NETCOREAPP2_0
+[assembly: InternalsVisibleTo("Apache.Ignite.Core.Tests.DotNetCore")]
+#endif
 #endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java
 
b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java
index f192d59..c9bc7ee 100644
--- 
a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java
+++ 
b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java
@@ -25,17 +25,26 @@ import com.jcraft.jsch.Session;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
 import java.io.PrintStream;
+import java.nio.charset.Charset;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.UUID;
+import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterStartNodeResult;
+import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.cluster.ClusterStartNodeResultImpl;
+import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
+import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter;
+import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
 import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.LoggerResource;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SSH_HOST;
@@ -51,12 +60,30 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
     /** Default Ignite home path for Linux (taken from environment variable). 
*/
     private static final String DFLT_IGNITE_HOME_LINUX = "$IGNITE_HOME";
 
+    /** Windows console encoding */
+    private static final String WINDOWS_ENCODING = "IBM866";
+
+    /** Default start script path for Windows. */
+    private static final String DFLT_SCRIPT_WIN = "bin\\ignite.bat -v -np";
+
     /** Default start script path for Linux. */
     private static final String DFLT_SCRIPT_LINUX = "bin/ignite.sh -v";
 
     /** Date format for log file name. */
     private static final SimpleDateFormat FILE_NAME_DATE_FORMAT = new 
SimpleDateFormat("MM-dd-yyyy--HH-mm-ss");
 
+    /** Used to register successful node start in log */
+    private static final String SUCCESSFUL_START_MSG = "Successfully bound to 
TCP port";
+
+    /**  */
+    private static final long EXECUTE_WAIT_TIME = 1000;
+
+    /**  */
+    private static final long NODE_START_CHECK_PERIOD = 2000;
+
+    /**  */
+    private static final long NODE_START_CHECK_LIMIT = 5;
+
     /** Specification. */
     private final IgniteRemoteStartSpecification spec;
 
@@ -65,13 +92,18 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
 
     /** Logger. */
     @LoggerResource
-    private IgniteLogger log;
+    private transient IgniteLogger log;
+
+    /** Ignite. */
+    @IgniteInstanceResource
+    private transient Ignite ignite;
 
     /**
      * Required by Externalizable.
      */
     public StartNodeCallableImpl() {
         spec = null;
+
         timeout = 0;
 
         assert false;
@@ -87,6 +119,7 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
         assert spec != null;
 
         this.spec = spec;
+
         this.timeout = timeout;
     }
 
@@ -111,6 +144,8 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
 
             boolean win = isWindows(ses);
 
+            info("Windows mode: " + win, spec.logger(), log);
+
             char separator = win ? '\\' : '/';
 
             spec.fixPaths(separator);
@@ -123,30 +158,95 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
             String script = spec.script();
 
             if (script == null)
-                script = DFLT_SCRIPT_LINUX;
+                script = win ? DFLT_SCRIPT_WIN : DFLT_SCRIPT_LINUX;
 
             String cfg = spec.configuration();
 
             if (cfg == null)
                 cfg = "";
 
-            String startNodeCmd;
-            String scriptOutputFileName = FILE_NAME_DATE_FORMAT.format(new 
Date()) + '-'
-                + UUID.randomUUID().toString().substring(0, 8) + ".log";
+            String id = FILE_NAME_DATE_FORMAT.format(new Date()) + '-' + 
UUID.randomUUID().toString().substring(0, 8);
+
+            String scriptOutputFileName = id + ".log";
+
+            int spaceIdx = script.indexOf(' ');
 
-            if (win)
-                throw new UnsupportedOperationException("Apache Ignite cannot 
be auto-started on Windows from IgniteCluster.startNodes(…) API.");
+            String scriptPath = spaceIdx > -1 ? script.substring(0, spaceIdx) 
: script;
+
+            String scriptArgs = spaceIdx > -1 ? script.substring(spaceIdx + 1) 
: "";
+
+            String rmtLogArgs = buildRemoteLogArguments(spec.username(), 
spec.host());
+
+            String scriptOutputDir;
+
+            String dfltTmpDir = igniteHome + separator + "work" + separator + 
"log";
+
+            if (win) {
+                String tmpDir = env(ses, "%TMPDIR%", dfltTmpDir, 
WINDOWS_ENCODING);
+
+                if ("%TMPDIR%".equals(tmpDir))
+                    tmpDir = dfltTmpDir;
+
+                scriptOutputDir = tmpDir + "\\ignite-startNodes";
+            }
             else { // Assume Unix.
-                int spaceIdx = script.indexOf(' ');
+                String logDir = env(ses, "$TMPDIR", dfltTmpDir);
+
+                scriptOutputDir = logDir + "/ignite-startNodes";
+            }
+
+            shell(ses, "mkdir " + scriptOutputDir);
 
-                String scriptPath = spaceIdx > -1 ? script.substring(0, 
spaceIdx) : script;
-                String scriptArgs = spaceIdx > -1 ? script.substring(spaceIdx 
+ 1) : "";
-                String rmtLogArgs = buildRemoteLogArguments(spec.username(), 
spec.host());
-                String tmpDir = env(ses, "$TMPDIR", "/tmp/");
-                String scriptOutputDir = tmpDir + "ignite-startNodes";
+            String scriptOutputPath = scriptOutputDir + separator + 
scriptOutputFileName;
 
-                shell(ses, "mkdir " + scriptOutputDir);
+            String findSuccess;
 
+            if (win) {
+                String scriptFileName = scriptOutputDir + '\\' + id + ".bat";
+
+                String createScript = new SB()
+                    .a("echo \"").a(igniteHome).a('\\').a(scriptPath).a("\" ")
+                    .a(scriptArgs)
+                    .a(!cfg.isEmpty() ? " \"" : "").a(cfg).a(!cfg.isEmpty() ? 
"\"" : "")
+                    .a(rmtLogArgs)
+                    .a(" ^> ").a(scriptOutputPath).a(" ^2^>^&^1")
+                    .a(" > ").a(scriptFileName)
+                    .toString();
+
+                info("Create script with command: " + createScript, 
spec.logger(), log);
+
+                shell(ses, createScript);
+
+                try {
+                    String createTask = new SB()
+                        .a("schtasks /create /f /sc onstart")
+                        .a(" /ru ").a(spec.username())
+                        .a(" /rp ").a(spec.password())
+                        .a(" /tn ").a(id)
+                        .a(" /np /tr \"").a(scriptFileName).a('\"')
+                        .toString();
+
+                    info("Create task with command: " + createTask, 
spec.logger(), log);
+
+                    shell(ses, createTask);
+
+                    String runTask = "schtasks /run /i /tn " + id;
+
+                    info("Run task with command: " + runTask, spec.logger(), 
log);
+
+                    shell(ses, runTask);
+                }
+                finally {
+                    String deleteTask = "schtasks /delete /f /tn " + id;
+
+                    info("Delete task with command: " + deleteTask, 
spec.logger(), log);
+
+                    shell(ses, deleteTask);
+                }
+
+                findSuccess = "find \"" + SUCCESSFUL_START_MSG + "\" " + 
scriptOutputPath;
+            }
+            else { // Assume Unix.
                 // Mac os don't support ~ in double quotes. Trying get home 
path from remote system.
                 if (igniteHome.startsWith("~")) {
                     String homeDir = env(ses, "$HOME", "~");
@@ -154,22 +254,36 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
                     igniteHome = igniteHome.replaceFirst("~", homeDir);
                 }
 
-                startNodeCmd = new SB().
+                String startNodeCmd = new SB()
                     // Console output is consumed, started nodes must use 
Ignite file appenders for log.
-                        a("nohup ").
-                    a("\"").a(igniteHome).a('/').a(scriptPath).a("\"").
-                    a(" ").a(scriptArgs).
-                    a(!cfg.isEmpty() ? " \"" : "").a(cfg).a(!cfg.isEmpty() ? 
"\"" : "").
-                    a(rmtLogArgs).
-                    a(" > 
").a(scriptOutputDir).a("/").a(scriptOutputFileName).a(" 2>& 1 &").
-                    toString();
+                    .a("nohup ")
+                    .a("\"").a(igniteHome).a('/').a(scriptPath).a("\"")
+                    .a(" ").a(scriptArgs)
+                    .a(!cfg.isEmpty() ? " \"" : "").a(cfg).a(!cfg.isEmpty() ? 
"\"" : "")
+                    .a(rmtLogArgs)
+                    .a(" > 
").a(scriptOutputDir).a('/').a(scriptOutputFileName).a(" 2>& 1 &")
+                    .toString();
+
+                info("Starting remote node with SSH command: " + startNodeCmd, 
spec.logger(), log);
+
+                shell(ses, startNodeCmd);
+
+                findSuccess = "grep \"" + SUCCESSFUL_START_MSG + "\" " + 
scriptOutputPath;
             }
 
-            info("Starting remote node with SSH command: " + startNodeCmd, 
spec.logger(), log);
+            for (int i = 0; i < NODE_START_CHECK_LIMIT; ++i) {
+                Thread.sleep(NODE_START_CHECK_PERIOD);
+
+                String res = exec(ses, findSuccess, win ? WINDOWS_ENCODING : 
null);
 
-            shell(ses, startNodeCmd);
+                info("Find result: " + res, spec.logger(), log);
+
+                if (res != null && res.contains(SUCCESSFUL_START_MSG))
+                    return new ClusterStartNodeResultImpl(spec.host(), true, 
null);
+            }
 
-            return new ClusterStartNodeResultImpl(spec.host(), true, null);
+            return new ClusterStartNodeResultImpl(spec.host(), false, "Remote 
node could not start. " +
+                "See log for details: " + scriptOutputPath);
         }
         catch (IgniteInterruptedCheckedException e) {
             return new ClusterStartNodeResultImpl(spec.host(), false, 
e.getMessage());
@@ -203,7 +317,7 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
             try (PrintStream out = new PrintStream(ch.getOutputStream(), 
true)) {
                 out.println(cmd);
 
-                U.sleep(1000);
+                U.sleep(EXECUTE_WAIT_TIME);
             }
         }
         finally {
@@ -238,8 +352,29 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
      * @throws JSchException In case of SSH error.
      */
     private String env(Session ses, String name, String dflt) throws 
JSchException {
+        return env(ses, name, dflt, null);
+    }
+
+    /**
+     * Gets the value of the specified environment variable.
+     *
+     * @param ses SSH session.
+     * @param name environment variable name.
+     * @param dflt default value.
+     * @param encoding Process output encoding, {@code null} for default 
charset encoding.
+     * @return environment variable value.
+     * @throws JSchException In case of SSH error.
+     */
+    private String env(Session ses, String name, String dflt, String encoding) 
throws JSchException {
         try {
-            return exec(ses, "echo " + name);
+            String res = exec(ses, "echo " + name, encoding);
+
+            if (res == null)
+                return dflt;
+
+            res = res.trim();
+
+            return res.isEmpty() ? dflt : res;
         }
         catch (IOException ignored) {
             return dflt;
@@ -256,6 +391,20 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
      * @throws IOException If failed.
      */
     private String exec(Session ses, String cmd) throws JSchException, 
IOException {
+        return exec(ses, cmd, null);
+    }
+
+    /**
+     * Gets the value of the specified environment variable.
+     *
+     * @param ses SSH session.
+     * @param cmd environment variable name.
+     * @param encoding Process output encoding, {@code null} for default 
charset encoding.
+     * @return environment variable value.
+     * @throws JSchException In case of SSH error.
+     * @throws IOException If failed.
+     */
+    private String exec(Session ses, final String cmd, String encoding) throws 
JSchException, IOException {
         ChannelExec ch = null;
 
         try {
@@ -265,9 +414,62 @@ public class StartNodeCallableImpl implements 
StartNodeCallable {
 
             ch.connect();
 
-            try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(ch.getInputStream()))) {
-                return reader.readLine();
+            if (encoding == null)
+                encoding = Charset.defaultCharset().name();
+
+            IgniteEx grid = (IgniteEx)ignite;
+
+            GridTimeoutProcessor proc = grid.context().timeout();
+
+            GridTimeoutObject to = null;
+
+            SB out = null;
+
+            try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(ch.getInputStream(), encoding))) {
+                String line;
+
+                boolean first = true;
+
+                while ((line = reader.readLine()) != null) {
+                    if (first)
+                        out = new SB();
+                    else
+                        out.a('\n');
+
+                    out.a(line);
+
+                    if (first) {
+                        to = new GridTimeoutObjectAdapter(EXECUTE_WAIT_TIME) {
+                            /**  */
+                            private final Thread thread = 
Thread.currentThread();
+
+                            @Override public void onTimeout() {
+                                thread.interrupt();
+                            }
+
+                            @Override public String toString() {
+                                return S.toString("GridTimeoutObject", "cmd", 
cmd, "thread", thread);
+                            }
+                        };
+
+                        assert proc.addTimeoutObject(to) : "Timeout object was 
not added: " + to;
+
+                        first = false;
+                    }
+                }
             }
+            catch (InterruptedIOException ignore) {
+                // No-op.
+            }
+            finally {
+                if (to != null) {
+                    boolean r = proc.removeTimeoutObject(to);
+
+                    assert r || to.endTime() <= U.currentTimeMillis() : 
"Timeout object was not removed: " + to;
+                }
+            }
+
+            return out == null ? null : out.toString();
         }
         finally {
             if (ch != null && ch.isConnected())

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js 
b/modules/web-console/frontend/app/app.js
index 332bc24..7380124 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -92,6 +92,7 @@ import ModelNormalizer from 
'./services/ModelNormalizer.service.js';
 import UnsavedChangesGuard from './services/UnsavedChangesGuard.service';
 import Clusters from './services/Clusters';
 import Caches from './services/Caches';
+import {CSV} from './services/CSV';
 
 import AngularStrapTooltip from './services/AngularStrapTooltip.decorator';
 import AngularStrapSelect from './services/AngularStrapSelect.decorator';
@@ -263,6 +264,7 @@ angular.module('ignite-console', [
 .service('IgniteActivitiesUserDialog', IgniteActivitiesUserDialog)
 .service('Clusters', Clusters)
 .service('Caches', Caches)
+.service(CSV.name, CSV)
 // Controllers.
 .controller(...resetPassword)
 .controller(...profile)

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/components/grid-export/component.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/grid-export/component.js 
b/modules/web-console/frontend/app/components/grid-export/component.js
index 9c239a6..18e41c7 100644
--- a/modules/web-console/frontend/app/components/grid-export/component.js
+++ b/modules/web-console/frontend/app/components/grid-export/component.js
@@ -16,13 +16,18 @@
  */
 
 import template from './template.pug';
+import {CSV} from 'app/services/CSV';
 
 export default {
     template,
     controller: class {
-        static $inject = ['$scope', 'uiGridGroupingConstants', 
'uiGridExporterService', 'uiGridExporterConstants'];
+        static $inject = ['$scope', 'uiGridGroupingConstants', 
'uiGridExporterService', 'uiGridExporterConstants', CSV.name];
 
-        constructor($scope, uiGridGroupingConstants, uiGridExporterService, 
uiGridExporterConstants) {
+        /**
+         * @param {CSV} CSV
+         */
+        constructor($scope, uiGridGroupingConstants, uiGridExporterService, 
uiGridExporterConstants, CSV) {
+            this.CSV = CSV;
             Object.assign(this, { uiGridGroupingConstants, 
uiGridExporterService, uiGridExporterConstants });
         }
 
@@ -42,7 +47,7 @@ export default {
                 data.push(values);
             });
 
-            const csvContent = 
this.uiGridExporterService.formatAsCsv(columnHeaders, data, 
this.gridApi.grid.options.exporterCsvColumnSeparator);
+            const csvContent = 
this.uiGridExporterService.formatAsCsv(columnHeaders, data, 
this.CSV.getSeparator());
             
this.uiGridExporterService.downloadFile(this.gridApi.grid.options.exporterCsvFilename,
 csvContent, this.gridApi.grid.options.exporterOlderExcelCompatibility);
         }
     },

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
 
b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
index 6c55753..62bc269 100644
--- 
a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
+++ 
b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
@@ -91,7 +91,11 @@ export default class IgniteListOfRegisteredUsersCtrl {
             user.adminChanging = true;
 
             AdminData.toggleAdmin(user)
-                .finally(() => user.adminChanging = false);
+                .finally(() => {
+                    $ctrl._updateSelected();
+
+                    user.adminChanging = false;
+                });
         };
 
         const showActivities = () => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/components/page-queries/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-queries/controller.js 
b/modules/web-console/frontend/app/components/page-queries/controller.js
index bd03b22..a871a0d 100644
--- a/modules/web-console/frontend/app/components/page-queries/controller.js
+++ b/modules/web-console/frontend/app/components/page-queries/controller.js
@@ -25,6 +25,8 @@ import { fromPromise } from 'rxjs/observable/fromPromise';
 import { timer } from 'rxjs/observable/timer';
 import { defer } from 'rxjs/observable/defer';
 
+import {CSV} from 'app/services/CSV';
+
 import paragraphRateTemplateUrl from 'views/sql/paragraph-rate.tpl.pug';
 import cacheMetadataTemplateUrl from 'views/sql/cache-metadata.tpl.pug';
 import chartSettingsTemplateUrl from 'views/sql/chart-settings.tpl.pug';
@@ -246,11 +248,15 @@ class Paragraph {
 
 // Controller for SQL notebook screen.
 export default class {
-    static $inject = ['$rootScope', '$scope', '$http', '$q', '$timeout', 
'$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', 
'$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 
'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 
'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 
'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard'];
+    static $inject = ['$rootScope', '$scope', '$http', '$q', '$timeout', 
'$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', 
'$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 
'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 
'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 
'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard', CSV.name];
 
-    constructor($root, $scope, $http, $q, $timeout, $interval, $animate, 
$location, $anchorScroll, $state, $filter, $modal, $popover, Loading, 
LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, 
uiGridExporterConstants, Version, ActivitiesData, JavaTypes, 
IgniteCopyToClipboard) {
+    /**
+     * @param {CSV} CSV
+     */
+    constructor($root, $scope, $http, $q, $timeout, $interval, $animate, 
$location, $anchorScroll, $state, $filter, $modal, $popover, Loading, 
LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, 
uiGridExporterConstants, Version, ActivitiesData, JavaTypes, 
IgniteCopyToClipboard, CSV) {
         const $ctrl = this;
 
+        this.CSV = CSV;
         Object.assign(this, { $root, $scope, $http, $q, $timeout, $interval, 
$animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, 
LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, 
uiGridExporterConstants, Version, ActivitiesData, JavaTypes });
 
         // Define template urls.
@@ -1654,6 +1660,7 @@ export default class {
         };
 
         const _export = (fileName, columnDefs, meta, rows, toClipBoard = 
false) => {
+            const csvSeparator = this.CSV.getSeparator();
             let csvContent = '';
 
             const cols = [];
@@ -1666,7 +1673,7 @@ export default class {
                     excludedCols.push(idx);
             });
 
-            csvContent += cols.join(';') + '\n';
+            csvContent += cols.join(csvSeparator) + '\n';
 
             _.forEach(rows, (row) => {
                 cols.length = 0;
@@ -1689,7 +1696,7 @@ export default class {
                     });
                 }
 
-                csvContent += cols.join(';') + '\n';
+                csvContent += cols.join(csvSeparator) + '\n';
             });
 
             if (toClipBoard)

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/components/web-console-header/component.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/web-console-header/component.js 
b/modules/web-console/frontend/app/components/web-console-header/component.js
index 3b1f2f2..a0a8230 100644
--- 
a/modules/web-console/frontend/app/components/web-console-header/component.js
+++ 
b/modules/web-console/frontend/app/components/web-console-header/component.js
@@ -24,7 +24,7 @@ export default {
         static $inject = ['$rootScope', '$scope', '$state', 'IgniteBranding', 
'UserNotifications'];
 
         static connectedClustersUnvisibleStates = [
-            '403', '404'
+            '403', '404', 'signin'
         ];
 
         constructor($rootScope, $scope, $state, branding, UserNotifications) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js
 
b/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js
index 0c40890..cf14293 100644
--- 
a/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js
+++ 
b/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js
@@ -1479,7 +1479,8 @@ export default class IgniteConfigurationGenerator {
                 .boolProperty('cacheSanityCheckEnabled');
         }
 
-        cfg.boolProperty('lateAffinityAssignment');
+        if (available(['1.0.0', '2.1.0']))
+            cfg.boolProperty('lateAffinityAssignment');
 
         return cfg;
     }
@@ -1509,30 +1510,34 @@ export default class IgniteConfigurationGenerator {
 
     // Generate marshaller group.
     static clusterMarshaller(cluster, available, cfg = 
this.igniteConfigurationBean(cluster)) {
-        const kind = _.get(cluster.marshaller, 'kind');
-        const settings = _.get(cluster.marshaller, kind);
+        if (available(['1.0.0', '2.1.0'])) {
+            const kind = _.get(cluster.marshaller, 'kind');
+            const settings = _.get(cluster.marshaller, kind);
 
-        let bean;
+            let bean;
 
-        switch (kind) {
-            case 'OptimizedMarshaller':
-                bean = new 
Bean('org.apache.ignite.marshaller.optimized.OptimizedMarshaller', 
'marshaller', settings)
-                    .intProperty('poolSize')
-                    .intProperty('requireSerializable');
+            switch (kind) {
+                case 'OptimizedMarshaller':
+                    if (available(['1.0.0', '2.0.0'])) {
+                        bean = new 
Bean('org.apache.ignite.marshaller.optimized.OptimizedMarshaller', 
'marshaller', settings)
+                            .intProperty('poolSize')
+                            .intProperty('requireSerializable');
+                    }
 
-                break;
+                    break;
 
-            case 'JdkMarshaller':
-                bean = new 
Bean('org.apache.ignite.marshaller.jdk.JdkMarshaller', 'marshaller', settings);
+                case 'JdkMarshaller':
+                    bean = new 
Bean('org.apache.ignite.marshaller.jdk.JdkMarshaller', 'marshaller', settings);
 
-                break;
+                    break;
 
-            default:
+                default:
                 // No-op.
-        }
+            }
 
-        if (bean)
-            cfg.beanProperty('marshaller', bean);
+            if (bean)
+                cfg.beanProperty('marshaller', bean);
+        }
 
         cfg.intProperty('marshalLocalJobs');
 
@@ -1881,7 +1886,8 @@ export default class IgniteConfigurationGenerator {
     /**
      * Generate eviction policy object.
      * @param {Object} ccfg Parent configuration.
-     * @param {String} name Property name.
+     * @param {Function} available Function to check feature is supported in 
Ignite current version.
+     * @param {Boolean} near Near cache flag.
      * @param {Object} src Source.
      * @param {Object} dflt Default.
      * @returns {Object} Parent configuration.
@@ -2335,7 +2341,7 @@ export default class IgniteConfigurationGenerator {
         this.cacheNodeFilter(cache, igfs ? [igfs] : [], ccfg);
         this.cacheConcurrency(cache, available, ccfg);
         this.cacheRebalance(cache, ccfg);
-        this.cacheNearServer(cache, ccfg);
+        this.cacheNearServer(cache, available, ccfg);
         this.cacheStatistics(cache, ccfg);
         this.cacheDomains(cache.domains, available, ccfg);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
 
b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
index e5f4804..74b3fc6 100644
--- 
a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
+++ 
b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
@@ -17,7 +17,9 @@
 
 import AbstractTransformer from './AbstractTransformer';
 import StringBuilder from './StringBuilder';
+import VersionService from 'app/services/Version.service';
 
+const versionService = new VersionService();
 const STORE_FACTORY = 
['org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory'];
 
 // Descriptors for generation of demo data.
@@ -884,12 +886,13 @@ export default class IgniteJavaTransformer extends 
AbstractTransformer {
      * Build Java startup class with configuration.
      *
      * @param {Bean} cfg
+     * @param available Function to check target version of generated source 
to appropriate for generation.
      * @param pkg Package name.
      * @param {String} clsName Class name for generate factory class otherwise 
generate code snippet.
      * @param {Array.<Object>} clientNearCaches Is client node.
      * @returns {StringBuilder}
      */
-    static igniteConfiguration(cfg, pkg, clsName, clientNearCaches) {
+    static igniteConfiguration(cfg, available, pkg, clsName, clientNearCaches) 
{
         const sb = new StringBuilder();
 
         sb.append(`package ${pkg};`);
@@ -903,7 +906,7 @@ export default class IgniteJavaTransformer extends 
AbstractTransformer {
             
imports.push('org.apache.ignite.configuration.NearCacheConfiguration');
 
             _.forEach(clientNearCaches, (cache) => {
-                const nearCacheBean = this.generator.cacheNearClient(cache);
+                const nearCacheBean = this.generator.cacheNearClient(cache, 
available);
 
                 nearCacheBean.cacheName = cache.name;
 
@@ -1045,7 +1048,9 @@ export default class IgniteJavaTransformer extends 
AbstractTransformer {
         const clientNearCaches = client ? _.filter(cluster.caches, (cache) =>
             cache.cacheMode === 'PARTITIONED' && _.get(cache, 
'clientNearConfiguration.enabled')) : [];
 
-        return this.igniteConfiguration(cfg, pkg, clsName, clientNearCaches);
+        const available = versionService.since.bind(versionService, 
targetVer.ignite);
+
+        return this.igniteConfiguration(cfg, available, pkg, clsName, 
clientNearCaches);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/f53d8574/modules/web-console/frontend/app/modules/configuration/generator/SpringTransformer.service.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/modules/configuration/generator/SpringTransformer.service.js
 
b/modules/web-console/frontend/app/modules/configuration/generator/SpringTransformer.service.js
index f0bfdb6..9e35e5d 100644
--- 
a/modules/web-console/frontend/app/modules/configuration/generator/SpringTransformer.service.js
+++ 
b/modules/web-console/frontend/app/modules/configuration/generator/SpringTransformer.service.js
@@ -19,6 +19,9 @@ import _ from 'lodash';
 
 import AbstractTransformer from './AbstractTransformer';
 import StringBuilder from './StringBuilder';
+import VersionService from 'app/services/Version.service';
+
+const versionService = new VersionService();
 
 export default class IgniteSpringTransformer extends AbstractTransformer {
     static escapeXml(str) {
@@ -252,10 +255,11 @@ export default class IgniteSpringTransformer extends 
AbstractTransformer {
      * Build final XML.
      *
      * @param {Bean} cfg Ignite configuration.
+     * @param available Function to check target version of generated source 
to appropriate for generation.
      * @param {Boolean} clientNearCaches
      * @returns {StringBuilder}
      */
-    static igniteConfiguration(cfg, clientNearCaches) {
+    static igniteConfiguration(cfg, available, clientNearCaches) {
         const sb = new StringBuilder();
 
         // 0. Add header.
@@ -302,7 +306,7 @@ export default class IgniteSpringTransformer extends 
AbstractTransformer {
         _.forEach(clientNearCaches, (cache) => {
             this.commentBlock(sb, `Configuration of near cache for cache 
"${cache.name}"`);
 
-            this.appendBean(sb, this.generator.cacheNearClient(cache), true);
+            this.appendBean(sb, this.generator.cacheNearClient(cache, 
available), true);
 
             sb.emptyLine();
         });
@@ -322,6 +326,8 @@ export default class IgniteSpringTransformer extends 
AbstractTransformer {
         const clientNearCaches = client ? _.filter(cluster.caches, (cache) =>
             cache.cacheMode === 'PARTITIONED' && _.get(cache, 
'clientNearConfiguration.enabled')) : [];
 
-        return this.igniteConfiguration(cfg, clientNearCaches);
+        const available = versionService.since.bind(versionService, 
targetVer.ignite);
+
+        return this.igniteConfiguration(cfg, available, clientNearCaches);
     }
 }

Reply via email to