You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/03/31 13:32:14 UTC

[1/5] ignite git commit: IGNITE-2703 .NET: Dynamic type registration

Repository: ignite
Updated Branches:
  refs/heads/master 2ad2365a0 -> 79bac4f87


http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Binary/Address.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Binary/Address.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Binary/Address.cs
index 7053e78..0bacdb7 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Binary/Address.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Binary/Address.cs
@@ -17,14 +17,12 @@
 
 namespace Apache.Ignite.ExamplesDll.Binary
 {
-    using System;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache.Configuration;
 
     /// <summary>
     /// Address.
     /// </summary>
-    [Serializable]
     public class Address : IBinarizable
     {
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Compute/CharacterCountClosure.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Compute/CharacterCountClosure.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Compute/CharacterCountClosure.cs
index a34c3fa..9d407cf 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Compute/CharacterCountClosure.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Compute/CharacterCountClosure.cs
@@ -23,7 +23,6 @@ namespace Apache.Ignite.ExamplesDll.Compute
     /// <summary>
     /// Closure counting characters in a string.
     /// </summary>
-    [Serializable]
     public class CharacterCountClosure : IComputeFunc<string, int>
     {
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/ContinuousQueryFilter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/ContinuousQueryFilter.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/ContinuousQueryFilter.cs
index f569f3e..e8d4fd3 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/ContinuousQueryFilter.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/ContinuousQueryFilter.cs
@@ -17,13 +17,11 @@
 
 namespace Apache.Ignite.ExamplesDll.Datagrid
 {
-    using System;
     using Apache.Ignite.Core.Cache.Event;
 
     /// <summary>
     /// Filter for continuous query example.
     /// </summary>
-    [Serializable]
     public class ContinuousQueryFilter : ICacheEntryEventFilter<int, string>
     {
         /// <summary> Threshold. </summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/EmployeeStorePredicate.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/EmployeeStorePredicate.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/EmployeeStorePredicate.cs
index 5c3bf89..1df7630 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/EmployeeStorePredicate.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Datagrid/EmployeeStorePredicate.cs
@@ -17,14 +17,12 @@
 
 namespace Apache.Ignite.ExamplesDll.Datagrid
 {
-    using System;
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.ExamplesDll.Binary;
 
     /// <summary>
     /// Example cache entry predicate.
     /// </summary>
-    [Serializable]
     public class EmployeeStorePredicate : ICacheEntryFilter<int, Employee>
     {
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteOrderedListener.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteOrderedListener.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteOrderedListener.cs
index edf38f2..fd7e6ff 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteOrderedListener.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteOrderedListener.cs
@@ -25,7 +25,6 @@ namespace Apache.Ignite.ExamplesDll.Messaging
     /// <summary>
     /// Listener for Ordered topic.
     /// </summary>
-    [Serializable]
     public class RemoteOrderedListener : IMessageListener<int>
     {
         /** Injected Ignite instance. */

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteUnorderedListener.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteUnorderedListener.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteUnorderedListener.cs
index 8054d36..1432f11 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteUnorderedListener.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Messaging/RemoteUnorderedListener.cs
@@ -25,7 +25,6 @@ namespace Apache.Ignite.ExamplesDll.Messaging
     /// <summary>
     /// Listener for Unordered topic.
     /// </summary>
-    [Serializable]
     public class RemoteUnorderedListener : IMessageListener<int>
     {
         /** Injected Ignite instance. */

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Services/MapService.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Services/MapService.cs b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Services/MapService.cs
index 7071cd4..8ca9ab0 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Services/MapService.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.ExamplesDll/Services/MapService.cs
@@ -26,7 +26,6 @@ namespace Apache.Ignite.ExamplesDll.Services
     /// <summary>
     /// Service implementation.
     /// </summary>
-    [Serializable]
     public class MapService<TK, TV> : IService
     {
         /** Injected Ignite instance. */


[4/5] ignite git commit: IGNITE-2703 .NET: Dynamic type registration

Posted by pt...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/CallbacksTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/CallbacksTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/CallbacksTest.cs
new file mode 100644
index 0000000..a014205
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/CallbacksTest.cs
@@ -0,0 +1,369 @@
+\ufeff/*
+ * 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.Binary.Serializable
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests that deserialization callbacks are invoked correctly.
+    /// </summary>
+    public class CallbacksTest
+    {
+        /** Deserialization messages. */
+        private static readonly List<string> Messages = new List<string>();
+
+        /// <summary>
+        /// Tests that callbacks are invoked in correct order on class with ISerializable interface.
+        /// </summary>
+        [Test]
+        public void TestSerializable()
+        {
+            CheckCallbacks<SerCallbacks>(true);
+        }
+
+        /// <summary>
+        /// Tests that callbacks are invoked in correct order on class without ISerializable interface.
+        /// </summary>
+        [Test]
+        public void TestNonSerializable()
+        {
+            CheckCallbacks<SerCallbacksNoInterface>(false);
+        }
+
+        /// <summary>
+        /// Tests that callbacks are invoked in correct order on class with ISerializable interface.
+        /// </summary>
+        [Test]
+        public void TestSerializableStruct()
+        {
+            var obj = new SerCallbacksStruct
+            {
+                Name = "Foo",
+                Inner = new SerCallbacksStruct
+                {
+                    Name = "Bar"
+                }
+            };
+
+            Messages.Clear();
+            var res = TestUtils.SerializeDeserialize(obj);
+
+            Assert.AreEqual("Foo", res.Name);
+            Assert.AreEqual("Bar", ((SerCallbacksStruct) res.Inner).Name);
+
+            // OnDeserialization callbacks should be called AFTER entire tree is deserialized.
+            // Other callbacks order is not strictly defined.
+            var expected = new[]
+            {
+                "Foo.OnSerializing",
+                "Bar.OnSerializing",
+                "Bar.OnSerialized",
+                "Foo.OnSerialized",
+                ".OnDeserializing",
+                ".OnDeserializing",
+                "Bar.ctor",
+                "Bar.OnDeserialized",
+                "Foo.ctor",
+                "Foo.OnDeserialized",
+                "Foo.OnDeserialization",
+                "Bar.OnDeserialization",
+            };
+
+            Assert.AreEqual(expected, Messages);
+        }
+
+        /// <summary>
+        /// Tests that callbacks are invoked in correct order on class without ISerializable interface.
+        /// </summary>
+        [Test]
+        public void TestNonSerializableStruct()
+        {
+            var obj = new SerCallbacksStructNoInterface
+            {
+                Name = "Foo",
+                Inner = new SerCallbacksStructNoInterface
+                {
+                    Name = "Bar"
+                }
+            };
+
+            Messages.Clear();
+            var res = TestUtils.SerializeDeserialize(obj);
+
+            Assert.AreEqual("Foo", res.Name);
+            Assert.AreEqual("Bar", ((SerCallbacksStructNoInterface) res.Inner).Name);
+
+            // OnDeserialization callbacks should be called AFTER entire tree is deserialized.
+            // Other callbacks order is not strictly defined.
+            var expected = new[]
+            {
+                "Foo.OnSerializing",
+                "Bar.OnSerializing",
+                "Bar.OnSerialized",
+                "Foo.OnSerialized",
+                ".OnDeserializing",
+                ".OnDeserializing",
+                "Bar.OnDeserialized",
+                "Foo.OnDeserialized",
+                "Foo.OnDeserialization",
+                "Bar.OnDeserialization",
+            };
+
+            Assert.AreEqual(expected, Messages);
+        }
+
+        /// <summary>
+        /// Checks the callbacks.
+        /// </summary>
+        private static void CheckCallbacks<T>(bool ctorCall) where T : SerCallbacksNoInterface, new()
+        {
+            var obj = new T
+            {
+                Name = "Foo",
+                Inner = new T
+                {
+                    Name = "Bar",
+                    Inner = new T
+                    {
+                        Name = "Baz"
+                    }
+                }
+            };
+
+            Messages.Clear();
+            var res = TestUtils.SerializeDeserialize(obj);
+
+            Assert.AreEqual("Foo", res.Name);
+            Assert.AreEqual("Bar", res.Inner.Name);
+            Assert.AreEqual("Baz", res.Inner.Inner.Name);
+
+            // OnDeserialization callbacks should be called AFTER entire tree is deserialized.
+            // Other callbacks order is not strictly defined.
+            var expected = new[]
+            {
+                "Foo.OnSerializing",
+                "Bar.OnSerializing",
+                "Baz.OnSerializing",
+                "Baz.OnSerialized",
+                "Bar.OnSerialized",
+                "Foo.OnSerialized",
+                ".OnDeserializing",
+                ".OnDeserializing",
+                ".OnDeserializing",
+                "Baz.ctor",
+                "Baz.OnDeserialized",
+                "Bar.ctor",
+                "Bar.OnDeserialized",
+                "Foo.ctor",
+                "Foo.OnDeserialized",
+                "Foo.OnDeserialization",
+                "Bar.OnDeserialization",
+                "Baz.OnDeserialization"
+            };
+
+            if (!ctorCall)
+                expected = expected.Where(x => !x.Contains("ctor")).ToArray();
+
+            Assert.AreEqual(expected, Messages);
+        }
+
+        /// <summary>
+        /// Tests that incorrect method signature causes a descriptive exception.
+        /// </summary>
+        [Test]
+        public void TestIncorrectMethodSignature()
+        {
+            var ex = Assert.Throws<TypeLoadException>(
+                    () => TestUtils.SerializeDeserialize(new InvalidCallbackSignature()));
+
+            var t = typeof(InvalidCallbackSignature);
+
+            Assert.AreEqual(string.Format("Type '{0}' in assembly '{1}' has method 'OnDeserializing' " +
+                                          "with an incorrect signature for the serialization attribute that it " +
+                                          "is decorated with.", t, t.Assembly), ex.Message);
+        }
+
+        /// <summary>
+        /// Class with serialization callbacks and <see cref="ISerializable" /> implemented.
+        /// This goes through <see cref="SerializableSerializer"/>.
+        /// </summary>
+        [Serializable]
+        private class SerCallbacks : SerCallbacksNoInterface, ISerializable
+        {
+            public SerCallbacks()
+            {
+            }
+
+            protected SerCallbacks(SerializationInfo info, StreamingContext context)
+            {
+                Name = info.GetString("name");
+                Inner = (SerCallbacks) info.GetValue("inner", typeof(SerCallbacks));
+
+                Messages.Add(string.Format("{0}.ctor", Name));
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.AddValue("name", Name);
+                info.AddValue("inner", Inner);
+            }
+        }
+
+        /// <summary>
+        /// Class with serialization callbacks and without <see cref="ISerializable" /> implemented.
+        /// This goes through <see cref="BinaryReflectiveSerializer"/>.
+        /// </summary>
+        [Serializable]
+        private class SerCallbacksNoInterface : IDeserializationCallback
+        {
+            public string Name { get; set; }
+
+            public SerCallbacksNoInterface Inner { get; set; }
+
+            public void OnDeserialization(object sender)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialization", Name));
+            }
+
+            [OnSerializing]
+            public void OnSerializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerializing", Name));
+            }
+
+            [OnSerialized]
+            public void OnSerialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerialized", Name));
+            }
+
+            [OnDeserializing]
+            public void OnDeserializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserializing", Name));
+            }
+
+            [OnDeserialized]
+            public void OnDeserialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialized", Name));
+            }
+        }
+
+        private class InvalidCallbackSignature
+        {
+            [OnDeserializing]
+            public void OnDeserializing()
+            {
+                // No-op.
+            }
+        }
+
+        [Serializable]
+        private struct SerCallbacksStruct : IDeserializationCallback, ISerializable
+        {
+            public string Name { get; set; }
+
+            public object Inner { get; set; }
+
+            public SerCallbacksStruct(SerializationInfo info, StreamingContext context) : this()
+            {
+                Name = info.GetString("name");
+                Inner = info.GetValue("inner", typeof(object));
+                Messages.Add(string.Format("{0}.ctor", Name));
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.AddValue("name", Name);
+                info.AddValue("inner", Inner);
+            }
+
+            public void OnDeserialization(object sender)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialization", Name));
+            }
+
+            [OnSerializing]
+            public void OnSerializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerializing", Name));
+            }
+
+            [OnSerialized]
+            public void OnSerialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerialized", Name));
+            }
+
+            [OnDeserializing]
+            public void OnDeserializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserializing", Name));
+            }
+
+            [OnDeserialized]
+            public void OnDeserialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialized", Name));
+            }
+        }
+
+        private struct SerCallbacksStructNoInterface : IDeserializationCallback
+        {
+            public string Name { get; set; }
+
+            public object Inner { get; set; }
+
+            public void OnDeserialization(object sender)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialization", Name));
+            }
+
+            [OnSerializing]
+            public void OnSerializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerializing", Name));
+            }
+
+            [OnSerialized]
+            public void OnSerialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnSerialized", Name));
+            }
+
+            [OnDeserializing]
+            public void OnDeserializing(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserializing", Name));
+            }
+
+            [OnDeserialized]
+            public void OnDeserialized(StreamingContext context)
+            {
+                Messages.Add(string.Format("{0}.OnDeserialized", Name));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/DelegatesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/DelegatesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/DelegatesTest.cs
new file mode 100644
index 0000000..90720d4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/DelegatesTest.cs
@@ -0,0 +1,161 @@
+\ufeff/*
+ * 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.Binary.Serializable
+{
+    using System;
+    using System.Reflection;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests delegate serialization.
+    /// </summary>
+    public class DelegatesTest
+    {
+        /** Test int value. */
+        private static int _int;
+
+        /** Test delegate. */
+        private delegate string LowerSubStringDelegate(string s, int startIndex);
+
+        /// <summary>
+        /// Tests that delegates can be serialized.
+        /// </summary>
+        [Test]
+        public void TestAction()
+        {
+            // Action with captured variable.
+            var val = new PrimitivesTest.Primitives {Int = 135};
+
+            Action act = () => {
+                val.Int++;
+                _int = val.Int;
+            };
+
+            var res = TestUtils.SerializeDeserialize(act);
+            Assert.AreEqual(act.Method, res.Method);
+            Assert.AreNotEqual(act.Target, res.Target);
+
+            res();
+            Assert.AreEqual(135, val.Int);   // Captured variable is deserialized to a new instance.
+            Assert.AreEqual(136, _int);
+
+            // Action with arguments.
+            Action<PrimitivesTest.Primitives, int> act1 = (p, i) => { p.Int = i; };
+
+            var res1 = TestUtils.SerializeDeserialize(act1);
+            Assert.AreEqual(act1.Method, res1.Method);
+
+            res1(val, 33);
+            Assert.AreEqual(33, val.Int);
+        }
+
+        /// <summary>
+        /// Tests that anonymous function can be serialized.
+        /// </summary>
+        [Test]
+        public void TestFunc()
+        {
+            int ms = DateTime.Now.Millisecond;
+
+            Func<int, int> func = x => x + ms;
+
+            var resFunc = TestUtils.SerializeDeserialize(func);
+            Assert.AreEqual(func.Method, resFunc.Method);
+            Assert.AreNotEqual(func.Target, resFunc.Target);
+
+            Assert.AreEqual(ms + 20, resFunc(20));
+        }
+
+        /// <summary>
+        /// Tests that old-fashioned delegate can be serialized.
+        /// </summary>
+        [Test]
+        public void TestDelegate()
+        {
+            // Delegate to a static method.
+            LowerSubStringDelegate del1 = LowerSubString;
+
+            var del1Res = TestUtils.SerializeDeserialize(del1);
+
+            Assert.AreEqual(del1.Method, del1Res.Method);
+            Assert.IsNull(del1Res.Target);
+
+            Assert.AreEqual("ooz", del1Res("FOOZ", 1));
+
+            // Delegate to an anonymous method.
+            LowerSubStringDelegate del2 = (s, i) => s.Substring(i).ToLower();
+
+            var del2Res = TestUtils.SerializeDeserialize(del2);
+
+            Assert.AreEqual(del2.Method, del2Res.Method, "Delegate methods are same");
+
+            Assert.AreEqual("ooz", del2Res("FOOZ", 1), "Delegate works as expected");
+        }
+
+        /// <summary>
+        /// Tests that MethodInfo can be serialized.
+        /// </summary>
+        [Test]
+        public void TestMethodInfo()
+        {
+            var methods = typeof(string).GetMethods(BindingFlags.Public | BindingFlags.NonPublic
+                                                    | BindingFlags.Instance | BindingFlags.Static);
+
+            Assert.IsNotEmpty(methods);
+
+            foreach (var methodInfo in methods)
+            {
+                var res = TestUtils.SerializeDeserialize(methodInfo);
+
+                Assert.AreEqual(methodInfo.Name, res.Name);
+                Assert.AreEqual(methodInfo.DeclaringType, res.DeclaringType);
+                Assert.AreEqual(methodInfo.ReturnType, res.ReturnType);
+                Assert.AreEqual(methodInfo.GetParameters(), res.GetParameters());
+            }
+        }
+
+        /// <summary>
+        /// Tests that recursive anonymous function can be serialized.
+        /// </summary>
+        [Test]
+        public void TestRecursiveFunc()
+        {
+            Func<int, int> fib = null;
+            fib = x => x == 0
+                ? 0
+                : x == 1
+                    ? 1
+                    : fib(x - 2) + fib(x - 1);
+
+            Assert.AreEqual(89, fib(11));
+            Assert.AreEqual(144, fib(12));
+
+            var resFib = TestUtils.SerializeDeserialize(fib);
+
+            Assert.AreEqual(fib.Method, resFib.Method);
+
+            Assert.AreEqual(89, resFib(11));
+            Assert.AreEqual(144, resFib(12));
+        }
+
+        private static string LowerSubString(string s, int startIndex)
+        {
+            return s.Substring(startIndex).ToLower();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/ObjectReferenceTests.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/ObjectReferenceTests.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/ObjectReferenceTests.cs
new file mode 100644
index 0000000..71d2f9a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/ObjectReferenceTests.cs
@@ -0,0 +1,131 @@
+\ufeff/*
+ * 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.Binary.Serializable
+{
+    using System;
+    using System.Runtime.Serialization;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests that <see cref="IObjectReference"/> objects are deserialized properly.
+    /// This only applies to <see cref="ISerializable"/> implementers, which can replace underlying object
+    /// with <see cref="SerializationInfo.SetType"/>, <see cref="SerializationInfo.AssemblyName"/>, and
+    /// <see cref="SerializationInfo.FullTypeName"/>.
+    /// </summary>
+    public class ObjectReferenceTests
+    {
+        /// <summary>
+        /// Tests serialization object replacement with <see cref="SerializationInfo.SetType"/> method.
+        /// </summary>
+        [Test]
+        public void TestSetType()
+        {
+            var obj = new SetTypeReplacer(25);
+
+            var res = TestUtils.SerializeDeserialize(obj);
+
+            Assert.AreEqual(obj.Value, res.Value);
+        }
+
+        /// <summary>
+        /// Tests serialization object replacement with <see cref="SerializationInfo.FullTypeName"/> property.
+        /// </summary>
+        [Test]
+        public void TestTypeName()
+        {
+            var obj = new TypeNameReplacer(36);
+
+            var res = TestUtils.SerializeDeserialize(obj);
+
+            Assert.AreEqual(obj.Value, res.Value);
+        }
+
+        [Serializable]
+        private class SetTypeReplacer : ISerializable
+        {
+            private readonly int _value;
+
+            public SetTypeReplacer(int value)
+            {
+                _value = value;
+            }
+
+            public int Value
+            {
+                get { return _value; }
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.SetType(typeof(ObjectInfoHolder));
+
+                info.AddValue("type", GetType());
+                info.AddValue("val", Value);
+            }
+        }
+
+        [Serializable]
+        private class TypeNameReplacer : ISerializable
+        {
+            private readonly int _value;
+
+            public TypeNameReplacer(int value)
+            {
+                _value = value;
+            }
+
+            public int Value
+            {
+                get { return _value; }
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.FullTypeName = typeof(ObjectInfoHolder).FullName;
+                info.AssemblyName = typeof(ObjectInfoHolder).Assembly.FullName;
+
+                info.AddValue("type", GetType());
+                info.AddValue("val", Value);
+            }
+        }
+
+        [Serializable]
+        private class ObjectInfoHolder : IObjectReference, ISerializable
+        {
+            public Type ObjectType { get; set; }
+
+            public int Value { get; set; }
+
+            public object GetRealObject(StreamingContext context)
+            {
+                return Activator.CreateInstance(ObjectType, Value);
+            }
+
+            public ObjectInfoHolder(SerializationInfo info, StreamingContext context)
+            {
+                ObjectType = (Type) info.GetValue("type", typeof(Type));
+                Value = info.GetInt32("val");
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                // No-op.
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/PrimitivesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/PrimitivesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/PrimitivesTest.cs
new file mode 100644
index 0000000..bbbee60
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/PrimitivesTest.cs
@@ -0,0 +1,754 @@
+\ufeff/*
+ * 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.
+ */
+
+// ReSharper disable StringLiteralTypo
+// ReSharper disable IdentifierTypo
+namespace Apache.Ignite.Core.Tests.Binary.Serializable
+{
+    using System;
+    using System.Linq;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Binary;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests [Serializable] mechanism handling primitive types.
+    /// </summary>
+    public class PrimitivesTest
+    {
+        /** */
+        private IIgnite _ignite;
+        
+        /// <summary>
+        /// Sets up the test fixture.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            _ignite = Ignition.Start(TestUtils.GetTestConfiguration());
+        }
+
+        /// <summary>
+        /// Tears down the test fixture.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests the DateTime which is ISerializable struct.
+        /// </summary>
+        [Test]
+        public void TestDateTime()
+        {
+            var marsh = GetMarshaller();
+
+            var val = DateTime.Now;
+
+            Assert.AreEqual(val, marsh.Unmarshal<DateTime>(marsh.Marshal(val)));
+
+            Assert.AreEqual(new[] {val}, marsh.Unmarshal<DateTime[]>(marsh.Marshal(new[] {val})));
+
+            Assert.AreEqual(new DateTime?[] {val, null},
+                marsh.Unmarshal<DateTime?[]>(marsh.Marshal(new DateTime?[] {val, null})));
+        }
+
+        /// <summary>
+        /// Tests that primitive types can be serialized with ISerializable mechanism.
+        /// </summary>
+        [Test]
+        public void TestPrimitives()
+        {
+            var marsh = GetMarshaller();
+
+            var val1 = new Primitives
+            {
+                Byte = 1,
+                Bytes = new byte[] {2, 3, byte.MinValue, byte.MaxValue},
+                Sbyte = -64,
+                Sbytes = new sbyte[] {sbyte.MinValue, sbyte.MaxValue, 1, 2, -4, -5},
+                Bool = true,
+                Bools = new[] {true, true, false},
+                Char = 'x',
+                Chars = new[] {'a', 'z', char.MinValue, char.MaxValue},
+                Short = -25,
+                Shorts = new short[] {5, -7, 9, short.MinValue, short.MaxValue},
+                Ushort = 99,
+                Ushorts = new ushort[] {10, 20, 12, ushort.MinValue, ushort.MaxValue},
+                Int = -456,
+                Ints = new[] {-100, 200, -300, int.MinValue, int.MaxValue},
+                Uint = 456,
+                Uints = new uint[] {100, 200, 300, uint.MinValue, uint.MaxValue},
+                Long = long.MaxValue,
+                Longs = new[] {long.MinValue, long.MaxValue, 33, -44},
+                Ulong = ulong.MaxValue,
+                Ulongs = new ulong[] {ulong.MinValue, ulong.MaxValue, 33},
+                Float = 1.33f,
+                Floats = new[]
+                {
+                    float.MinValue, float.MaxValue,
+                    float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN,
+                    1.23f, -2.5f
+                },
+                Double = -6.78,
+                Doubles = new[]
+                {
+                    double.MinValue, double.MaxValue, double.Epsilon,
+                    double.NegativeInfinity, double.PositiveInfinity,
+                    3.76, -9.89
+                },
+                Decimal = 1.23456789m,
+                Decimals = new[]
+                {
+                    decimal.MinValue, decimal.MaxValue, decimal.One, decimal.MinusOne, decimal.Zero,
+                    1.35m, -2.46m
+                },
+                DateTime = DateTime.UtcNow,
+                DateTimes = new[] {DateTime.Now, DateTime.MinValue, DateTime.MaxValue, DateTime.UtcNow},
+                Guid = Guid.NewGuid(),
+                Guids = new[] {Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()},
+                String = "hello world",
+                Strings = new[] {"hello", "world"}
+            };
+
+            var vals = new[] {new Primitives(), val1};
+
+            foreach (var val in vals)
+            {
+                Assert.IsFalse(val.GetObjectDataCalled);
+                Assert.IsFalse(val.SerializationCtorCalled);
+
+                // Unmarshal in full and binary form.
+                var bytes = marsh.Marshal(val);
+                var res = marsh.Unmarshal<Primitives>(bytes);
+                var bin = marsh.Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
+
+                // Verify flags.
+                Assert.IsTrue(val.GetObjectDataCalled);
+                Assert.IsFalse(val.SerializationCtorCalled);
+
+                Assert.IsFalse(res.GetObjectDataCalled);
+                Assert.IsTrue(res.SerializationCtorCalled);
+
+                // Verify values.
+                Assert.AreEqual(val.Byte, res.Byte);
+                Assert.AreEqual(val.Byte, bin.GetField<byte>("byte"));
+
+                Assert.AreEqual(val.Bytes, res.Bytes);
+                Assert.AreEqual(val.Bytes, bin.GetField<byte[]>("bytes"));
+
+                Assert.AreEqual(val.Sbyte, res.Sbyte);
+                Assert.AreEqual(val.Sbyte, bin.GetField<sbyte>("sbyte"));
+
+                Assert.AreEqual(val.Sbytes, res.Sbytes);
+                Assert.AreEqual(val.Sbytes, bin.GetField<sbyte[]>("sbytes"));
+
+                Assert.AreEqual(val.Bool, res.Bool);
+                Assert.AreEqual(val.Bool, bin.GetField<bool>("bool"));
+
+                Assert.AreEqual(val.Bools, res.Bools);
+                Assert.AreEqual(val.Bools, bin.GetField<bool[]>("bools"));
+
+                Assert.AreEqual(val.Char, res.Char);
+                Assert.AreEqual(val.Char, bin.GetField<char>("char"));
+
+                Assert.AreEqual(val.Chars, res.Chars);
+                Assert.AreEqual(val.Chars, bin.GetField<char[]>("chars"));
+
+                Assert.AreEqual(val.Short, res.Short);
+                Assert.AreEqual(val.Short, bin.GetField<short>("short"));
+
+                Assert.AreEqual(val.Shorts, res.Shorts);
+                Assert.AreEqual(val.Shorts, bin.GetField<short[]>("shorts"));
+
+                Assert.AreEqual(val.Ushort, res.Ushort);
+                Assert.AreEqual(val.Ushort, bin.GetField<ushort>("ushort"));
+
+                Assert.AreEqual(val.Ushorts, res.Ushorts);
+                Assert.AreEqual(val.Ushorts, bin.GetField<ushort[]>("ushorts"));
+
+                Assert.AreEqual(val.Int, res.Int);
+                Assert.AreEqual(val.Int, bin.GetField<int>("int"));
+
+                Assert.AreEqual(val.Ints, res.Ints);
+                Assert.AreEqual(val.Ints, bin.GetField<int[]>("ints"));
+
+                Assert.AreEqual(val.Uint, res.Uint);
+                Assert.AreEqual(val.Uint, bin.GetField<uint>("uint"));
+
+                Assert.AreEqual(val.Uints, res.Uints);
+                Assert.AreEqual(val.Uints, bin.GetField<uint[]>("uints"));
+
+                Assert.AreEqual(val.Long, res.Long);
+                Assert.AreEqual(val.Long, bin.GetField<long>("long"));
+
+                Assert.AreEqual(val.Longs, res.Longs);
+                Assert.AreEqual(val.Longs, bin.GetField<long[]>("longs"));
+
+                Assert.AreEqual(val.Ulong, res.Ulong);
+                Assert.AreEqual(val.Ulong, bin.GetField<ulong>("ulong"));
+
+                Assert.AreEqual(val.Ulongs, res.Ulongs);
+                Assert.AreEqual(val.Ulongs, bin.GetField<ulong[]>("ulongs"));
+
+                Assert.AreEqual(val.Float, res.Float);
+                Assert.AreEqual(val.Float, bin.GetField<float>("float"));
+
+                Assert.AreEqual(val.Floats, res.Floats);
+                Assert.AreEqual(val.Floats, bin.GetField<float[]>("floats"));
+
+                Assert.AreEqual(val.Double, res.Double);
+                Assert.AreEqual(val.Double, bin.GetField<double>("double"));
+
+                Assert.AreEqual(val.Doubles, res.Doubles);
+                Assert.AreEqual(val.Doubles, bin.GetField<double[]>("doubles"));
+
+                Assert.AreEqual(val.Decimal, res.Decimal);
+                Assert.AreEqual(val.Decimal, bin.GetField<decimal>("decimal"));
+
+                Assert.AreEqual(val.Decimals, res.Decimals);
+                Assert.AreEqual(val.Decimals, bin.GetField<decimal[]>("decimals"));
+
+                Assert.AreEqual(val.Guid, res.Guid);
+                Assert.AreEqual(val.Guid, bin.GetField<Guid>("guid"));
+
+                Assert.AreEqual(val.Guids, res.Guids);
+                Assert.AreEqual(val.Guids, bin.GetField<Guid[]>("guids"));
+
+                Assert.AreEqual(val.DateTime, res.DateTime);
+                Assert.AreEqual(val.DateTime, bin.GetField<IBinaryObject>("datetime").Deserialize<DateTime>());
+
+                Assert.AreEqual(val.DateTimes, res.DateTimes);
+                var dts = bin.GetField<IBinaryObject[]>("datetimes");
+                Assert.AreEqual(val.DateTimes, dts == null ? null : dts.Select(x => x.Deserialize<DateTime>()));
+
+                Assert.AreEqual(val.String, res.String);
+                Assert.AreEqual(val.String, bin.GetField<string>("string"));
+
+                Assert.AreEqual(val.Strings, res.Strings);
+                Assert.AreEqual(val.Strings, bin.GetField<string[]>("strings"));
+
+                VerifyFieldTypes(bin);
+            }
+        }
+
+        /// <summary>
+        /// Tests that primitive types in nullable form can be serialized with ISerializable mechanism.
+        /// </summary>
+        [Test]
+        public void TestPrimitivesNullable()
+        {
+            var marsh = GetMarshaller();
+
+            var val1 = new PrimitivesNullable
+            {
+                Byte = 1,
+                Bytes = new byte?[] {2, 3, byte.MinValue, byte.MaxValue, null},
+                Sbyte = -64,
+                Sbytes = new sbyte?[] {sbyte.MinValue, sbyte.MaxValue, 1, 2, -4, -5, null},
+                Bool = true,
+                Bools = new bool?[] {true, true, false, null},
+                Char = 'x',
+                Chars = new char?[] {'a', 'z', char.MinValue, char.MaxValue, null},
+                Short = -25,
+                Shorts = new short?[] {5, -7, 9, short.MinValue, short.MaxValue, null},
+                Ushort = 99,
+                Ushorts = new ushort?[] {10, 20, 12, ushort.MinValue, ushort.MaxValue, null},
+                Int = -456,
+                Ints = new int?[] {-100, 200, -300, int.MinValue, int.MaxValue, null},
+                Uint = 456,
+                Uints = new uint?[] {100, 200, 300, uint.MinValue, uint.MaxValue, null},
+                Long = long.MaxValue,
+                Longs = new long?[] {long.MinValue, long.MaxValue, 33, -44, null},
+                Ulong = ulong.MaxValue,
+                Ulongs = new ulong?[] {ulong.MinValue, ulong.MaxValue, 33, null},
+                Float = 1.33f,
+                Floats = new float?[]
+                {
+                    float.MinValue, float.MaxValue,
+                    float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN,
+                    1.23f, -2.5f, null
+                },
+                Double = -6.78,
+                Doubles = new double?[]
+                {
+                    double.MinValue, double.MaxValue, double.Epsilon,
+                    double.NegativeInfinity, double.PositiveInfinity,
+                    3.76, -9.89, null
+                },
+                Decimal = 1.23456789m,
+                Decimals = new decimal?[]
+                {
+                    decimal.MinValue, decimal.MaxValue, decimal.One, decimal.MinusOne, decimal.Zero,
+                    1.35m, -2.46m, null
+                },
+                DateTime = DateTime.UtcNow,
+                DateTimes = new DateTime?[]
+                {
+                    DateTime.Now, DateTime.MinValue, DateTime.MaxValue, DateTime.UtcNow, null
+                },
+                Guid = Guid.NewGuid(),
+                Guids = new Guid?[] {Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), null},
+            };
+
+            var vals = new[] {new PrimitivesNullable(), val1};
+
+            foreach (var val in vals)
+            {
+                Assert.IsFalse(val.GetObjectDataCalled);
+                Assert.IsFalse(val.SerializationCtorCalled);
+
+                // Unmarshal in full and binary form.
+                var bytes = marsh.Marshal(val);
+                var res = marsh.Unmarshal<PrimitivesNullable>(bytes);
+                var bin = marsh.Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
+
+                // Verify flags.
+                Assert.IsTrue(val.GetObjectDataCalled);
+                Assert.IsFalse(val.SerializationCtorCalled);
+
+                Assert.IsFalse(res.GetObjectDataCalled);
+                Assert.IsTrue(res.SerializationCtorCalled);
+
+                // Verify values.
+                Assert.AreEqual(val.Byte, res.Byte);
+                Assert.AreEqual(val.Byte, bin.GetField<byte?>("byte"));
+
+                Assert.AreEqual(val.Bytes, res.Bytes);
+                Assert.AreEqual(val.Bytes, bin.GetField<byte?[]>("bytes"));
+
+                Assert.AreEqual(val.Sbyte, res.Sbyte);
+                Assert.AreEqual(val.Sbyte, bin.GetField<sbyte?>("sbyte"));
+
+                Assert.AreEqual(val.Sbytes, res.Sbytes);
+                Assert.AreEqual(val.Sbytes, bin.GetField<sbyte?[]>("sbytes"));
+
+                Assert.AreEqual(val.Bool, res.Bool);
+                Assert.AreEqual(val.Bool, bin.GetField<bool?>("bool"));
+
+                Assert.AreEqual(val.Bools, res.Bools);
+                Assert.AreEqual(val.Bools, bin.GetField<bool?[]>("bools"));
+
+                Assert.AreEqual(val.Char, res.Char);
+                Assert.AreEqual(val.Char, bin.GetField<char?>("char"));
+
+                Assert.AreEqual(val.Chars, res.Chars);
+                Assert.AreEqual(val.Chars, bin.GetField<char?[]>("chars"));
+
+                Assert.AreEqual(val.Short, res.Short);
+                Assert.AreEqual(val.Short, bin.GetField<short?>("short"));
+
+                Assert.AreEqual(val.Shorts, res.Shorts);
+                Assert.AreEqual(val.Shorts, bin.GetField<short?[]>("shorts"));
+
+                Assert.AreEqual(val.Ushort, res.Ushort);
+                Assert.AreEqual(val.Ushort, bin.GetField<ushort?>("ushort"));
+
+                Assert.AreEqual(val.Ushorts, res.Ushorts);
+                Assert.AreEqual(val.Ushorts, bin.GetField<ushort?[]>("ushorts"));
+
+                Assert.AreEqual(val.Int, res.Int);
+                Assert.AreEqual(val.Int, bin.GetField<int?>("int"));
+
+                Assert.AreEqual(val.Ints, res.Ints);
+                Assert.AreEqual(val.Ints, bin.GetField<int?[]>("ints"));
+
+                Assert.AreEqual(val.Uint, res.Uint);
+                Assert.AreEqual(val.Uint, bin.GetField<uint?>("uint"));
+
+                Assert.AreEqual(val.Uints, res.Uints);
+                Assert.AreEqual(val.Uints, bin.GetField<uint?[]>("uints"));
+
+                Assert.AreEqual(val.Long, res.Long);
+                Assert.AreEqual(val.Long, bin.GetField<long?>("long"));
+
+                Assert.AreEqual(val.Longs, res.Longs);
+                Assert.AreEqual(val.Longs, bin.GetField<long?[]>("longs"));
+
+                Assert.AreEqual(val.Ulong, res.Ulong);
+                Assert.AreEqual(val.Ulong, bin.GetField<ulong?>("ulong"));
+
+                Assert.AreEqual(val.Ulongs, res.Ulongs);
+                Assert.AreEqual(val.Ulongs, bin.GetField<ulong?[]>("ulongs"));
+
+                Assert.AreEqual(val.Float, res.Float);
+                Assert.AreEqual(val.Float, bin.GetField<float?>("float"));
+
+                Assert.AreEqual(val.Floats, res.Floats);
+                Assert.AreEqual(val.Floats, bin.GetField<float?[]>("floats"));
+
+                Assert.AreEqual(val.Double, res.Double);
+                Assert.AreEqual(val.Double, bin.GetField<double?>("double"));
+
+                Assert.AreEqual(val.Doubles, res.Doubles);
+                Assert.AreEqual(val.Doubles, bin.GetField<double?[]>("doubles"));
+
+                Assert.AreEqual(val.Decimal, res.Decimal);
+                Assert.AreEqual(val.Decimal, bin.GetField<decimal?>("decimal"));
+
+                Assert.AreEqual(val.Decimals, res.Decimals);
+                Assert.AreEqual(val.Decimals, bin.GetField<decimal?[]>("decimals"));
+
+                Assert.AreEqual(val.Guid, res.Guid);
+                Assert.AreEqual(val.Guid, bin.GetField<Guid?>("guid"));
+
+                Assert.AreEqual(val.Guids, res.Guids);
+                Assert.AreEqual(val.Guids, bin.GetField<Guid?[]>("guids"));
+
+                Assert.AreEqual(val.DateTime, res.DateTime);
+                var dt = bin.GetField<IBinaryObject>("datetime");
+                Assert.AreEqual(val.DateTime, dt == null ? null : dt.Deserialize<DateTime?>());
+
+                Assert.AreEqual(val.DateTimes, res.DateTimes);
+                var dts = bin.GetField<IBinaryObject[]>("datetimes");
+                Assert.AreEqual(val.DateTimes, dts == null
+                    ? null
+                    : dts.Select(x => x == null ? null : x.Deserialize<DateTime?>()));
+            }
+        }
+
+        /// <summary>
+        /// Verifies the field types.
+        /// </summary>
+        private static void VerifyFieldTypes(IBinaryObject bin)
+        {
+            var binType = bin.GetBinaryType();
+            
+            Assert.AreEqual("byte", binType.GetFieldTypeName("byte"));
+            Assert.AreEqual("byte", binType.GetFieldTypeName("sbyte"));
+            
+            Assert.AreEqual("byte[]", binType.GetFieldTypeName("bytes"));
+            Assert.AreEqual("byte[]", binType.GetFieldTypeName("sbytes"));
+            
+            Assert.AreEqual("boolean", binType.GetFieldTypeName("bool"));
+            Assert.AreEqual("boolean[]", binType.GetFieldTypeName("bools"));
+            
+            Assert.AreEqual("char", binType.GetFieldTypeName("char"));
+            Assert.AreEqual("char[]", binType.GetFieldTypeName("chars"));
+
+            Assert.AreEqual("short", binType.GetFieldTypeName("short"));
+            Assert.AreEqual("short[]", binType.GetFieldTypeName("shorts"));
+
+            Assert.AreEqual("short", binType.GetFieldTypeName("ushort"));
+            Assert.AreEqual("short[]", binType.GetFieldTypeName("ushorts"));
+
+            Assert.AreEqual("int", binType.GetFieldTypeName("int"));
+            Assert.AreEqual("int[]", binType.GetFieldTypeName("ints"));
+
+            Assert.AreEqual("int", binType.GetFieldTypeName("uint"));
+            Assert.AreEqual("int[]", binType.GetFieldTypeName("uints"));
+
+            Assert.AreEqual("long", binType.GetFieldTypeName("long"));
+            Assert.AreEqual("long[]", binType.GetFieldTypeName("longs"));
+
+            Assert.AreEqual("long", binType.GetFieldTypeName("ulong"));
+            Assert.AreEqual("long[]", binType.GetFieldTypeName("ulongs"));
+
+            Assert.AreEqual("float", binType.GetFieldTypeName("float"));
+            Assert.AreEqual("float[]", binType.GetFieldTypeName("floats"));
+
+            Assert.AreEqual("double", binType.GetFieldTypeName("double"));
+            Assert.AreEqual("double[]", binType.GetFieldTypeName("doubles"));
+
+            Assert.AreEqual("decimal", binType.GetFieldTypeName("decimal"));
+            Assert.AreEqual("Object", binType.GetFieldTypeName("decimals"));
+
+            Assert.AreEqual("UUID", binType.GetFieldTypeName("guid"));
+            Assert.AreEqual("Object", binType.GetFieldTypeName("guids"));
+
+            Assert.AreEqual("Object", binType.GetFieldTypeName("datetime"));
+            Assert.AreEqual("Object", binType.GetFieldTypeName("datetimes"));
+        }
+
+        /// <summary>
+        /// Gets the marshaller.
+        /// </summary>
+        private Marshaller GetMarshaller()
+        {
+            return ((Ignite) _ignite).Marshaller;
+        }
+
+        [Serializable]
+        public class Primitives : ISerializable
+        {
+            public bool GetObjectDataCalled { get; private set; }
+            public bool SerializationCtorCalled { get; private set; }
+
+            public byte Byte { get; set; }
+            public byte[] Bytes { get; set; }
+            public sbyte Sbyte { get; set; }
+            public sbyte[] Sbytes { get; set; }
+            public bool Bool { get; set; }
+            public bool[] Bools { get; set; }
+            public char Char { get; set; }
+            public char[] Chars { get; set; }
+            public short Short { get; set; }
+            public short[] Shorts { get; set; }
+            public ushort Ushort { get; set; }
+            public ushort[] Ushorts { get; set; }
+            public int Int { get; set; }
+            public int[] Ints { get; set; }
+            public uint Uint { get; set; }
+            public uint[] Uints { get; set; }
+            public long Long { get; set; }
+            public long[] Longs { get; set; }
+            public ulong Ulong { get; set; }
+            public ulong[] Ulongs { get; set; }
+            public float Float { get; set; }
+            public float[] Floats { get; set; }
+            public double Double { get; set; }
+            public double[] Doubles { get; set; }
+            public decimal Decimal { get; set; }
+            public decimal[] Decimals { get; set; }
+            public Guid Guid { get; set; }
+            public Guid[] Guids { get; set; }
+            public DateTime DateTime { get; set; }
+            public DateTime[] DateTimes { get; set; }
+            public string String { get; set; }
+            public string[] Strings { get; set; }
+
+            public Primitives()
+            {
+                // No-op.
+            }
+
+            protected Primitives(SerializationInfo info, StreamingContext context)
+            {
+                SerializationCtorCalled = true;
+
+                Byte = info.GetByte("byte");
+                Bytes = (byte[]) info.GetValue("bytes", typeof(byte[]));
+
+                Sbyte = info.GetSByte("sbyte");
+                Sbytes = (sbyte[]) info.GetValue("sbytes", typeof(sbyte[]));
+
+                Bool = info.GetBoolean("bool");
+                Bools = (bool[]) info.GetValue("bools", typeof(bool[]));
+
+                Char = info.GetChar("char");
+                Chars = (char[]) info.GetValue("chars", typeof(char[]));
+
+                Short = info.GetInt16("short");
+                Shorts = (short[]) info.GetValue("shorts", typeof(short[]));
+
+                Ushort = info.GetUInt16("ushort");
+                Ushorts = (ushort[]) info.GetValue("ushorts", typeof(ushort[]));
+
+                Int = info.GetInt32("int");
+                Ints = (int[]) info.GetValue("ints", typeof(int[]));
+
+                Uint = info.GetUInt32("uint");
+                Uints = (uint[]) info.GetValue("uints", typeof(uint[]));
+
+                Long = info.GetInt64("long");
+                Longs = (long[]) info.GetValue("longs", typeof(long[]));
+
+                Ulong = info.GetUInt64("ulong");
+                Ulongs = (ulong[]) info.GetValue("ulongs", typeof(ulong[]));
+
+                Float = info.GetSingle("float");
+                Floats = (float[]) info.GetValue("floats", typeof(float[]));
+
+                Double = info.GetDouble("double");
+                Doubles = (double[]) info.GetValue("doubles", typeof(double[]));
+
+                Decimal = info.GetDecimal("decimal");
+                Decimals = (decimal[]) info.GetValue("decimals", typeof(decimal[]));
+
+                Guid = (Guid) info.GetValue("guid", typeof(Guid));
+                Guids = (Guid[]) info.GetValue("guids", typeof(Guid[]));
+
+                DateTime = info.GetDateTime("datetime");
+                DateTimes = (DateTime[]) info.GetValue("datetimes", typeof(DateTime[]));
+
+                String = info.GetString("string");
+                Strings = (string[]) info.GetValue("strings", typeof(string[]));
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                GetObjectDataCalled = true;
+
+                info.AddValue("byte", Byte);
+                info.AddValue("bytes", Bytes, typeof(byte[]));
+                info.AddValue("sbyte", Sbyte);
+                info.AddValue("sbytes", Sbytes, typeof(sbyte[]));
+                info.AddValue("bool", Bool);
+                info.AddValue("bools", Bools, typeof(bool[]));
+                info.AddValue("char", Char);
+                info.AddValue("chars", Chars, typeof(char[]));
+                info.AddValue("short", Short);
+                info.AddValue("shorts", Shorts, typeof(short[]));
+                info.AddValue("ushort", Ushort);
+                info.AddValue("ushorts", Ushorts, typeof(ushort[]));
+                info.AddValue("int", Int);
+                info.AddValue("ints", Ints, typeof(int[]));
+                info.AddValue("uint", Uint);
+                info.AddValue("uints", Uints, typeof(uint[]));
+                info.AddValue("long", Long);
+                info.AddValue("longs", Longs, typeof(long[]));
+                info.AddValue("ulong", Ulong);
+                info.AddValue("ulongs", Ulongs, typeof(ulong[]));
+                info.AddValue("float", Float);
+                info.AddValue("floats", Floats, typeof(float[]));
+                info.AddValue("double", Double);
+                info.AddValue("doubles", Doubles, typeof(double[]));
+                info.AddValue("decimal", Decimal);
+                info.AddValue("decimals", Decimals, typeof(decimal[]));
+                info.AddValue("guid", Guid);
+                info.AddValue("guids", Guids, typeof(Guid[]));
+                info.AddValue("datetime", DateTime);
+                info.AddValue("datetimes", DateTimes, typeof(DateTime[]));
+                info.AddValue("string", String, typeof(string));
+                info.AddValue("strings", Strings, typeof(string[]));
+            }
+        }
+
+        [Serializable]
+        private class PrimitivesNullable : ISerializable
+        {
+            public bool GetObjectDataCalled { get; private set; }
+            public bool SerializationCtorCalled { get; private set; }
+
+            public byte? Byte { get; set; }
+            public byte?[] Bytes { get; set; }
+            public sbyte? Sbyte { get; set; }
+            public sbyte?[] Sbytes { get; set; }
+            public bool? Bool { get; set; }
+            public bool?[] Bools { get; set; }
+            public char? Char { get; set; }
+            public char?[] Chars { get; set; }
+            public short? Short { get; set; }
+            public short?[] Shorts { get; set; }
+            public ushort? Ushort { get; set; }
+            public ushort?[] Ushorts { get; set; }
+            public int? Int { get; set; }
+            public int?[] Ints { get; set; }
+            public uint? Uint { get; set; }
+            public uint?[] Uints { get; set; }
+            public long? Long { get; set; }
+            public long?[] Longs { get; set; }
+            public ulong? Ulong { get; set; }
+            public ulong?[] Ulongs { get; set; }
+            public float? Float { get; set; }
+            public float?[] Floats { get; set; }
+            public double? Double { get; set; }
+            public double?[] Doubles { get; set; }
+            public decimal? Decimal { get; set; }
+            public decimal?[] Decimals { get; set; }
+            public Guid? Guid { get; set; }
+            public Guid?[] Guids { get; set; }
+            public DateTime? DateTime { get; set; }
+            public DateTime?[] DateTimes { get; set; }
+
+            public PrimitivesNullable()
+            {
+                // No-op.
+            }
+
+            protected PrimitivesNullable(SerializationInfo info, StreamingContext context)
+            {
+                SerializationCtorCalled = true;
+
+                Byte = (byte?) info.GetValue("byte", typeof(byte?));
+                Bytes = (byte?[]) info.GetValue("bytes", typeof(byte?[]));
+
+                Sbyte = (sbyte?) info.GetValue("sbyte", typeof(sbyte?));
+                Sbytes = (sbyte?[]) info.GetValue("sbytes", typeof(sbyte?[]));
+
+                Bool = (bool?) info.GetValue("bool", typeof(bool?));
+                Bools = (bool?[]) info.GetValue("bools", typeof(bool?[]));
+
+                Char = (char?) info.GetValue("char", typeof(char?));
+                Chars = (char?[]) info.GetValue("chars", typeof(char?[]));
+
+                Short = (short?) info.GetValue("short", typeof(short?));
+                Shorts = (short?[]) info.GetValue("shorts", typeof(short?[]));
+
+                Ushort = (ushort?) info.GetValue("ushort", typeof(ushort?));
+                Ushorts = (ushort?[]) info.GetValue("ushorts", typeof(ushort?[]));
+
+                Int = (int?) info.GetValue("int", typeof(int?));
+                Ints = (int?[]) info.GetValue("ints", typeof(int?[]));
+
+                Uint = (uint?) info.GetValue("uint", typeof(uint?));
+                Uints = (uint?[]) info.GetValue("uints", typeof(uint?[]));
+
+                Long = (long?) info.GetValue("long", typeof(long?));
+                Longs = (long?[]) info.GetValue("longs", typeof(long?[]));
+
+                Ulong = (ulong?) info.GetValue("ulong", typeof(ulong?));
+                Ulongs = (ulong?[]) info.GetValue("ulongs", typeof(ulong?[]));
+
+                Float = (float?) info.GetValue("float", typeof(float?));
+                Floats = (float?[]) info.GetValue("floats", typeof(float?[]));
+
+                Double = (double?) info.GetValue("double", typeof(double?));
+                Doubles = (double?[]) info.GetValue("doubles", typeof(double?[]));
+
+                Decimal = (decimal?) info.GetValue("decimal", typeof(decimal?));
+                Decimals = (decimal?[]) info.GetValue("decimals", typeof(decimal?[]));
+
+                Guid = (Guid?) info.GetValue("guid", typeof(Guid?));
+                Guids = (Guid?[]) info.GetValue("guids", typeof(Guid?[]));
+
+                DateTime = (DateTime?) info.GetValue("datetime", typeof(DateTime?));
+                DateTimes = (DateTime?[]) info.GetValue("datetimes", typeof(DateTime?[]));
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                GetObjectDataCalled = true;
+
+                info.AddValue("byte", Byte, typeof(object));
+                info.AddValue("bytes", Bytes, typeof(object));
+                info.AddValue("sbyte", Sbyte, typeof(object));
+                info.AddValue("sbytes", Sbytes, typeof(object));
+                info.AddValue("bool", Bool, typeof(object));
+                info.AddValue("bools", Bools, typeof(object));
+                info.AddValue("char", Char, typeof(object));
+                info.AddValue("chars", Chars, typeof(object));
+                info.AddValue("short", Short, typeof(object));
+                info.AddValue("shorts", Shorts, typeof(object));
+                info.AddValue("ushort", Ushort, typeof(object));
+                info.AddValue("ushorts", Ushorts, typeof(object));
+                info.AddValue("int", Int, typeof(object));
+                info.AddValue("ints", Ints, typeof(object));
+                info.AddValue("uint", Uint, typeof(object));
+                info.AddValue("uints", Uints, typeof(object));
+                info.AddValue("long", Long, typeof(object));
+                info.AddValue("longs", Longs, typeof(object));
+                info.AddValue("ulong", Ulong, typeof(object));
+                info.AddValue("ulongs", Ulongs, typeof(object));
+                info.AddValue("float", Float, typeof(object));
+                info.AddValue("floats", Floats, typeof(object));
+                info.AddValue("double", Double, typeof(object));
+                info.AddValue("doubles", Doubles, typeof(object));
+                info.AddValue("decimal", Decimal, typeof(object));
+                info.AddValue("decimals", Decimals, typeof(object));
+                info.AddValue("guid", Guid, typeof(object));
+                info.AddValue("guids", Guids, typeof(object));
+                info.AddValue("datetime", DateTime, typeof(object));
+                info.AddValue("datetimes", DateTimes, typeof(object));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/SqlDmlTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/SqlDmlTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/SqlDmlTest.cs
new file mode 100644
index 0000000..b59247e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/SqlDmlTest.cs
@@ -0,0 +1,277 @@
+\ufeff/*
+ * 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.
+ */
+
+// ReSharper disable UnusedMember.Local
+// ReSharper disable UnusedParameter.Local
+namespace Apache.Ignite.Core.Tests.Binary.Serializable
+{
+    using System;
+    using System.IO;
+    using System.Linq;
+    using System.Runtime.Serialization;
+    using System.Text;
+    using System.Threading;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Linq;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests SQL and DML with Serializable types.
+    /// </summary>
+    public class SqlDmlTest
+    {
+        /** */
+        private IIgnite _ignite;
+        
+        /** */
+        private StringBuilder _outSb;
+
+        /// <summary>
+        /// Sets up the test fixture.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            _outSb = new StringBuilder();
+            Console.SetError(new StringWriter(_outSb));
+
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                BinaryConfiguration = new BinaryConfiguration(typeof(SimpleSerializable))
+            };
+
+            _ignite = Ignition.Start(cfg);
+        }
+
+        /// <summary>
+        /// Tears down the test fixture.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests the simple serializable.
+        /// </summary>
+        [Test]
+        public void TestSimpleSerializable()
+        {
+            var cache = _ignite.CreateCache<int, SimpleSerializable>(
+                new CacheConfiguration("simple", new QueryEntity(typeof(int), typeof(SimpleSerializable))));
+
+            cache[1] = new SimpleSerializable
+            {
+                String = "abc"
+            };
+            cache[2] = new SimpleSerializable
+            {
+                Byte = 25,
+                Bool = true,
+                Short = 66,
+                Int = 2,
+                Long = 98,
+                Float = 2.25f,
+                Double = 1.123,
+                Decimal = 5.67m,
+                Guid = Guid.NewGuid(),
+                String = "bar2"
+            };
+
+            // Test SQL.
+            var res = cache.Query(new SqlQuery(typeof(SimpleSerializable), "where Int = 2")).GetAll().Single();
+
+            Assert.AreEqual(2, res.Key);
+            Assert.AreEqual(2, res.Value.Int);
+            Assert.AreEqual("bar2", res.Value.String);
+
+            // Test DML.
+            var guid = Guid.NewGuid();
+            var insertRes = cache.QueryFields(new SqlFieldsQuery(
+                "insert into SimpleSerializable(_key, Byte, Bool, Short, Int, Long, Float, Double, " +
+                "Decimal, Guid, String) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 
+                3, 45, true, 43, 33, 99, 4.5f, 6.7, 9.04m, guid, "bar33")).GetAll();
+
+            Assert.AreEqual(1, insertRes.Count);
+            Assert.AreEqual(1, insertRes[0][0]);
+
+            var dmlRes = cache[3];
+            Assert.AreEqual(45, dmlRes.Byte);
+            Assert.AreEqual(true, dmlRes.Bool);
+            Assert.AreEqual(43, dmlRes.Short);
+            Assert.AreEqual(33, dmlRes.Int);
+            Assert.AreEqual(99, dmlRes.Long);
+            Assert.AreEqual(4.5f, dmlRes.Float);
+            Assert.AreEqual(6.7, dmlRes.Double);
+            Assert.AreEqual(9.04m, dmlRes.Decimal);
+            Assert.AreEqual(guid, dmlRes.Guid);
+            Assert.AreEqual("bar33", dmlRes.String);
+        }
+
+        /// <summary>
+        /// Tests the .NET specific serializable.
+        /// </summary>
+        [Test]
+        public void TestDotNetSpecificSerializable()
+        {
+            var cache = _ignite.CreateCache<int, DotNetSpecificSerializable>(new CacheConfiguration("dotnet-ser",
+                new QueryEntity(typeof(int), typeof(DotNetSpecificSerializable))));
+
+            cache[1] = new DotNetSpecificSerializable(uint.MaxValue);
+            Assert.AreEqual(uint.MaxValue, cache[1].Uint);
+
+            // Test SQL.
+            var sqlRes = cache.QueryFields(new SqlFieldsQuery(
+                "select uint from DotNetSpecificSerializable where uint <> 0")).GetAll();
+
+            Assert.AreEqual(1, sqlRes.Count);
+            Assert.AreEqual(uint.MaxValue, (uint) (int) sqlRes[0][0]);
+
+            // Test LINQ.
+            var linqRes = cache.AsCacheQueryable().Select(x => x.Value.Uint).Single();
+            Assert.AreEqual(uint.MaxValue, linqRes);
+
+            // Test DML.
+            var dmlRes = cache.QueryFields(new SqlFieldsQuery(
+                "insert into DotNetSpecificSerializable(_key, uint) values (?, ?), (?, ?)",
+                2, uint.MaxValue, 3, 88)).GetAll();
+            Assert.AreEqual(1, dmlRes.Count);
+
+            Assert.AreEqual(88, cache[3].Uint);  // Works when value is in int range.
+
+            var ex = Assert.Throws<OverflowException>(() => cache.Get(2));  // Fails when out of int range.
+            Assert.AreEqual("Value was either too large or too small for a UInt32.", ex.Message);
+        }
+
+        /// <summary>
+        /// Tests the log warning.
+        /// </summary>
+        [Test]
+        public void TestLogWarning()
+        {
+            Thread.Sleep(10);  // Wait for logger update.
+
+            var expected =
+                string.Format("[WARN ][main][Marshaller] Type '{0}' implements '{1}'. " +
+                              "It will be written in Ignite binary format, however, " +
+                              "the following limitations apply: DateTime fields would not work in SQL; " +
+                              "sbyte, ushort, uint, ulong fields would not work in DML.",
+                    typeof(SimpleSerializable), typeof(ISerializable));
+
+            Assert.IsTrue(_outSb.ToString().Contains(expected));
+        }
+
+        /// <summary>
+        /// Serializable with Java-compatible fields.
+        /// </summary>
+        private class SimpleSerializable : ISerializable
+        {
+            [QuerySqlField]
+            public byte Byte { get; set; }
+
+            [QuerySqlField]
+            public bool Bool { get; set; }
+
+            [QuerySqlField]
+            public short Short { get; set; }
+            
+            [QuerySqlField]
+            public int Int { get; set; }
+            
+            [QuerySqlField]
+            public long Long { get; set; }
+            
+            [QuerySqlField]
+            public float Float { get; set; }
+            
+            [QuerySqlField]
+            public double Double { get; set; }
+            
+            [QuerySqlField]
+            public decimal Decimal { get; set; }
+            
+            [QuerySqlField]
+            public Guid Guid { get; set; }
+            
+            [QuerySqlField]
+            public string String { get; set; }
+
+            public SimpleSerializable()
+            {
+                // No-op.
+            }
+
+            public SimpleSerializable(SerializationInfo info, StreamingContext context)
+            {
+                Byte = info.GetByte("Byte");
+                Bool = info.GetBoolean("Bool");
+                Short = info.GetInt16("Short");
+                Int = info.GetInt32("Int");
+                Long = info.GetInt64("Long");
+                Float = info.GetSingle("Float");
+                Double = info.GetDouble("Double");
+                Decimal = info.GetDecimal("Decimal");
+                Guid = (Guid) info.GetValue("Guid", typeof(Guid));
+                String = info.GetString("String");
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.AddValue("Byte", Byte);
+                info.AddValue("Bool", Bool);
+                info.AddValue("Short", Short);
+                info.AddValue("Int", Int);
+                info.AddValue("Long", Long);
+                info.AddValue("Float", Float);
+                info.AddValue("Double", Double);
+                info.AddValue("Decimal", Decimal);
+                info.AddValue("Guid", Guid);
+                info.AddValue("String", String);
+            }
+        }
+
+        /// <summary>
+        /// Serializable with incompatible fields.
+        /// </summary>
+        private class DotNetSpecificSerializable : ISerializable
+        {
+            /// <summary>
+            /// Uint is not supported in Java.
+            /// </summary>
+            [QuerySqlField]
+            public uint Uint { get; set; }
+
+            public DotNetSpecificSerializable(uint u)
+            {
+                Uint = u;
+            }
+
+            public DotNetSpecificSerializable(SerializationInfo info, StreamingContext context)
+            {
+                Uint = info.GetUInt32("uint");
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.AddValue("uint", Uint);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs
index 9348449..a3e6252 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs
@@ -233,21 +233,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
         }
 
         /// <summary>
-        /// Tests the error on non-serializable function.
-        /// </summary>
-        [Test]
-        public void TestNonSerializableFunction()
-        {
-            var ex = Assert.Throws<IgniteException>(() =>
-                _ignite.CreateCache<int, int>(new CacheConfiguration("failCache")
-                {
-                    AffinityFunction = new NonSerializableAffinityFunction()
-                }));
-
-            Assert.AreEqual(ex.Message, "AffinityFunction should be serializable.");
-        }
-
-        /// <summary>
         /// Tests the exception propagation.
         /// </summary>
         [Test]
@@ -388,12 +373,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
             }
         }
 
-        private class NonSerializableAffinityFunction : SimpleAffinityFunction
-        {
-            // No-op.
-        }
-
-        [Serializable]
         private class FailInGetPartitionAffinityFunction : IAffinityFunction
         {
             public int Partitions

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 f97741a..ce0441d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
@@ -232,9 +232,19 @@ namespace Apache.Ignite.Core.Tests.Cache
     /// <summary>
     /// Non-serializable processor.
     /// </summary>
-    public class NonSerializableCacheEntryProcessor : AddArgCacheEntryProcessor
+    public class NonSerializableCacheEntryProcessor : AddArgCacheEntryProcessor, IBinarizable
     {
-        // No-op.
+        /** <inheritdoc /> */
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            throw new Exception("ExpectedException");
+        }
+
+        /** <inheritdoc /> */
+        public void ReadBinary(IBinaryReader reader)
+        {
+            throw new Exception("ExpectedException");
+        }
     }
 
     /// <summary>
@@ -269,9 +279,19 @@ namespace Apache.Ignite.Core.Tests.Cache
     /// <summary>
     /// Non-serializable exception.
     /// </summary>
-    public class NonSerializableException : Exception
+    public class NonSerializableException : Exception, IBinarizable
     {
-        // No-op
+        /** <inheritdoc /> */
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            throw new Exception("ExpectedException");
+        }
+
+        /** <inheritdoc /> */
+        public void ReadBinary(IBinaryReader reader)
+        {
+            throw new Exception("ExpectedException");
+        }
     }
 
     /// <summary>
@@ -2356,15 +2376,7 @@ namespace Apache.Ignite.Core.Tests.Cache
             TestInvoke<AddArgCacheEntryProcessor>(async);
             TestInvoke<BinarizableAddArgCacheEntryProcessor>(async);
 
-            try
-            {
-                TestInvoke<NonSerializableCacheEntryProcessor>(async);
-                Assert.Fail();
-            }
-            catch (BinaryObjectException)
-            {
-                // Expected
-            }
+            Assert.Throws<Exception>(() => TestInvoke<NonSerializableCacheEntryProcessor>(async));
         }
 
         private void TestInvoke<T>(bool async) where T: AddArgCacheEntryProcessor, new()
@@ -2396,7 +2408,7 @@ namespace Apache.Ignite.Core.Tests.Cache
             AssertThrowsCacheEntryProcessorException(
                 () => cache.Invoke(key, new T {ThrowErrBinarizable = true}, arg));
             AssertThrowsCacheEntryProcessorException(
-                () => cache.Invoke(key, new T { ThrowErrNonSerializable = true }, arg), "BinaryObjectException");
+                () => cache.Invoke(key, new T { ThrowErrNonSerializable = true }, arg), "ExpectedException");
         }
 
         private static void AssertThrowsCacheEntryProcessorException(Action action, string containsText = null)
@@ -2417,7 +2429,8 @@ namespace Apache.Ignite.Core.Tests.Cache
                     Assert.AreEqual(AddArgCacheEntryProcessor.ExceptionText, ex.InnerException.Message);
                 }
                 else
-                    Assert.IsTrue(ex.ToString().Contains(containsText));
+                    Assert.IsTrue(ex.ToString().Contains(containsText), 
+                        "Expected: " + containsText + ", actual: " + ex);
             }
         }
 
@@ -2439,16 +2452,7 @@ namespace Apache.Ignite.Core.Tests.Cache
             {
                 TestInvokeAll<AddArgCacheEntryProcessor>(async, i);
                 TestInvokeAll<BinarizableAddArgCacheEntryProcessor>(async, i);
-
-                try
-                {
-                    TestInvokeAll<NonSerializableCacheEntryProcessor>(async, i);
-                    Assert.Fail();
-                }
-                catch (BinaryObjectException)
-                {
-                    // Expected
-                }
+                Assert.Throws<Exception>(() => TestInvokeAll<NonSerializableCacheEntryProcessor>(async, i));
             }
         }
 
@@ -2493,7 +2497,7 @@ namespace Apache.Ignite.Core.Tests.Cache
             TestInvokeAllException(cache, entries, new T { ThrowErrBinarizable = true, ThrowOnKey = errKey }, 
                 arg, errKey);
             TestInvokeAllException(cache, entries, new T { ThrowErrNonSerializable = true, ThrowOnKey = errKey },
-                arg, errKey, "BinaryObjectException");
+                arg, errKey, "ExpectedException");
 
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
index fc47f52..d6705d4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
@@ -55,7 +55,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         [TestFixtureSetUp]
         public void StartGrids()
         {
-            TestUtils.JvmDebug = true;
             TestUtils.KillProcesses();
 
             IgniteConfiguration cfg = new IgniteConfiguration
@@ -867,8 +866,16 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
     /// <summary>
     /// Filter that can't be serialized.
     /// </summary>
-    public class InvalidScanQueryFilter<TV> : ScanQueryFilter<TV>
+    public class InvalidScanQueryFilter<TV> : ScanQueryFilter<TV>, IBinarizable
     {
-        // No-op.
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            throw new BinaryObjectException("Expected");
+        }
+
+        public void ReadBinary(IBinaryReader reader)
+        {
+            throw new BinaryObjectException("Expected");
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryAbstractTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryAbstractTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryAbstractTest.cs
index e890198..3c0633d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryAbstractTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryAbstractTest.cs
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+#pragma warning disable 618
 namespace Apache.Ignite.Core.Tests.Cache.Query.Continuous
 {
     using System;
@@ -1108,9 +1109,19 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Continuous
         /// <summary>
         /// Filter which cannot be serialized.
         /// </summary>
-        public class LocalFilter : AbstractFilter<BinarizableEntry>
+        public class LocalFilter : AbstractFilter<BinarizableEntry>, IBinarizable
         {
-            // No-op.
+            /** <inheritDoc /> */
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                throw new BinaryObjectException("Expected");
+            }
+
+            /** <inheritDoc /> */
+            public void ReadBinary(IBinaryReader reader)
+            {
+                throw new BinaryObjectException("Expected");
+            }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Store/CacheStoreTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Store/CacheStoreTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Store/CacheStoreTest.cs
index 4b13b9f..76241d2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Store/CacheStoreTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Store/CacheStoreTest.cs
@@ -23,7 +23,9 @@ namespace Apache.Ignite.Core.Tests.Cache.Store
     using System.Linq;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Store;
+    using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl;
     using NUnit.Framework;
 
@@ -107,9 +109,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Store
             for (int i = 105; i < 110; i++)
                 Assert.AreEqual("val_" + i, cache.Get(i));
 
-            // Test invalid filter
-            Assert.Throws<BinaryObjectException>(() => cache.LoadCache(new InvalidCacheEntryFilter(), 100, 10));
-
             // Test exception in filter
             Assert.Throws<CacheStoreException>(() => cache.LoadCache(new ExceptionalEntryFilter(), 100, 10));
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 e82e238..3ef9ad0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
@@ -911,10 +911,12 @@ namespace Apache.Ignite.Core.Tests.Compute
             Assert.AreEqual(1, res.GetField<int>("field"));
 
             // This call must fail because "keepBinary" flag is reset.
-            Assert.Catch(typeof(BinaryObjectException), () =>
+            var ex = Assert.Throws<BinaryObjectException>(() =>
             {
                 compute.ExecuteJavaTask<IBinaryObject>(EchoTask, EchoTypeBinarizableJava);
             });
+
+            Assert.AreEqual("Unknown pair [platformId=1, typeId=2009791293]", ex.Message);
         }
 
         /// <summary>
@@ -1386,9 +1388,17 @@ namespace Apache.Ignite.Core.Tests.Compute
         }
     }
 
-    class InvalidNetSimpleJob : NetSimpleJob
+    class InvalidNetSimpleJob : NetSimpleJob, IBinarizable
     {
-        // No-op.
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            throw new BinaryObjectException("Expected");
+        }
+
+        public void ReadBinary(IBinaryReader reader)
+        {
+            throw new BinaryObjectException("Expected");
+        }
     }
 
     [Serializable]
@@ -1460,9 +1470,17 @@ namespace Apache.Ignite.Core.Tests.Compute
         }
     }
 
-    class InvalidComputeAction : ComputeAction
+    class InvalidComputeAction : ComputeAction, IBinarizable
     {
-        // No-op.
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            throw new BinaryObjectException("Expected");
+        }
+
+        public void ReadBinary(IBinaryReader reader)
+        {
+            throw new BinaryObjectException("Expected");
+        }
     }
 
     interface IUserInterface<out T>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
index 912102c..21cd263 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
@@ -88,9 +88,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         {
             Mode = ErrorMode.MapJobNotMarshalable;
 
-            var e = ExecuteWithError() as BinaryObjectException;
-
-            Assert.IsNotNull(e);
+            Assert.IsInstanceOf<BinaryObjectException>(ExecuteWithError());
         }
 
         /// <summary>
@@ -168,13 +166,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         {
             Mode = ErrorMode.RmtJobErrNotMarshalable;
 
-            int res = Execute();
-
-            Assert.AreEqual(1, res);
-
-            Assert.AreEqual(4, JobErrs.Count);
-
-            Assert.IsNotNull(JobErrs.ElementAt(0) as IgniteException);
+            Assert.Throws<SerializationException>(() => Execute());
         }
 
         /// <summary>
@@ -566,7 +558,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// 
         /// </summary>
-        public class BadJob : IComputeJob<object>
+        public class BadJob : IComputeJob<object>, IBinarizable
         {
             [InstanceResource]
 
@@ -581,6 +573,18 @@ namespace Apache.Ignite.Core.Tests.Compute
             {
                 // No-op.
             }
+
+            /** <inheritDoc /> */
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                throw new BinaryObjectException("Expected");
+            }
+
+            /** <inheritDoc /> */
+            public void ReadBinary(IBinaryReader reader)
+            {
+                throw new BinaryObjectException("Expected");
+            }
         }
 
         /// <summary>
@@ -621,7 +625,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// 
         /// </summary>
-        public class BadJobResult
+        public class BadJobResult : IBinarizable
         {
             /** */
             public bool Rmt;
@@ -634,6 +638,18 @@ namespace Apache.Ignite.Core.Tests.Compute
             {
                 Rmt = rmt;
             }
+
+            /** <inheritDoc /> */
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                throw new BinaryObjectException("Expected");
+            }
+
+            /** <inheritDoc /> */
+            public void ReadBinary(IBinaryReader reader)
+            {
+                throw new BinaryObjectException("Expected");
+            }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ResourceTaskTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ResourceTaskTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ResourceTaskTest.cs
index 433b635..c693a8b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ResourceTaskTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ResourceTaskTest.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests.Compute
     using System.Collections.Generic;
     using System.Linq;
     using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cluster;
     using Apache.Ignite.Core.Compute;
     using Apache.Ignite.Core.Resource;
@@ -158,9 +159,17 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// Binarizable job.
         /// </summary>
-        public class InjectionJobBinarizable : InjectionJob
+        public class InjectionJobBinarizable : InjectionJob, IBinarizable
         {
-            // No-op.
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                // No-op.
+            }
+
+            public void ReadBinary(IBinaryReader reader)
+            {
+                // No-op.
+            }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
index ab5a1a6..ece4894 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
@@ -15,8 +15,6 @@
  * limitations under the License.
  */
 
-#pragma warning disable 649
-#pragma warning disable 169
 namespace Apache.Ignite.Core.Tests
 {
     using System;
@@ -53,15 +51,21 @@ namespace Apache.Ignite.Core.Tests
             Assert.Greater(jars.Length, 3);
 
             foreach (var jar in jars)
-                // ReSharper disable once AssignNullToNotNullAttribute
-                File.Copy(jar, Path.Combine(folder, Path.GetFileName(jar)), true);
+            {
+                var fileName = Path.GetFileName(jar);
+                Assert.IsNotNull(fileName);
+                File.Copy(jar, Path.Combine(folder, fileName), true);
+            }
 
             // Build classpath
             var classpath = string.Join(";", Directory.GetFiles(folder).Select(Path.GetFileName));
 
             // Copy .NET binaries
-            foreach (var asm in new[] {typeof (IgniteRunner).Assembly, typeof (Ignition).Assembly, GetType().Assembly})
+            foreach (var asm in new[] {typeof(IgniteRunner).Assembly, typeof(Ignition).Assembly, GetType().Assembly})
+            {
+                Assert.IsNotNull(asm.Location);
                 File.Copy(asm.Location, Path.Combine(folder, Path.GetFileName(asm.Location)));
+            }
 
             // Copy config
             var springPath = Path.GetFullPath("config\\compute\\compute-grid2.xml");
@@ -76,7 +80,6 @@ namespace Apache.Ignite.Core.Tests
                 "-springConfigUrl=" + springFile,
                 "-jvmClasspath=" + classpath,
                 "-J-ea",
-                "-J-Xcheck:jni",
                 "-J-Xms512m",
                 "-J-Xmx512m"
             });
@@ -157,6 +160,7 @@ namespace Apache.Ignite.Core.Tests
             throw new InvalidOperationException();
         }
 
+        #pragma warning disable 649
         /// <summary>
         /// Function that returns process path.
         /// </summary>


[5/5] ignite git commit: IGNITE-2703 .NET: Dynamic type registration

Posted by pt...@apache.org.
IGNITE-2703 .NET: Dynamic type registration

* BinaryTypeConfiguration is not required anymore
* Serializable types are written in Ignite binary format


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

Branch: refs/heads/master
Commit: 79bac4f87b15081d44e096d5bfc2c22854aad20e
Parents: 2ad2365
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Fri Mar 31 16:31:56 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Fri Mar 31 16:31:56 2017 +0300

----------------------------------------------------------------------
 .../ignite/internal/MarshallerPlatformIds.java  |   3 +
 .../ignite/internal/binary/BinaryUtils.java     |   4 +
 .../platform/PlatformContextImpl.java           |  10 +-
 .../binary/PlatformBinaryProcessor.java         |  40 +-
 .../Apache.Ignite.Core.Tests.csproj             |  11 +-
 .../Binary/BinaryBuilderSelfTest.cs             | 112 +--
 .../BinaryBuilderSelfTestDynamicRegistration.cs |  40 +
 .../Binary/BinaryCompactFooterInteropTest.cs    |   2 +-
 .../Binary/BinaryDynamicRegistrationTest.cs     | 441 +++++++++++
 .../Binary/BinarySelfTest.cs                    | 197 +++--
 .../Binary/BinarySelfTestFullFooter.cs          |   5 +-
 .../Binary/JavaBinaryInteropTest.cs             | 182 +++++
 .../Serializable/AdvancedSerializationTest.cs   | 228 ++++++
 .../BasicSerializableObjectsTest.cs             | 124 +++
 .../Binary/Serializable/CallbacksTest.cs        | 369 +++++++++
 .../Binary/Serializable/DelegatesTest.cs        | 161 ++++
 .../Binary/Serializable/ObjectReferenceTests.cs | 131 ++++
 .../Binary/Serializable/PrimitivesTest.cs       | 754 +++++++++++++++++++
 .../Binary/Serializable/SqlDmlTest.cs           | 277 +++++++
 .../Cache/Affinity/AffinityFunctionTest.cs      |  21 -
 .../Cache/CacheAbstractTest.cs                  |  56 +-
 .../Cache/Query/CacheQueriesTest.cs             |  13 +-
 .../Continuous/ContinuousQueryAbstractTest.cs   |  15 +-
 .../Cache/Store/CacheStoreTest.cs               |   5 +-
 .../Compute/ComputeApiTest.cs                   |  28 +-
 .../Compute/IgniteExceptionTaskSelfTest.cs      |  40 +-
 .../Compute/ResourceTaskTest.cs                 |  13 +-
 .../Apache.Ignite.Core.Tests/DeploymentTest.cs  |  16 +-
 .../Examples/ExamplesTest.cs                    |   2 +-
 .../Apache.Ignite.Core.Tests/ExecutableTest.cs  |  28 +-
 .../SerializationTest.cs                        | 240 ------
 .../Services/ServiceProxyTest.cs                |  40 +-
 .../Apache.Ignite.Core.Tests/TestUtils.cs       |  11 +
 .../Apache.Ignite.Core.csproj                   |   7 +-
 .../Cache/Configuration/CacheConfiguration.cs   |   8 +-
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |  25 +-
 .../dotnet/Apache.Ignite.Core/Ignition.cs       |   4 +-
 .../Impl/Binary/BinarizableSerializer.cs        |   5 +-
 .../Impl/Binary/BinaryFullTypeDescriptor.cs     |  49 +-
 .../Impl/Binary/BinaryObjectBuilder.cs          |  27 +-
 .../Impl/Binary/BinaryObjectHeader.cs           |  13 +-
 .../Impl/Binary/BinaryObjectSchemaSerializer.cs |   2 +
 .../Impl/Binary/BinaryProcessor.cs              |  38 +-
 .../Impl/Binary/BinaryReader.cs                 |  39 +-
 .../Impl/Binary/BinaryReflectiveActions.cs      |   2 +-
 .../BinaryReflectiveSerializerInternal.cs       |  84 ++-
 .../Binary/BinarySurrogateTypeDescriptor.cs     |  13 +-
 .../Impl/Binary/BinarySystemHandlers.cs         |  96 +--
 .../Impl/Binary/BinarySystemTypeSerializer.cs   |   2 +-
 .../Impl/Binary/BinaryUtils.cs                  |  54 +-
 .../Impl/Binary/BinaryWriter.cs                 | 242 +++---
 .../Impl/Binary/DateTimeHolder.cs               | 101 ---
 .../Impl/Binary/DateTimeSerializer.cs           |  48 --
 .../Binary/DeserializationCallbackProcessor.cs  | 102 +++
 .../Impl/Binary/IBinarySerializerInternal.cs    |   4 +-
 .../Impl/Binary/IBinaryTypeDescriptor.cs        |   8 +
 .../Impl/Binary/Io/BinaryStreamAdapter.cs       | 119 ---
 .../Impl/Binary/Marshaller.cs                   | 248 ++++--
 .../Impl/Binary/ReflectionUtils.cs              |  50 ++
 .../Impl/Binary/SerializableObjectHolder.cs     |  96 ---
 .../Impl/Binary/SerializableSerializer.cs       | 656 +++++++++++++++-
 .../Impl/Binary/TypeResolver.cs                 |   7 +
 .../Impl/Binary/UserSerializerProxy.cs          |   5 +-
 .../Affinity/AffinityFunctionSerializer.cs      |   3 -
 .../Apache.Ignite.Core/Impl/Cache/CacheImpl.cs  |   3 +-
 .../Common/CopyOnWriteConcurrentDictionary.cs   |  35 +
 .../Impl/Common/DelegateConverter.cs            |  90 ++-
 .../Impl/Common/DelegateTypeDescriptor.cs       |   3 +-
 .../Impl/Common/SerializableTypeDescriptor.cs   | 222 ++++++
 .../dotnet/Apache.Ignite.Core/Impl/Ignite.cs    |  13 +-
 .../Impl/Services/ServiceProxySerializer.cs     |   4 +-
 .../Impl/Unmanaged/UnmanagedCallbacks.cs        |   8 +-
 .../NuGet/LINQPad/ComputeExample.linq           |   1 -
 .../NuGet/LINQPad/PutGetExample.linq            |   5 +-
 .../NuGet/LINQPad/QueryExample.linq             |   5 +-
 .../NuGet/LINQPad/QueryExample.linq             |   5 +-
 .../examples/Apache.Ignite.Examples/App.config  |  16 +-
 .../Apache.Ignite.ExamplesDll/Binary/Address.cs |   2 -
 .../Compute/CharacterCountClosure.cs            |   1 -
 .../Datagrid/ContinuousQueryFilter.cs           |   2 -
 .../Datagrid/EmployeeStorePredicate.cs          |   2 -
 .../Messaging/RemoteOrderedListener.cs          |   1 -
 .../Messaging/RemoteUnorderedListener.cs        |   1 -
 .../Services/MapService.cs                      |   1 -
 84 files changed, 4956 insertions(+), 1240 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/core/src/main/java/org/apache/ignite/internal/MarshallerPlatformIds.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerPlatformIds.java b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerPlatformIds.java
index 458ae49..4167f41 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerPlatformIds.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerPlatformIds.java
@@ -25,6 +25,9 @@ public final class MarshallerPlatformIds {
     public static final byte JAVA_ID = 0;
 
     /** */
+    public static final byte DOTNET_ID = 1;
+
+    /** */
     private MarshallerPlatformIds() {
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
index c59b8b7..e4011a4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
@@ -110,6 +110,10 @@ public class BinaryUtils {
     /** Flag: compact footer, no field IDs. */
     public static final short FLAG_COMPACT_FOOTER = 0x0020;
 
+    /** Flag: raw data contains .NET type information. Always 0 in Java. Keep it here for information only. */
+    @SuppressWarnings("unused")
+    public static final short FLAG_CUSTOM_DOTNET_TYPE = 0x0040;
+
     /** Offset which fits into 1 byte. */
     public static final int OFFSET_1 = 1;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
index 10a8f74..bdcb88c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
@@ -430,10 +430,12 @@ public class PlatformContextImpl implements PlatformContext {
         if (schema == null) {
             BinaryTypeImpl meta = (BinaryTypeImpl)cacheObjProc.metadata(typeId);
 
-            for (BinarySchema typeSchema : meta.metadata().schemas()) {
-                if (schemaId == typeSchema.schemaId()) {
-                    schema = typeSchema;
-                    break;
+            if (meta != null) {
+                for (BinarySchema typeSchema : meta.metadata().schemas()) {
+                    if (schemaId == typeSchema.schemaId()) {
+                        schema = typeSchema;
+                        break;
+                    }
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java
index 3c00abc..8d95ac8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.processors.platform.binary;
 
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.internal.MarshallerPlatformIds;
 import org.apache.ignite.internal.binary.BinaryRawReaderEx;
 import org.apache.ignite.internal.binary.BinaryRawWriterEx;
 import org.apache.ignite.internal.processors.platform.PlatformAbstractTarget;
@@ -39,6 +41,12 @@ public class PlatformBinaryProcessor extends PlatformAbstractTarget {
     /** */
     private static final int OP_GET_SCHEMA = 4;
 
+    /** */
+    private static final int OP_REGISTER_TYPE = 5;
+
+    /** */
+    private static final int OP_GET_TYPE = 6;
+
     /**
      * Constructor.
      *
@@ -50,10 +58,20 @@ public class PlatformBinaryProcessor extends PlatformAbstractTarget {
 
     /** {@inheritDoc} */
     @Override public long processInStreamOutLong(int type, BinaryRawReaderEx reader) throws IgniteCheckedException {
-        if (type == OP_PUT_META) {
-            platformCtx.processMetadata(reader);
+        switch (type) {
+            case OP_PUT_META:
+                platformCtx.processMetadata(reader);
+
+                return TRUE;
+
+            case OP_REGISTER_TYPE: {
+                int typeId = reader.readInt();
+                String typeName = reader.readString();
 
-            return TRUE;
+                return platformContext().kernalContext().marshallerContext()
+                    .registerClassName(MarshallerPlatformIds.DOTNET_ID, typeId, typeName)
+                    ? TRUE : FALSE;
+            }
         }
 
         return super.processInStreamOutLong(type, reader);
@@ -88,6 +106,22 @@ public class PlatformBinaryProcessor extends PlatformAbstractTarget {
                 break;
             }
 
+            case OP_GET_TYPE: {
+                int typeId = reader.readInt();
+
+                try {
+                    String typeName = platformContext().kernalContext().marshallerContext()
+                        .getClassName(MarshallerPlatformIds.DOTNET_ID, typeId);
+
+                    writer.writeString(typeName);
+                }
+                catch (ClassNotFoundException e) {
+                    throw new BinaryObjectException(e);
+                }
+
+                break;
+            }
+
             default:
                 super.processInStreamOutStream(type, reader, writer);
                 break;

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 1540243..27aec9c 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
@@ -69,9 +69,17 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Binary\BinaryEqualityComparerTest.cs" />
+    <Compile Include="Binary\BinaryBuilderSelfTestDynamicRegistration.cs" />
     <Compile Include="Binary\BinaryReaderWriterTest.cs" />
     <Compile Include="Binary\IO\BinaryStreamsTest.cs" />
+    <Compile Include="Binary\JavaBinaryInteropTest.cs" />
     <Compile Include="Binary\JavaTypeMappingTest.cs" />
+    <Compile Include="Binary\Serializable\CallbacksTest.cs" />
+    <Compile Include="Binary\Serializable\DelegatesTest.cs" />
+    <Compile Include="Binary\Serializable\BasicSerializableObjectsTest.cs" />
+    <Compile Include="Binary\Serializable\ObjectReferenceTests.cs" />
+    <Compile Include="Binary\Serializable\PrimitivesTest.cs" />
+    <Compile Include="Binary\Serializable\SqlDmlTest.cs" />
     <Compile Include="Binary\TypeResolverTest.cs" />
     <Compile Include="Cache\Affinity\AffinityKeyTest.cs" />
     <Compile Include="Cache\Affinity\AffinityTopologyVersionTest.cs" />
@@ -103,6 +111,7 @@
     <Compile Include="TestAppConfig.cs" />
     <Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" />
     <Compile Include="Binary\BinaryCompactFooterInteropTest.cs" />
+    <Compile Include="Binary\BinaryDynamicRegistrationTest.cs" />
     <Compile Include="Binary\BinarySelfTestFullFooter.cs" />
     <Compile Include="Binary\BinaryStringTest.cs" />
     <Compile Include="Cache\Affinity\AffinityFieldTest.cs" />
@@ -190,7 +199,7 @@
     <Compile Include="ProcessExtensions.cs" />
     <Compile Include="ProjectFilesTest.cs" />
     <Compile Include="ReconnectTest.cs" />
-    <Compile Include="SerializationTest.cs" />
+    <Compile Include="Binary\Serializable\AdvancedSerializationTest.cs" />
     <Compile Include="IgniteStartStopTest.cs" />
     <Compile Include="Services\ServicesTestFullFooter.cs" />
     <Compile Include="TestUtils.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 e59611b..35c7e47 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
@@ -56,36 +56,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             {
                 BinaryConfiguration = new BinaryConfiguration
                 {
-                    TypeConfigurations = new List<BinaryTypeConfiguration>
-                    {
-                        new BinaryTypeConfiguration(typeof(Empty)),
-                        new BinaryTypeConfiguration(typeof(Primitives)),
-                        new BinaryTypeConfiguration(typeof(PrimitiveArrays)),
-                        new BinaryTypeConfiguration(typeof(StringDateGuidEnum)),
-                        new BinaryTypeConfiguration(typeof(WithRaw)),
-                        new BinaryTypeConfiguration(typeof(MetaOverwrite)),
-                        new BinaryTypeConfiguration(typeof(NestedOuter)),
-                        new BinaryTypeConfiguration(typeof(NestedInner)),
-                        new BinaryTypeConfiguration(typeof(MigrationOuter)),
-                        new BinaryTypeConfiguration(typeof(MigrationInner)),
-                        new BinaryTypeConfiguration(typeof(InversionOuter)),
-                        new BinaryTypeConfiguration(typeof(InversionInner)),
-                        new BinaryTypeConfiguration(typeof(CompositeOuter)),
-                        new BinaryTypeConfiguration(typeof(CompositeInner)),
-                        new BinaryTypeConfiguration(typeof(CompositeArray)),
-                        new BinaryTypeConfiguration(typeof(CompositeContainer)),
-                        new BinaryTypeConfiguration(typeof(ToBinary)),
-                        new BinaryTypeConfiguration(typeof(Remove)),
-                        new BinaryTypeConfiguration(typeof(RemoveInner)),
-                        new BinaryTypeConfiguration(typeof(BuilderInBuilderOuter)),
-                        new BinaryTypeConfiguration(typeof(BuilderInBuilderInner)),
-                        new BinaryTypeConfiguration(typeof(BuilderCollection)),
-                        new BinaryTypeConfiguration(typeof(BuilderCollectionItem)),
-                        new BinaryTypeConfiguration(typeof(DecimalHolder)),
-                        new BinaryTypeConfiguration(TypeEmpty),
-                        new BinaryTypeConfiguration(typeof(TestEnumRegistered)),
-                        new BinaryTypeConfiguration(typeof(NameMapperTestType))
-                    },
+                    TypeConfigurations = GetTypeConfigurations(),
                     DefaultIdMapper = new IdMapper(),
                     DefaultNameMapper = new NameMapper(),
                     CompactFooter = GetCompactFooter()
@@ -98,6 +69,43 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
 
         /// <summary>
+        /// Gets the type configurations.
+        /// </summary>
+        protected virtual ICollection<BinaryTypeConfiguration> GetTypeConfigurations()
+        {
+            return new[]
+            {
+                new BinaryTypeConfiguration(typeof(Empty)),
+                new BinaryTypeConfiguration(typeof(Primitives)),
+                new BinaryTypeConfiguration(typeof(PrimitiveArrays)),
+                new BinaryTypeConfiguration(typeof(StringDateGuidEnum)),
+                new BinaryTypeConfiguration(typeof(WithRaw)),
+                new BinaryTypeConfiguration(typeof(MetaOverwrite)),
+                new BinaryTypeConfiguration(typeof(NestedOuter)),
+                new BinaryTypeConfiguration(typeof(NestedInner)),
+                new BinaryTypeConfiguration(typeof(MigrationOuter)),
+                new BinaryTypeConfiguration(typeof(MigrationInner)),
+                new BinaryTypeConfiguration(typeof(InversionOuter)),
+                new BinaryTypeConfiguration(typeof(InversionInner)),
+                new BinaryTypeConfiguration(typeof(CompositeOuter)),
+                new BinaryTypeConfiguration(typeof(CompositeInner)),
+                new BinaryTypeConfiguration(typeof(CompositeArray)),
+                new BinaryTypeConfiguration(typeof(CompositeContainer)),
+                new BinaryTypeConfiguration(typeof(ToBinary)),
+                new BinaryTypeConfiguration(typeof(Remove)),
+                new BinaryTypeConfiguration(typeof(RemoveInner)),
+                new BinaryTypeConfiguration(typeof(BuilderInBuilderOuter)),
+                new BinaryTypeConfiguration(typeof(BuilderInBuilderInner)),
+                new BinaryTypeConfiguration(typeof(BuilderCollection)),
+                new BinaryTypeConfiguration(typeof(BuilderCollectionItem)),
+                new BinaryTypeConfiguration(typeof(DecimalHolder)),
+                new BinaryTypeConfiguration(TypeEmpty),
+                new BinaryTypeConfiguration(typeof(TestEnumRegistered)),
+                new BinaryTypeConfiguration(typeof(NameMapperTestType))
+            };
+        }
+
+        /// <summary>
         /// Gets the compact footer setting.
         /// </summary>
         protected virtual bool GetCompactFooter()
@@ -213,7 +221,7 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             // 2. Special types.
             Assert.AreEqual("a", api.ToBinary<string>("a"));
-            Assert.AreEqual(date, api.ToBinary<DateTime>(date));
+            Assert.AreEqual(date, api.ToBinary<IBinaryObject>(date).Deserialize<DateTime>());
             Assert.AreEqual(guid, api.ToBinary<Guid>(guid));
             Assert.AreEqual(TestEnumRegistered.One, api.ToBinary<IBinaryObject>(TestEnumRegistered.One)
                 .Deserialize<TestEnumRegistered>());
@@ -231,7 +239,8 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(new[] { 'a' }, api.ToBinary<char[]>(new[] { 'a' }));
 
             Assert.AreEqual(new[] { "a" }, api.ToBinary<string[]>(new[] { "a" }));
-            Assert.AreEqual(new[] { date }, api.ToBinary<DateTime[]>(new[] { date }));
+            Assert.AreEqual(new[] {date}, api.ToBinary<IBinaryObject[]>(new[] {date})
+                .Select(x => x.Deserialize<DateTime>()));
             Assert.AreEqual(new[] { guid }, api.ToBinary<Guid[]>(new[] { guid }));
             Assert.AreEqual(new[] { TestEnumRegistered.One},
                 api.ToBinary<IBinaryObject[]>(new[] { TestEnumRegistered.One})
@@ -619,6 +628,11 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             CheckPrimitiveFields1(binObj);
 
+            // Rebuild unchanged.
+            binObj = binObj.ToBuilder().Build();
+
+            CheckPrimitiveFields1(binObj);
+
             // Specific setter methods.
             var binObj2 = _grid.GetBinary().GetBuilder(typeof(Primitives))
                 .SetByteField("fByte", 1)
@@ -766,6 +780,11 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             CheckPrimitiveArrayFields1(binObj);
 
+            // Rebuild unchanged.
+            binObj = binObj.ToBuilder().Build();
+
+            CheckPrimitiveArrayFields1(binObj);
+
             // Specific setters.
             var binObj2 = _grid.GetBinary().GetBuilder(typeof(PrimitiveArrays))
                 .SetByteArrayField("fByte", new byte[] {1})
@@ -814,7 +833,7 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .Build();
 
             CheckPrimitiveArrayFields2(binObj);
-            
+
             // Check equality.
             Assert.AreEqual(binObj, binObj2);
             Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
@@ -918,6 +937,11 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             CheckStringDateGuidEnum1(binObj, nDate, nGuid);
 
+            // Rebuild with no changes.
+            binObj = binObj.ToBuilder().Build();
+
+            CheckStringDateGuidEnum1(binObj, nDate, nGuid);
+
             // Specific setters.
             var binObj2 = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
                 .SetStringField("fStr", "str")
@@ -1001,12 +1025,13 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(BinaryTypeNames.TypeNameArrayEnum, meta.GetFieldTypeName("fEnumArr"));
 
             Assert.AreEqual("str", binObj.GetField<string>("fStr"));
-            Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNDate"));
+            Assert.AreEqual(nDate, binObj.GetField<IBinaryObject>("fNDate").Deserialize<DateTime?>());
             Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNTimestamp"));
             Assert.AreEqual(nGuid, binObj.GetField<Guid?>("fNGuid"));
             Assert.AreEqual(TestEnum.One, binObj.GetField<IBinaryObject>("fEnum").Deserialize<TestEnum>());
             Assert.AreEqual(new[] {"str"}, binObj.GetField<string[]>("fStrArr"));
-            Assert.AreEqual(new[] {nDate}, binObj.GetField<DateTime?[]>("fDateArr"));
+            Assert.AreEqual(new[] {nDate}, binObj.GetField<IBinaryObject[]>("fDateArr")
+                .Select(x => x.Deserialize<DateTime?>()));
             Assert.AreEqual(new[] {nDate}, binObj.GetField<DateTime?[]>("fTimestampArr"));
             Assert.AreEqual(new[] {nGuid}, binObj.GetField<Guid?[]>("fGuidArr"));
             Assert.AreEqual(new[] {TestEnum.One},
@@ -1028,12 +1053,13 @@ namespace Apache.Ignite.Core.Tests.Binary
             var builder = _grid.GetBinary().GetBuilder(binObj);
 
             Assert.AreEqual("str", builder.GetField<string>("fStr"));
-            Assert.AreEqual(nDate, builder.GetField<DateTime?>("fNDate"));
+            Assert.AreEqual(nDate, builder.GetField<IBinaryObjectBuilder>("fNDate").Build().Deserialize<DateTime?>());
             Assert.AreEqual(nDate, builder.GetField<DateTime?>("fNTimestamp"));
             Assert.AreEqual(nGuid, builder.GetField<Guid?>("fNGuid"));
             Assert.AreEqual(TestEnum.One, builder.GetField<IBinaryObject>("fEnum").Deserialize<TestEnum>());
             Assert.AreEqual(new[] {"str"}, builder.GetField<string[]>("fStrArr"));
-            Assert.AreEqual(new[] {nDate}, builder.GetField<DateTime?[]>("fDateArr"));
+            Assert.AreEqual(new[] {nDate}, builder.GetField<IBinaryObjectBuilder[]>("fDateArr")
+                .Select(x => x.Build().Deserialize<DateTime?>()));
             Assert.AreEqual(new[] {nDate}, builder.GetField<DateTime?[]>("fTimestampArr"));
             Assert.AreEqual(new[] {nGuid}, builder.GetField<Guid?[]>("fGuidArr"));
             Assert.AreEqual(new[] {TestEnum.One},
@@ -1043,12 +1069,13 @@ namespace Apache.Ignite.Core.Tests.Binary
             binObj = builder.Build();
 
             Assert.AreEqual("str", binObj.GetField<string>("fStr"));
-            Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNDate"));
+            Assert.AreEqual(nDate, binObj.GetField<IBinaryObject>("fNDate").Deserialize<DateTime?>());
             Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNTimestamp"));
             Assert.AreEqual(nGuid, binObj.GetField<Guid?>("fNGuid"));
             Assert.AreEqual(TestEnum.One, binObj.GetField<IBinaryObject>("fEnum").Deserialize<TestEnum>());
             Assert.AreEqual(new[] {"str"}, binObj.GetField<string[]>("fStrArr"));
-            Assert.AreEqual(new[] {nDate}, binObj.GetField<DateTime?[]>("fDateArr"));
+            Assert.AreEqual(new[] {nDate}, binObj.GetField<IBinaryObject[]>("fDateArr")
+                .Select(x => x.Deserialize<DateTime?>()));
             Assert.AreEqual(new[] {nDate}, binObj.GetField<DateTime?[]>("fTimestampArr"));
             Assert.AreEqual(new[] {nGuid}, binObj.GetField<Guid?[]>("fGuidArr"));
             Assert.AreEqual(new[] { TestEnum.One },
@@ -1073,12 +1100,13 @@ namespace Apache.Ignite.Core.Tests.Binary
         private static void CheckStringDateGuidEnum2(IBinaryObject binObj, DateTime? nDate, Guid? nGuid)
         {
             Assert.AreEqual("str2", binObj.GetField<string>("fStr"));
-            Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNDate"));
+            Assert.AreEqual(nDate, binObj.GetField<IBinaryObject>("fNDate").Deserialize<DateTime?>());
             Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNTimestamp"));
             Assert.AreEqual(nGuid, binObj.GetField<Guid?>("fNGuid"));
             Assert.AreEqual(TestEnum.Two, binObj.GetField<IBinaryObject>("fEnum").Deserialize<TestEnum>());
             Assert.AreEqual(new[] { "str2" }, binObj.GetField<string[]>("fStrArr"));
-            Assert.AreEqual(new[] { nDate }, binObj.GetField<DateTime?[]>("fDateArr"));
+            Assert.AreEqual(new[] {nDate}, binObj.GetField<IBinaryObject[]>("fDateArr")
+                .Select(x => x.Deserialize<DateTime?>()));
             Assert.AreEqual(new[] { nDate }, binObj.GetField<DateTime?[]>("fTimestampArr"));
             Assert.AreEqual(new[] { nGuid }, binObj.GetField<Guid?[]>("fGuidArr"));
             Assert.AreEqual(new[] {TestEnum.Two},
@@ -1659,7 +1687,7 @@ namespace Apache.Ignite.Core.Tests.Binary
                 cache1[1] = new Primitives {FByte = 3};
                 var obj = cache2[1];
 
-                // Rebuild with no changes
+                // Rebuild with no changes.
                 cache2[2] = obj.ToBuilder().Build();
                 Assert.AreEqual(3, cache1[2].FByte);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
new file mode 100644
index 0000000..3f37833
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
@@ -0,0 +1,40 @@
+/*
+ * 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.Binary
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Binary builder self test with dynamic type registration.
+    /// </summary>
+    public class BinaryBuilderSelfTestDynamicRegistration : BinaryBuilderSelfTest
+    {
+        /** <inheritdoc /> */
+        protected override ICollection<BinaryTypeConfiguration> GetTypeConfigurations()
+        {
+            // The only type to be registered is TestEnumRegistered,
+            // because unregistered enums are handled differently.
+
+            return new []
+            {
+                new BinaryTypeConfiguration(typeof(TestEnumRegistered))
+            };
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryCompactFooterInteropTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryCompactFooterInteropTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryCompactFooterInteropTest.cs
index 830e7f4..76ef999 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryCompactFooterInteropTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryCompactFooterInteropTest.cs
@@ -30,7 +30,7 @@ namespace Apache.Ignite.Core.Tests.Binary
     public class BinaryCompactFooterInteropTest
     {
         /** */
-        private const string PlatformSqlQueryTask = "org.apache.ignite.platform.PlatformSqlQueryTask";
+        public const string PlatformSqlQueryTask = "org.apache.ignite.platform.PlatformSqlQueryTask";
 
         /** */
         private IIgnite _grid;

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
new file mode 100644
index 0000000..10e6e0b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
@@ -0,0 +1,441 @@
+\ufeff/*
+ * 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.
+ */
+
+// ReSharper disable UnusedAutoPropertyAccessor.Local
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Store;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Compute;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Common;
+    using Apache.Ignite.Core.Tests.Compute;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests the dynamic type registration.
+    /// </summary>
+    public class BinaryDynamicRegistrationTest
+    {
+        /// <summary>
+        /// Executes before each test.
+        /// </summary>
+        [SetUp]
+        public void SetUp()
+        {
+            ClearMarshallerWorkDir();
+        }
+
+        /// <summary>
+        /// Tests the failed registration.
+        /// </summary>
+        [Test]
+        public void TestFailedRegistration()
+        {
+            TestFailedRegistration<Foo>(false, false);
+            TestFailedRegistration<Bin>(true, false);
+            TestFailedRegistration<BinRaw>(true, true);
+        }
+
+        /// <summary>
+        /// Tests the failed registration, when we write type name after the header.
+        /// </summary>
+        private static void TestFailedRegistration<T>(bool rawStr, bool rawInt) where T : ITest, new()
+        {
+            // Disable compact footers for local mode
+            var cfg = new BinaryConfiguration {CompactFooter = false};
+
+            // Test in local mode so that MarshallerContext can't propagate type registration.
+            var bytes = new Marshaller(cfg).Marshal(new T {Int = 1, Str = "2"});
+
+            var res = new Marshaller(cfg).Unmarshal<T>(bytes);
+
+            Assert.AreEqual(1, res.Int);
+            Assert.AreEqual("2", res.Str);
+
+            // Check binary mode
+            var bin = new Marshaller(cfg).Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
+
+            if (!rawStr)
+                Assert.AreEqual("2", bin.GetField<string>("Str"));
+
+            if (!rawInt)
+                Assert.AreEqual(1, bin.GetField<int>("Int"));
+
+            res = bin.Deserialize<T>();
+
+            Assert.AreEqual(1, res.Int);
+            Assert.AreEqual("2", res.Str);
+        }
+
+        /// <summary>
+        /// Tests the store with node restart to make sure type names are persisted to disk properly.
+        /// </summary>
+        [Test]
+        public void TestStore()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                // Disable compact footers to test grid restart with persistent store
+                // (Because store operates on raw binary objects).
+                BinaryConfiguration = new BinaryConfiguration {CompactFooter = false},
+                CacheConfiguration = new[]
+                {
+                    new CacheConfiguration
+                    {
+                        CacheStoreFactory = new StoreFactory(),
+                        ReadThrough = true,
+                        WriteThrough = true
+                    }
+                }
+            };
+
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                // Put through dynamically started cache
+                var dynCache = ignite.CreateCache<int, Foo>(new CacheConfiguration("dynCache")
+                {
+                    CacheStoreFactory = new StoreFactory(),
+                    ReadThrough = true,
+                    WriteThrough = true
+                });
+                dynCache[2] = new Foo { Str = "test2", Int = 3 };
+
+                // Start another server node so that store is initialized there
+                using (var ignite2 = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
+                {
+                    IgniteInstanceName = "grid2"
+                }))
+                {
+                    var dynCache2 = ignite2.GetCache<int, Foo>(dynCache.Name);
+
+                    Assert.AreEqual("test2", dynCache2[2].Str);
+                    Assert.AreEqual(3, dynCache2[2].Int);
+                }
+            }
+
+            using (var ignite = Ignition.Start(cfg))
+            {
+                // Put through statically started cache
+                var staticCache = ignite.GetCache<int, Foo>(null);
+                staticCache[1] = new Foo {Str = "test", Int = 2};
+            }
+
+            using (var ignite = Ignition.Start(cfg))
+            {
+                var foo = ignite.GetCache<int, Foo>(null)[1];
+                var foo2 = ignite.GetCache<int, Foo>(null)[2];
+
+                Assert.AreEqual("test", foo.Str);
+                Assert.AreEqual(2, foo.Int);
+
+                Assert.AreEqual("test2", foo2.Str);
+                Assert.AreEqual(3, foo2.Int);
+
+                // Client node
+                using (var igniteClient = Ignition.Start(new IgniteConfiguration(cfg)
+                {
+                    ClientMode = true,
+                    IgniteInstanceName = "grid2"
+                }))
+                {
+                    var fooClient = igniteClient.GetCache<int, Foo>(null)[1];
+                    var fooClient2 = igniteClient.GetCache<int, Foo>(null)[2];
+
+                    Assert.AreEqual("test", fooClient.Str);
+                    Assert.AreEqual(2, fooClient.Int);
+
+                    Assert.AreEqual("test2", fooClient2.Str);
+                    Assert.AreEqual(3, fooClient2.Int);
+                }
+            }
+
+            // Delete directory and check that store no longer works
+            ClearMarshallerWorkDir();
+
+            using (var ignite = Ignition.Start(cfg))
+            {
+                var ex = Assert.Throws<BinaryObjectException>(() => ignite.GetCache<int, Foo>(null).Get(1));
+
+                Assert.IsTrue(ex.Message.Contains("Unknown pair"));
+            }
+        }
+
+        /// <summary>
+        /// Tests the store factory property propagation.
+        /// </summary>
+        [Test]
+        public void TestStoreFactory()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                CacheConfiguration = new[]
+                {
+                    new CacheConfiguration
+                    {
+                        CacheStoreFactory = new StoreFactory {StringProp = "test", IntProp = 9},
+                        ReadThrough = true,
+                        WriteThrough = true
+                    }
+                }
+            };
+
+            using (Ignition.Start(cfg))
+            {
+                var storeFactory = StoreFactory.LastInstance;
+
+                Assert.AreEqual("test", storeFactory.StringProp);
+                Assert.AreEqual(9, storeFactory.IntProp);
+            }
+        }
+
+        /// <summary>
+        /// Tests the single grid scenario.
+        /// </summary>
+        [Test]
+        public void TestSingleGrid()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                Test(ignite, ignite);
+            }
+        }
+
+        /// <summary>
+        /// Tests the two grid scenario.
+        /// </summary>
+        [Test]
+        public void TestTwoGrids([Values(false, true)] bool clientMode)
+        {
+            using (var ignite1 = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                using (var ignite2 = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
+                {
+                    IgniteInstanceName = "grid2",
+                    ClientMode = clientMode
+                }))
+                {
+                    Test(ignite1, ignite2);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Tests interop scenario: Java and .NET exchange an object with the same type id, 
+        /// but marshaller cache contains different entries for different platforms for the same id.
+        /// </summary>
+        [Test]
+        public void TestJavaInterop()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var cacheCfg = new CacheConfiguration(null, new QueryEntity(typeof(PlatformComputeBinarizable))
+                {
+                    Fields = new[] {new QueryField("Field", typeof(int))}
+                });
+
+                var cache = ignite.CreateCache<int, object>(cacheCfg);
+
+                // Force dynamic registration for .NET
+                cache.Put(1, new PlatformComputeBinarizable {Field = 7});
+
+                // Run Java code that will also perform dynamic registration
+                var fromJava = ignite.GetCompute().ExecuteJavaTask<PlatformComputeBinarizable>(ComputeApiTest.EchoTask,
+                    ComputeApiTest.EchoTypeBinarizable);
+
+                // Check that objects are compatible
+                Assert.AreEqual(1, fromJava.Field);
+
+                // Check that Java can read what .NET has put
+                var qryRes = ignite.GetCompute().ExecuteJavaTask<IList>(
+                    BinaryCompactFooterInteropTest.PlatformSqlQueryTask, "Field < 10");
+
+                Assert.AreEqual(7, qryRes.OfType<PlatformComputeBinarizable>().Single().Field);
+            }
+        }
+
+        /// <summary>
+        /// Tests the type registration.
+        /// </summary>
+        private static void Test(IIgnite ignite1, IIgnite ignite2)
+        {
+            const string cacheName = "cache";
+
+            // Put on one grid.
+            var cache1 = ignite1.CreateCache<int, object>(cacheName);
+            cache1[1] = new Foo {Int = 1, Str = "1"};
+            cache1[2] = ignite1.GetBinary().GetBuilder(typeof (Bar)).SetField("Int", 5).SetField("Str", "s").Build();
+
+            // Get on another grid.
+            var cache2 = ignite2.GetCache<int, Foo>(cacheName);
+            var foo = cache2[1];
+
+            Assert.AreEqual(1, foo.Int);
+            Assert.AreEqual("1", foo.Str);
+
+            var bar = cache2.WithKeepBinary<int, IBinaryObject>()[2];
+
+            Assert.AreEqual("s", bar.GetField<string>("Str"));
+            Assert.AreEqual(5, bar.GetField<int>("Int"));
+
+            var bar0 = bar.Deserialize<Bar>();
+
+            Assert.AreEqual("s", bar0.Str);
+            Assert.AreEqual(5, bar0.Int);
+
+            // Test compute.
+            var serverNodeCount = ignite1.GetCluster().ForServers().GetNodes().Count;
+
+            var res = ignite1.GetCompute().Broadcast(new CompFn<DateTime>(() => DateTime.Now));
+            Assert.AreEqual(serverNodeCount, res.Count);
+
+            // Variable capture.
+            var res2 = ignite1.GetCompute().Broadcast(new CompFn<string>(() => bar0.Str));
+            Assert.AreEqual(Enumerable.Repeat(bar0.Str, serverNodeCount), res2);
+        }
+
+        /// <summary>
+        /// Clears the marshaller work dir.
+        /// </summary>
+        private static void ClearMarshallerWorkDir()
+        {
+            // Delete all *.classname files within IGNITE_HOME
+            var home = IgniteHome.Resolve(null);
+
+            var files = Directory.GetFiles(home, "*.classname*", SearchOption.AllDirectories);
+
+            files.ToList().ForEach(File.Delete);
+        }
+
+        private interface ITest
+        {
+            int Int { get; set; }
+            string Str { get; set; }
+        }
+
+        private class Foo : ITest
+        {
+            public int Int { get; set; }
+            public string Str { get; set; }
+        }
+
+        private class Bar : ITest
+        {
+            public int Int { get; set; }
+            public string Str { get; set; }
+        }
+
+        private class Bin : IBinarizable, ITest
+        {
+            public int Int { get; set; }
+            public string Str { get; set; }
+
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                writer.WriteInt("Int", Int);
+                writer.GetRawWriter().WriteString(Str);
+            }
+
+            public void ReadBinary(IBinaryReader reader)
+            {
+                Int = reader.ReadInt("Int");
+                Str = reader.GetRawReader().ReadString();
+            }
+        }
+
+        private class BinRaw : IBinarizable, ITest
+        {
+            public int Int { get; set; }
+            public string Str { get; set; }
+
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                var w = writer.GetRawWriter();
+
+                w.WriteInt(Int);
+                w.WriteString(Str);
+            }
+
+            public void ReadBinary(IBinaryReader reader)
+            {
+                var r = reader.GetRawReader();
+
+                Int = r.ReadInt();
+                Str = r.ReadString();
+            }
+        }
+
+        [Serializable]
+        private class StoreFactory : IFactory<ICacheStore>
+        {
+            public string StringProp { get; set; }
+
+            public int IntProp { get; set; }
+
+            public static StoreFactory LastInstance { get; set; }
+
+            public ICacheStore CreateInstance()
+            {
+                LastInstance = this;
+                return new CacheStore();
+            }
+        }
+
+        private class CacheStore : CacheStoreAdapter<object, object>
+        {
+            private static readonly Dictionary<object, object>  Dict = new Dictionary<object, object>();
+
+            public override object Load(object key)
+            {
+                object res;
+                return Dict.TryGetValue(key, out res) ? res : null;
+            }
+
+            public override void Write(object key, object val)
+            {
+                Dict[key] = val;
+            }
+
+            public override void Delete(object key)
+            {
+                Dict.Remove(key);
+            }
+        }
+
+        private class CompFn<T> : IComputeFunc<T>
+        {
+            private readonly Func<T> _func;
+
+            public CompFn(Func<T> func)
+            {
+                _func = func;
+            }
+
+            public T Invoke()
+            {
+                return _func();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
index 70226e6..eb2751e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
@@ -63,16 +63,16 @@ namespace Apache.Ignite.Core.Tests.Binary
         [TestFixtureSetUp]
         public void BeforeTest()
         {
-            _marsh = new Marshaller(GetBinaryConfiguration());
+            _marsh = new Marshaller(new BinaryConfiguration{CompactFooter = GetCompactFooter()});
         }
 
         /// <summary>
         /// Gets the binary configuration.
         /// </summary>
         /// <returns></returns>
-        protected virtual BinaryConfiguration GetBinaryConfiguration()
+        protected virtual bool GetCompactFooter()
         {
-            return new BinaryConfiguration { CompactFooter = true };
+            return true;
         }
         
         /**
@@ -691,7 +691,8 @@ namespace Apache.Ignite.Core.Tests.Binary
                 {
                     new BinaryTypeConfiguration(typeof (PrimitiveFieldType)),
                     new BinaryTypeConfiguration(typeof (GenericCollectionsType<PrimitiveFieldType, SerializableObject>))
-                }
+                },
+                CompactFooter = GetCompactFooter()
             });
 
             var obj = new GenericCollectionsType<PrimitiveFieldType, SerializableObject>
@@ -721,6 +722,52 @@ namespace Apache.Ignite.Core.Tests.Binary
             CollectionAssert.AreEquivalent(obj.Objects, result.Objects);
         }
 
+        /// <summary>
+        /// Tests the circular reference handling with List.
+        /// </summary>
+        [Test]
+        public void TestListCircularReference()
+        {
+            var list1 = new List<object> {1};
+            var list2 = new List<object> {2};
+
+            list1.Add(list2);
+            list2.Add(list1);
+
+            var data = _marsh.Marshal(list1);
+
+            var resList1 = _marsh.Unmarshal<List<object>>(data);
+            Assert.AreEqual(1, resList1[0]);
+
+            var resList2 = (List<object>) resList1[1];
+            Assert.AreEqual(2, resList2[0]);
+            Assert.AreEqual(resList1, resList2[1]);
+        }
+
+        /// <summary>
+        /// Tests the circular reference handling with Dictionary.
+        /// This test checks proper handle support in combination with OnDeserialization callback,
+        /// which has to be called after entire graph is deserialized.
+        /// </summary>
+        [Test]
+        public void TestDictionaryCircularReference()
+        {
+            var dict1 = new Dictionary<object, object> {{0, 1}};
+            var dict2 = new Dictionary<object, object> {{0, 2}};
+
+            dict1[1] = dict2;
+            dict2[1] = dict1;
+
+            var data = _marsh.Marshal(dict1);
+
+            var resDict1 = _marsh.Unmarshal<Dictionary<object, object>>(data);
+            Assert.AreEqual(1, resDict1[0]);
+
+            var resDict2 = (Dictionary<object, object>) resDict1[1];
+            Assert.AreEqual(2, resDict2[0]);
+            Assert.AreEqual(resDict1, resDict2[1]);
+        }
+
         /**
          * <summary>Check property read.</summary>
          */
@@ -778,7 +825,8 @@ namespace Apache.Ignite.Core.Tests.Binary
                     {
                         Serializer = serializer
                     }
-                }
+                },
+                CompactFooter = GetCompactFooter()
             });
 
             // Use utc date fields because reflective serializer writes [QuerySqlField] fields as timestamp
@@ -791,20 +839,17 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckPrimitiveFields(marsh, obj);
         }
 
-        /**
-         * <summary>Check write of primitive fields through binary interface.</summary>
-         */
+        /// <summary>
+        /// Check write of primitive fields through binary interface.
+        /// </summary>
         [Test]
         public void TestPrimitiveFieldsBinary()
         {
-            ICollection<BinaryTypeConfiguration> typeCfgs = 
-                new List<BinaryTypeConfiguration>();
-
-            typeCfgs.Add(new BinaryTypeConfiguration(typeof(PrimitiveFieldBinaryType)));
-
-            BinaryConfiguration cfg = new BinaryConfiguration();
-
-            cfg.TypeConfigurations = typeCfgs;
+            var cfg = new BinaryConfiguration
+            {
+                TypeConfigurations = new[] { new BinaryTypeConfiguration(typeof(PrimitiveFieldBinaryType)) },
+                CompactFooter = GetCompactFooter()
+            };
 
             Marshaller marsh = new Marshaller(cfg);
 
@@ -813,44 +858,41 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckPrimitiveFields(marsh, obj);
         }
 
-        /**
-         * <summary>Check write of primitive fields through binary interface.</summary>
-         */
+        /// <summary>
+        /// Check write of primitive fields through binary interface.
+        /// </summary>
         [Test]
         public void TestPrimitiveFieldsRawBinary()
         {
-            ICollection<BinaryTypeConfiguration> typeCfgs = 
-                new List<BinaryTypeConfiguration>();
-
-            typeCfgs.Add(new BinaryTypeConfiguration(typeof(PrimitiveFieldRawBinaryType)));
-
-            BinaryConfiguration cfg = new BinaryConfiguration();
-
-            cfg.TypeConfigurations = typeCfgs;
-
-            Marshaller marsh = new Marshaller(cfg);
+            var marsh = new Marshaller(new BinaryConfiguration
+            {
+                TypeConfigurations = new[] { new BinaryTypeConfiguration(typeof(PrimitiveFieldRawBinaryType)) },
+                CompactFooter = GetCompactFooter()
+            });
 
-            PrimitiveFieldRawBinaryType obj = new PrimitiveFieldRawBinaryType();
+            var obj = new PrimitiveFieldRawBinaryType();
 
             CheckPrimitiveFields(marsh, obj);
         }
 
-        /**
-         * <summary>Check write of primitive fields through binary interface.</summary>
-         */
+        /// <summary>
+        /// Check write of primitive fields through binary interface.
+        /// </summary>
         [Test]
         public void TestPrimitiveFieldsSerializer()
         {
-            var typeCfgs = new List<BinaryTypeConfiguration>
+            var cfg = new BinaryConfiguration
             {
-                new BinaryTypeConfiguration(typeof (PrimitiveFieldType))
+                TypeConfigurations = new[]
                 {
-                    Serializer = new PrimitiveFieldsSerializer()
-                }
+                    new BinaryTypeConfiguration(typeof(PrimitiveFieldType))
+                    {
+                        Serializer = new PrimitiveFieldsSerializer(),
+                    }
+                },
+                CompactFooter = GetCompactFooter()
             };
 
-            BinaryConfiguration cfg = new BinaryConfiguration {TypeConfigurations = typeCfgs};
-
             Marshaller marsh = new Marshaller(cfg);
 
             PrimitiveFieldType obj = new PrimitiveFieldType();
@@ -909,31 +951,25 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(obj2.RawValArr, portObj.Deserialize<DecimalMarshalAware>().RawValArr);
         }
 
-        /**
-         * <summary>Check write of primitive fields through raw serializer.</summary>
-         */
+        /// <summary>
+        /// Check write of primitive fields through raw serializer.
+        /// </summary>
         [Test]
         public void TestPrimitiveFieldsRawSerializer()
         {
-            ICollection<BinaryTypeConfiguration> typeCfgs = 
-                new List<BinaryTypeConfiguration>();
-
-            BinaryTypeConfiguration typeCfg =
-                new BinaryTypeConfiguration(typeof(PrimitiveFieldType));
-
-            typeCfg.Serializer = new PrimitiveFieldsRawSerializer();
-
-            typeCfgs.Add(typeCfg);
-
-            BinaryConfiguration cfg = new BinaryConfiguration();
-
-            cfg.TypeConfigurations = typeCfgs;
-
-            Marshaller marsh = new Marshaller(cfg);
-
-            PrimitiveFieldType obj = new PrimitiveFieldType();
+            Marshaller marsh = new Marshaller(new BinaryConfiguration
+            {
+                TypeConfigurations = new[]
+                {
+                    new BinaryTypeConfiguration(typeof(PrimitiveFieldType))
+                    {
+                        Serializer = new PrimitiveFieldsRawSerializer()
+                    }
+                },
+                CompactFooter = GetCompactFooter()
+            });
 
-            CheckPrimitiveFields(marsh, obj);
+            CheckPrimitiveFields(marsh, new PrimitiveFieldType());
         }
 
         private void CheckPrimitiveFields(Marshaller marsh, PrimitiveFieldType obj)
@@ -941,7 +977,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckPrimitiveFieldsSerialization(marsh, obj);
         }
 
-        private void CheckPrimitiveFieldsSerialization(Marshaller marsh, PrimitiveFieldType obj)
+        private static void CheckPrimitiveFieldsSerialization(Marshaller marsh, PrimitiveFieldType obj)
         {
             byte[] bytes = marsh.Marshal(obj);
 
@@ -1029,7 +1065,8 @@ namespace Apache.Ignite.Core.Tests.Binary
                     {
                         Serializer = new BinaryReflectiveSerializer {RawMode = raw}
                     }
-                }
+                },
+                CompactFooter = GetCompactFooter()
             });
             
             var obj = new CollectionsType
@@ -1239,9 +1276,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             {
                 var reader = new BinaryReader(marsh, new BinaryHeapStream(bytes), BinaryMode.ForceBinary, null);
 
-                reader.DetachNext();
-
-                outerObj = reader.Deserialize<IBinaryObject>();
+                outerObj = reader.DetachNext().Deserialize<IBinaryObject>();
             }
             else
                 outerObj = marsh.Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
@@ -1272,7 +1307,8 @@ namespace Apache.Ignite.Core.Tests.Binary
                 TypeConfigurations = new[]
                 {
                     new BinaryTypeConfiguration(typeof (HandleCollection))
-                }
+                },
+                CompactFooter = GetCompactFooter()
             });
 
             // Collection in collection dependency loop
@@ -1441,8 +1477,10 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             Assert.AreEqual(guidArr, portObj.GetField<Guid[]>("guidArr"));
             Assert.AreEqual(nGuidArr, portObj.GetField<Guid?[]>("nGuidArr"));
-            Assert.AreEqual(dateArr, portObj.GetField<DateTime[]>("dateArr"));
-            Assert.AreEqual(nDateArr, portObj.GetField<DateTime?[]>("nDateArr"));
+            Assert.AreEqual(dateArr, portObj.GetField<IBinaryObject[]>("dateArr")
+                .Select(x => x.Deserialize<DateTime>()));
+            Assert.AreEqual(nDateArr, portObj.GetField<IBinaryObject[]>("nDateArr")
+                .Select(x => x.Deserialize<DateTime?>()));
 
             obj1 = portObj.Deserialize<SpecialArray>();
 
@@ -1452,12 +1490,13 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(nDateArr, obj1.NDateArr);
 
             // Use special with IGridbinaryMarshalAware.
-            SpecialArrayMarshalAware obj2 = new SpecialArrayMarshalAware();
-
-            obj2.GuidArr = guidArr;
-            obj2.NGuidArr = nGuidArr;
-            obj2.DateArr = dateArr;
-            obj2.NDateArr = nDateArr;
+            SpecialArrayMarshalAware obj2 = new SpecialArrayMarshalAware
+            {
+                GuidArr = guidArr,
+                NGuidArr = nGuidArr,
+                DateArr = dateArr,
+                NDateArr = nDateArr
+            };
 
             bytes = marsh.Marshal(obj2);
 
@@ -1465,8 +1504,8 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             Assert.AreEqual(guidArr, portObj.GetField<Guid[]>("a"));
             Assert.AreEqual(nGuidArr, portObj.GetField<Guid?[]>("b"));
-            Assert.AreEqual(dateArr, portObj.GetField<DateTime[]>("c"));
-            Assert.AreEqual(nDateArr, portObj.GetField<DateTime?[]>("d"));
+            Assert.AreEqual(dateArr, portObj.GetField<IBinaryObject[]>("c").Select(x => x.Deserialize<DateTime>()));
+            Assert.AreEqual(nDateArr, portObj.GetField<IBinaryObject[]>("d").Select(x => x.Deserialize<DateTime?>()));
 
             obj2 = portObj.Deserialize<SpecialArrayMarshalAware>();
 
@@ -1523,7 +1562,7 @@ namespace Apache.Ignite.Core.Tests.Binary
         [Test]
         public void TestCompactFooterSetting()
         {
-            Assert.AreEqual(GetBinaryConfiguration().CompactFooter, _marsh.CompactFooter);
+            Assert.AreEqual(GetCompactFooter(), _marsh.CompactFooter);
         }
 
         private static void CheckKeepSerialized(BinaryConfiguration cfg, bool expKeep)
@@ -1842,8 +1881,8 @@ namespace Apache.Ignite.Core.Tests.Binary
                 PString = "abc";
                 PGuid = Guid.NewGuid();
                 PnGuid = Guid.NewGuid();
-                PDate = DateTime.Now;
-                PnDate = DateTime.Now;
+                PDate = DateTime.UtcNow;
+                PnDate = DateTime.UtcNow;
                 IgniteGuid = new IgniteGuid(Guid.NewGuid(), 123);
             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTestFullFooter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTestFullFooter.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTestFullFooter.cs
index 06e43e1..72228cf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTestFullFooter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTestFullFooter.cs
@@ -17,7 +17,6 @@
 
 namespace Apache.Ignite.Core.Tests.Binary
 {
-    using Apache.Ignite.Core.Binary;
     using NUnit.Framework;
 
     /// <summary>
@@ -27,9 +26,9 @@ namespace Apache.Ignite.Core.Tests.Binary
     public class BinarySelfTestFullFooter : BinarySelfTest
     {
         /** <inheritdoc /> */
-        protected override BinaryConfiguration GetBinaryConfiguration()
+        protected override bool GetCompactFooter()
         {
-            return new BinaryConfiguration {CompactFooter = false};
+            return false;
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
new file mode 100644
index 0000000..9af5c35
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
@@ -0,0 +1,182 @@
+\ufeff/*
+ * 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.Binary
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Linq;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests binary type interoperability between .NET and Java code.
+    /// </summary>
+    public class JavaBinaryInteropTest
+    {
+        /// <summary>
+        /// Tests that all kinds of values from .NET can be handled properly on Java side.
+        /// </summary>
+        [Test]
+        public void TestValueRoundtrip()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                ignite.CreateCache<int, object>((string) null);
+
+                // Basic types.
+                // Types which map directly to Java are returned properly when retrieved as object.
+                // Non-directly mapped types are returned as their counterpart.
+                CheckValueCaching((char) 128);
+                CheckValueCaching((byte) 255);
+                CheckValueCaching((sbyte) -10, false);
+                CheckValueCaching((short) -32000);
+                CheckValueCaching((ushort) 65350, false);
+                CheckValueCaching(int.MinValue);
+                CheckValueCaching(uint.MaxValue, false);
+                CheckValueCaching(long.MinValue);
+                CheckValueCaching(ulong.MaxValue, false);
+
+                CheckValueCaching((float) 1.1);
+                CheckValueCaching(2.2);
+
+                CheckValueCaching((decimal) 3.3, asArray: false);
+                CheckValueCaching(Guid.NewGuid(), asArray: false);
+                CheckValueCaching(DateTime.Now, asArray: false);
+
+                CheckValueCaching("foobar");
+
+                // Special arrays.
+                CheckValueCaching(new[] {Guid.Empty, Guid.NewGuid()}, false);
+                CheckValueCaching(new Guid?[] {Guid.Empty, Guid.NewGuid()});
+
+                CheckValueCaching(new[] {1.2m, -3.4m}, false);
+                CheckValueCaching(new decimal?[] {1.2m, -3.4m});
+
+                CheckValueCaching(new[] {DateTime.Now}, false);
+
+                // Custom types.
+                CheckValueCaching(new Foo {X = 10}, asArray: false);
+                CheckValueCaching(new Bar {X = 20}, asArray: false);
+
+                // Collections.
+                CheckValueCaching(new List<Foo>(GetFoo()));
+                CheckValueCaching(new List<Bar>(GetBar()));
+
+                CheckValueCaching(new HashSet<Foo>(GetFoo()));
+                CheckValueCaching(new HashSet<Bar>(GetBar()));
+
+                CheckValueCaching(GetFoo().ToDictionary(x => x.X, x => x));
+                CheckValueCaching(GetBar().ToDictionary(x => x.X, x => x));
+
+                // Custom type arrays.
+                // Array type is lost, because in binary mode on Java side we receive the value as Object[].
+                CheckValueCaching(new[] {new Foo {X = -1}, new Foo {X = 1}}, false);
+                CheckValueCaching(new[] {new Bar {X = -10}, new Bar {X = 10}}, false);
+            }
+        }
+
+        /// <summary>
+        /// Checks caching of a value with generic cache.
+        /// </summary>
+        private static void CheckValueCaching<T>(T val, bool asObject = true, bool asArray = true)
+        {
+            var cache = Ignition.GetIgnite(null).GetCache<int, T>(null);
+
+            cache[1] = val;
+            Assert.AreEqual(val, cache[1]);
+
+            if (asObject)
+            {
+                CheckValueCachingAsObject(val);
+            }
+
+            // Array of T
+            if (asArray && !(val is IEnumerable))
+            {
+                CheckValueCaching(new[] {val}, asObject, false);
+            }
+        }
+
+        /// <summary>
+        /// Checks caching of a value with object cache.
+        /// </summary>
+        private static void CheckValueCachingAsObject<T>(T val)
+        {
+            var cache = Ignition.GetIgnite(null).GetCache<int, object>(null);
+
+            cache[1] = val;
+            Assert.AreEqual(val, (T) cache[1]);
+        }
+
+        /// <summary>
+        /// Gets Foo collection.
+        /// </summary>
+        private static IEnumerable<Foo> GetFoo()
+        {
+            return Enumerable.Range(-50, 100).Select(x => new Foo {X = x});
+        }
+
+        /// <summary>
+        /// Gets Bar collection.
+        /// </summary>
+        private static IEnumerable<Bar> GetBar()
+        {
+            return Enumerable.Range(-50, 100).Select(x => new Bar {X = x});
+        }
+
+        /// <summary>
+        /// Test custom class.
+        /// </summary>
+        private class Foo
+        {
+            public int X { get; set; }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) return false;
+                if (ReferenceEquals(this, obj)) return true;
+                if (obj.GetType() != GetType()) return false;
+                return X == ((Foo) obj).X;
+            }
+
+            public override int GetHashCode()
+            {
+                return X;
+            }
+        }
+
+        /// <summary>
+        /// Test custom struct.
+        /// </summary>
+        private struct Bar
+        {
+            public int X { get; set; }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) return false;
+                return obj is Bar && X == ((Bar) obj).X;
+            }
+
+            public override int GetHashCode()
+            {
+                return X;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
new file mode 100644
index 0000000..c96d111
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
@@ -0,0 +1,228 @@
+/*
+ * 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.Binary.Serializable
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Reflection;
+    using System.Reflection.Emit;
+    using System.Runtime.Serialization;
+    using System.Xml;
+    using Apache.Ignite.Core.Cluster;
+    using Apache.Ignite.Core.Compute;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests additional [Serializable] scenarios.
+    /// </summary>
+    public class AdvancedSerializationTest
+    {
+        /// <summary>
+        /// Set up routine.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void SetUp()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+        }
+
+        /// <summary>
+        /// Tear down routine.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void TearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Test complex file serialization.
+        /// </summary>
+        [Test]
+        public void TestSerializableXmlDoc()
+        {
+            var grid = Ignition.GetIgnite(null);
+            var cache = grid.GetOrCreateCache<int, SerializableXmlDoc>("cache");
+
+            var doc = new SerializableXmlDoc();
+
+            doc.LoadXml("<document><test1>val</test1><test2 attr=\"x\" /></document>");
+
+            for (var i = 0; i < 50; i++)
+            {
+                // Test cache
+                cache.Put(i, doc);
+
+                var resultDoc = cache.Get(i);
+
+                Assert.AreEqual(doc.OuterXml, resultDoc.OuterXml);
+
+                // Test task with document arg
+                CheckTask(grid, doc);
+            }
+        }
+
+        /// <summary>
+        /// Checks task execution.
+        /// </summary>
+        /// <param name="grid">Grid.</param>
+        /// <param name="arg">Task arg.</param>
+        private static void CheckTask(IIgnite grid, object arg)
+        {
+            var jobResult = grid.GetCompute().Execute(new CombineStringsTask(), arg);
+
+            var nodeCount = grid.GetCluster().GetNodes().Count;
+
+            var expectedRes =
+                CombineStringsTask.CombineStrings(Enumerable.Range(0, nodeCount).Select(x => arg.ToString()));
+
+            Assert.AreEqual(expectedRes, jobResult.InnerXml);
+        }
+
+        /// <summary>
+        /// Tests custom serialization binder.
+        /// </summary>
+        [Test]
+        public void TestSerializationBinder()
+        {
+            const int count = 50;
+
+            var cache = Ignition.GetIgnite(null).GetOrCreateCache<int, object>("cache");
+
+            // Put multiple objects from multiple same-named assemblies to cache
+            for (var i = 0; i < count; i++)
+            {
+                dynamic val = Activator.CreateInstance(GenerateDynamicType());
+                
+                val.Id = i;
+                val.Name = "Name_" + i;
+
+                cache.Put(i, val);
+            }
+
+            // Verify correct deserialization
+            for (var i = 0; i < count; i++)
+            {
+                dynamic val = cache.Get(i);
+
+                Assert.AreEqual(val.Id, i);
+                Assert.AreEqual(val.Name, "Name_" + i);
+            }
+        }
+
+        /// <summary>
+        /// Generates a Type in runtime, puts it into a dynamic assembly.
+        /// </summary>
+        /// <returns></returns>
+        private static Type GenerateDynamicType()
+        {
+            var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
+                new AssemblyName("GridSerializationTestDynamicAssembly"), AssemblyBuilderAccess.Run);
+
+            var moduleBuilder = asmBuilder.DefineDynamicModule("GridSerializationTestDynamicModule");
+
+            var typeBuilder = moduleBuilder.DefineType("GridSerializationTestDynamicType",
+                TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Serializable);
+
+            typeBuilder.DefineField("Id", typeof (int), FieldAttributes.Public);
+            
+            typeBuilder.DefineField("Name", typeof (string), FieldAttributes.Public);
+
+            return typeBuilder.CreateType();
+        }
+    }
+
+    [Serializable]
+    [DataContract]
+    public sealed class SerializableXmlDoc : XmlDocument, ISerializable
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public SerializableXmlDoc()
+        {
+            // No-op
+        }
+
+        /// <summary>
+        /// Serialization ctor.
+        /// </summary>
+        private SerializableXmlDoc(SerializationInfo info, StreamingContext context)
+        {
+            LoadXml(info.GetString("xmlDocument"));
+        }
+
+        /** <inheritdoc /> */
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            info.AddValue("xmlDocument", OuterXml, typeof(string));
+        }
+    }
+
+    [Serializable]
+    public class CombineStringsTask : IComputeTask<object, string, SerializableXmlDoc>
+    {
+        public IDictionary<IComputeJob<string>, IClusterNode> Map(IList<IClusterNode> subgrid, object arg)
+        {
+            return subgrid.ToDictionary(x => (IComputeJob<string>) new ToStringJob {Arg = arg}, x => x);
+        }
+
+        public ComputeJobResultPolicy OnResult(IComputeJobResult<string> res, IList<IComputeJobResult<string>> rcvd)
+        {
+            return ComputeJobResultPolicy.Wait;
+        }
+
+        public SerializableXmlDoc Reduce(IList<IComputeJobResult<string>> results)
+        {
+            var result = new SerializableXmlDoc();
+
+            result.LoadXml(CombineStrings(results.Select(x => x.Data)));
+
+            return result;
+        }
+
+        public static string CombineStrings(IEnumerable<string> strings)
+        {
+            var text = string.Concat(strings.Select(x => string.Format("<val>{0}</val>", x)));
+
+            return string.Format("<document>{0}</document>", text);
+        }
+    }
+
+    [Serializable]
+    public class ToStringJob : IComputeJob<string>
+    {
+        /// <summary>
+        /// Job argument.
+        /// </summary>
+        public object Arg { get; set; }
+
+        /** <inheritdoc /> */
+        public string Execute()
+        {
+            return Arg.ToString();
+        }
+
+        /** <inheritdoc /> */
+        public void Cancel()
+        {
+            // No-op.
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
new file mode 100644
index 0000000..82deb3c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
@@ -0,0 +1,124 @@
+\ufeff/*
+ * 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.Binary.Serializable
+{
+    using System;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests basic ISerializable scenarios.
+    /// </summary>
+    public class BasicSerializableObjectsTest
+    {
+        /// <summary>
+        /// Tests the object with no fields.
+        /// </summary>
+        [Test]
+        public void TestEmptyObject()
+        {
+            var res = TestUtils.SerializeDeserialize(new EmptyObject());
+
+            Assert.IsNotNull(res);
+        }
+
+        /// <summary>
+        /// Tests the object with no fields.
+        /// </summary>
+        [Test]
+        public void TestEmptyObjectOnline()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var cache = ignite.CreateCache<int, EmptyObject>("c");
+
+                cache[1] = new EmptyObject();
+
+                var res = cache[1];
+
+                Assert.IsNotNull(res);
+            }
+        }
+
+        /// <summary>
+        /// Tests ISerializable without serialization ctor.
+        /// </summary>
+        [Test]
+        public void TestMissingCtor()
+        {
+            var ex = Assert.Throws<SerializationException>(() => TestUtils.SerializeDeserialize(new MissingCtor()));
+            Assert.AreEqual(string.Format("The constructor to deserialize an object of type '{0}' was not found.", 
+                typeof(MissingCtor)), ex.Message);
+        }
+
+        /// <summary>
+        /// Tests <see cref="Type"/> serialization.
+        /// </summary>
+        [Test]
+        public void TestTypes()
+        {
+            var type = GetType();
+
+            var res = TestUtils.SerializeDeserialize(type);
+
+            Assert.AreEqual(type, res);
+        }
+
+        /// <summary>
+        /// Missing serialization ctor.
+        /// </summary>
+        private class MissingCtor : ISerializable
+        {
+            /** <inheritdoc /> */
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                // No-op.
+            }
+        }
+
+        /// <summary>
+        /// Object with no fields.
+        /// </summary>
+        [Serializable]
+        private class EmptyObject : ISerializable
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see cref="EmptyObject"/> class.
+            /// </summary>
+            public EmptyObject()
+            {
+                // No-op.
+            }
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="EmptyObject"/> class.
+            /// </summary>
+            private EmptyObject(SerializationInfo info, StreamingContext context)
+            {
+                Assert.IsInstanceOf<IBinaryReader>(context.Context);
+            }
+
+            /** <inheritdoc /> */
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                Assert.IsInstanceOf<IBinaryWriter>(context.Context);
+            }
+        }
+    }
+}


[2/5] ignite git commit: IGNITE-2703 .NET: Dynamic type registration

Posted by pt...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamAdapter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamAdapter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamAdapter.cs
deleted file mode 100644
index b062689..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamAdapter.cs
+++ /dev/null
@@ -1,119 +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.
- */
-
-namespace Apache.Ignite.Core.Impl.Binary.IO
-{
-    using System;
-    using System.Diagnostics.CodeAnalysis;
-    using System.IO;
-
-    /// <summary>
-    /// Adapter providing .Net streaming functionality over the binary stream.
-    /// </summary>
-    internal class BinaryStreamAdapter : Stream
-    {
-        /// <summary>
-        /// 
-        /// </summary>
-        private readonly IBinaryStream _stream;
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="stream">Stream.</param>
-        public BinaryStreamAdapter(IBinaryStream stream)
-        {
-            _stream = stream;
-        }
-
-        /** <inheritDoc /> */
-        public override void Write(byte[] buffer, int offset, int count)
-        {
-            _stream.Write(buffer, offset, count);
-        }
-
-        /** <inheritDoc /> */
-        public override int Read(byte[] buffer, int offset, int count)
-        {
-            _stream.Read(buffer, offset, count);
-
-            return count;
-        }
-
-        /** <inheritDoc /> */
-        public override void Flush()
-        {
-            // No-op.
-        }
-
-        /** <inheritDoc /> */
-        public override bool CanRead
-        {
-            get { return true; }
-        }
-
-        /** <inheritDoc /> */
-        public override bool CanWrite
-        {
-            get { return true; }
-        }
-
-        /** <inheritDoc /> */
-        public override bool CanSeek
-        {
-            get { return false; }
-        }
-
-        /** <inheritDoc /> */
-        [ExcludeFromCodeCoverage]
-        public override long Seek(long offset, SeekOrigin origin)
-        {
-            throw new NotSupportedException("Stream is not seekable.");
-        }
-
-        /** <inheritDoc /> */
-        [ExcludeFromCodeCoverage]
-        public override long Position
-        {
-            get
-            {
-                throw new NotSupportedException("Stream is not seekable.");
-            }
-            set
-            {
-                throw new NotSupportedException("Stream is not seekable.");
-            }
-        }
-
-        /** <inheritDoc /> */
-        [ExcludeFromCodeCoverage]
-        public override long Length
-        {
-            get 
-            {
-                throw new NotSupportedException("Stream is not seekable.");
-            }
-        }
-
-        /** <inheritDoc /> */
-        [ExcludeFromCodeCoverage]
-        public override void SetLength(long value)
-        {
-            throw new NotSupportedException("Stream is not seekable.");
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index b929f3a..5effc5c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Linq;
+    using System.Runtime.Serialization;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache.Affinity;
     using Apache.Ignite.Core.Common;
@@ -33,6 +34,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using Apache.Ignite.Core.Impl.Compute.Closure;
     using Apache.Ignite.Core.Impl.Datastream;
     using Apache.Ignite.Core.Impl.Messaging;
+    using Apache.Ignite.Core.Log;
 
     /// <summary>
     /// Marshaller implementation.
@@ -43,37 +45,43 @@ namespace Apache.Ignite.Core.Impl.Binary
         private readonly BinaryConfiguration _cfg;
 
         /** Type to descriptor map. */
-        private readonly IDictionary<Type, IBinaryTypeDescriptor> _typeToDesc =
-            new Dictionary<Type, IBinaryTypeDescriptor>();
+        private readonly CopyOnWriteConcurrentDictionary<Type, BinaryFullTypeDescriptor> _typeToDesc =
+            new CopyOnWriteConcurrentDictionary<Type, BinaryFullTypeDescriptor>();
 
         /** Type name to descriptor map. */
-        private readonly IDictionary<string, IBinaryTypeDescriptor> _typeNameToDesc =
-            new Dictionary<string, IBinaryTypeDescriptor>();
+        private readonly CopyOnWriteConcurrentDictionary<string, BinaryFullTypeDescriptor> _typeNameToDesc =
+            new CopyOnWriteConcurrentDictionary<string, BinaryFullTypeDescriptor>();
 
         /** ID to descriptor map. */
-        private readonly CopyOnWriteConcurrentDictionary<long, IBinaryTypeDescriptor> _idToDesc =
-            new CopyOnWriteConcurrentDictionary<long, IBinaryTypeDescriptor>();
+        private readonly CopyOnWriteConcurrentDictionary<long, BinaryFullTypeDescriptor> _idToDesc =
+            new CopyOnWriteConcurrentDictionary<long, BinaryFullTypeDescriptor>();
 
-        /** Cached metadatas. */
-        private volatile IDictionary<int, BinaryTypeHolder> _metas =
-            new Dictionary<int, BinaryTypeHolder>();
+        /** Cached binary types. */
+        private volatile IDictionary<int, BinaryTypeHolder> _metas = new Dictionary<int, BinaryTypeHolder>();
+
+        /** */
+        private volatile Ignite _ignite;
+
+        /** */
+        private readonly ILogger _log;
 
         /// <summary>
         /// Constructor.
         /// </summary>
         /// <param name="cfg">Configuration.</param>
-        public Marshaller(BinaryConfiguration cfg)
+        /// <param name="log"></param>
+        public Marshaller(BinaryConfiguration cfg, ILogger log = null)
         {
-            // Validation.
-            if (cfg == null)
-                cfg = new BinaryConfiguration();
+            _cfg = cfg ?? new BinaryConfiguration();
+
+            _log = log;
 
-            CompactFooter = cfg.CompactFooter;
+            CompactFooter = _cfg.CompactFooter;
 
-            if (cfg.TypeConfigurations == null)
-                cfg.TypeConfigurations = new List<BinaryTypeConfiguration>();
+            if (_cfg.TypeConfigurations == null)
+                _cfg.TypeConfigurations = new List<BinaryTypeConfiguration>();
 
-            foreach (BinaryTypeConfiguration typeCfg in cfg.TypeConfigurations)
+            foreach (BinaryTypeConfiguration typeCfg in _cfg.TypeConfigurations)
             {
                 if (string.IsNullOrEmpty(typeCfg.TypeName))
                     throw new BinaryObjectException("Type name cannot be null or empty: " + typeCfg);
@@ -85,25 +93,32 @@ namespace Apache.Ignite.Core.Impl.Binary
             // 2. Define user types.
             var typeResolver = new TypeResolver();
 
-            ICollection<BinaryTypeConfiguration> typeCfgs = cfg.TypeConfigurations;
+            ICollection<BinaryTypeConfiguration> typeCfgs = _cfg.TypeConfigurations;
 
             if (typeCfgs != null)
                 foreach (BinaryTypeConfiguration typeCfg in typeCfgs)
                     AddUserType(cfg, typeCfg, typeResolver);
 
-            var typeNames = cfg.Types;
+            var typeNames = _cfg.Types;
 
             if (typeNames != null)
                 foreach (string typeName in typeNames)
                     AddUserType(cfg, new BinaryTypeConfiguration(typeName), typeResolver);
-
-            _cfg = cfg;
         }
 
         /// <summary>
         /// Gets or sets the backing grid.
         /// </summary>
-        public Ignite Ignite { get; set; }
+        public Ignite Ignite
+        {
+            get { return _ignite; }
+            set
+            {
+                Debug.Assert(value != null);
+
+                _ignite = value;
+            }
+        }
 
         /// <summary>
         /// Gets the compact footer flag.
@@ -111,6 +126,12 @@ namespace Apache.Ignite.Core.Impl.Binary
         public bool CompactFooter { get; set; }
 
         /// <summary>
+        /// Gets or sets a value indicating whether type registration is disabled.
+        /// This may be desirable for static system marshallers where everything is written in unregistered mode.
+        /// </summary>
+        public bool RegistrationDisabled { get; set; }
+
+        /// <summary>
         /// Marshal object.
         /// </summary>
         /// <param name="val">Value.</param>
@@ -126,11 +147,10 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
-        /// Marshal object.
+        /// Marshals an object.
         /// </summary>
         /// <param name="val">Value.</param>
         /// <param name="stream">Output stream.</param>
-        /// <returns>Collection of metadatas (if any).</returns>
         private void Marshal<T>(T val, IBinaryStream stream)
         {
             BinaryWriter writer = StartMarshal(stream);
@@ -358,17 +378,20 @@ namespace Apache.Ignite.Core.Impl.Binary
                 _metas[meta.TypeId].Merge(mergeInfo);
             }
         }
-        
+
         /// <summary>
         /// Gets descriptor for type.
         /// </summary>
         /// <param name="type">Type.</param>
-        /// <returns>Descriptor.</returns>
+        /// <returns>
+        /// Descriptor.
+        /// </returns>
         public IBinaryTypeDescriptor GetDescriptor(Type type)
         {
-            IBinaryTypeDescriptor desc;
+            BinaryFullTypeDescriptor desc;
 
-            _typeToDesc.TryGetValue(type, out desc);
+            if (!_typeToDesc.TryGetValue(type, out desc) || !desc.IsRegistered)
+                desc = RegisterType(type, desc);
 
             return desc;
         }
@@ -380,10 +403,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <returns>Descriptor.</returns>
         public IBinaryTypeDescriptor GetDescriptor(string typeName)
         {
-            IBinaryTypeDescriptor desc;
+            BinaryFullTypeDescriptor desc;
 
-            return _typeNameToDesc.TryGetValue(typeName, out desc) ? desc : 
-                new BinarySurrogateTypeDescriptor(_cfg, typeName);
+            return _typeNameToDesc.TryGetValue(typeName, out desc)
+                ? (IBinaryTypeDescriptor) desc
+                : new BinarySurrogateTypeDescriptor(_cfg, typeName);
         }
 
         /// <summary>
@@ -391,24 +415,43 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="userType">User type flag.</param>
         /// <param name="typeId">Type id.</param>
-        /// <returns>Descriptor.</returns>
-        public IBinaryTypeDescriptor GetDescriptor(bool userType, int typeId)
+        /// <param name="requiresType">
+        /// If set to true, resulting descriptor must have Type property populated.
+        /// <para />
+        /// When working in binary mode, we don't need Type. And there is no Type at all in some cases.
+        /// So we should not attempt to call BinaryProcessor right away.
+        /// Only when we really deserialize the value, requiresType is set to true
+        /// and we attempt to resolve the type by all means.
+        /// </param>
+        /// <returns>
+        /// Descriptor.
+        /// </returns>
+        public IBinaryTypeDescriptor GetDescriptor(bool userType, int typeId, bool requiresType = false)
         {
-            IBinaryTypeDescriptor desc;
+            BinaryFullTypeDescriptor desc;
 
             var typeKey = BinaryUtils.TypeKey(userType, typeId);
 
-            if (_idToDesc.TryGetValue(typeKey, out desc))
+            if (_idToDesc.TryGetValue(typeKey, out desc) && (!requiresType || desc.Type != null))
                 return desc;
 
             if (!userType)
                 return null;
 
+            if (requiresType)
+            {
+                // Check marshaller context for dynamically registered type.
+                var type = _ignite == null ? null : _ignite.BinaryProcessor.GetType(typeId);
+
+                if (type != null)
+                    return AddUserType(type, typeId, BinaryUtils.GetTypeName(type), true, desc);
+            }
+
             var meta = GetBinaryType(typeId);
 
             if (meta != BinaryType.Empty)
             {
-                desc = new BinaryFullTypeDescriptor(null, meta.TypeId, meta.TypeName, true, null, null, null, false, 
+                desc = new BinaryFullTypeDescriptor(null, meta.TypeId, meta.TypeName, true, null, null, null, false,
                     meta.AffinityKeyFieldName, meta.IsEnum, null);
 
                 _idToDesc.GetOrAdd(typeKey, _ => desc);
@@ -416,13 +459,30 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return desc;
             }
 
-            return new BinarySurrogateTypeDescriptor(_cfg, typeId);
+            return new BinarySurrogateTypeDescriptor(_cfg, typeId, null);
+        }
+
+        /// <summary>
+        /// Registers the type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="desc">Existing descriptor.</param>
+        private BinaryFullTypeDescriptor RegisterType(Type type, BinaryFullTypeDescriptor desc)
+        {
+            Debug.Assert(type != null);
+
+            var typeName = BinaryUtils.GetTypeName(type);
+            var typeId = BinaryUtils.TypeId(typeName, _cfg.DefaultNameMapper, _cfg.DefaultIdMapper);
+
+            var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, type);
+
+            return AddUserType(type, typeId, typeName, registered, desc);
         }
 
         /// <summary>
         /// Gets the user type descriptors.
         /// </summary>
-        public ICollection<IBinaryTypeDescriptor> GetUserTypeDescriptors()
+        public ICollection<BinaryFullTypeDescriptor> GetUserTypeDescriptors()
         {
             return _typeNameToDesc.Values;
         }
@@ -430,18 +490,67 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Add user type.
         /// </summary>
-        /// <param name="cfg">Configuration.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="typeId">The type id.</param>
+        /// <param name="typeName">Name of the type.</param>
+        /// <param name="registered">Registered flag.</param>
+        /// <param name="desc">Existing descriptor.</param>
+        /// <returns>Descriptor.</returns>
+        private BinaryFullTypeDescriptor AddUserType(Type type, int typeId, string typeName, bool registered,
+            BinaryFullTypeDescriptor desc)
+        {
+            Debug.Assert(type != null);
+            Debug.Assert(typeName != null);
+
+            var ser = GetSerializer(_cfg, null, type, typeId, null, null, _log);
+
+            desc = desc == null
+                ? new BinaryFullTypeDescriptor(type, typeId, typeName, true, _cfg.DefaultNameMapper,
+                    _cfg.DefaultIdMapper, ser, false, null, type.IsEnum, null, registered)
+                : new BinaryFullTypeDescriptor(desc, type, ser, registered);
+
+            if (RegistrationDisabled)
+                return desc;
+
+            var typeKey = BinaryUtils.TypeKey(true, typeId);
+
+            var desc0 = _idToDesc.GetOrAdd(typeKey, x => desc);
+            if (desc0.Type != null && desc0.Type.FullName != type.FullName)
+                ThrowConflictingTypeError(type, desc0.Type, typeId);
+
+            desc0 = _typeNameToDesc.GetOrAdd(typeName, x => desc);
+            if (desc0.Type != null && desc0.Type.FullName != type.FullName)
+                ThrowConflictingTypeError(type, desc0.Type, typeId);
+
+            _typeToDesc.Set(type, desc);
+
+            return desc;
+        }
+
+        /// <summary>
+        /// Throws the conflicting type error.
+        /// </summary>
+        private static void ThrowConflictingTypeError(object type1, object type2, int typeId)
+        {
+            throw new BinaryObjectException(string.Format("Conflicting type IDs [type1='{0}', " +
+                                                          "type2='{1}', typeId={2}]", type1, type2, typeId));
+        }
+
+        /// <summary>
+        /// Add user type.
+        /// </summary>
+        /// <param name="cfg">The binary configuration.</param>
         /// <param name="typeCfg">Type configuration.</param>
         /// <param name="typeResolver">The type resolver.</param>
-        private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, 
-            TypeResolver typeResolver)
+        /// <exception cref="BinaryObjectException"></exception>
+        private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, TypeResolver typeResolver)
         {
             // Get converter/mapper/serializer.
-            IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? cfg.DefaultNameMapper;
+            IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? _cfg.DefaultNameMapper;
 
-            IBinaryIdMapper idMapper = typeCfg.IdMapper ?? cfg.DefaultIdMapper;
+            IBinaryIdMapper idMapper = typeCfg.IdMapper ?? _cfg.DefaultIdMapper;
 
-            bool keepDeserialized = typeCfg.KeepDeserialized ?? cfg.DefaultKeepDeserialized;
+            bool keepDeserialized = typeCfg.KeepDeserialized ?? _cfg.DefaultKeepDeserialized;
 
             // Try resolving type.
             Type type = typeResolver.ResolveType(typeCfg.TypeName);
@@ -459,7 +568,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 var typeName = BinaryUtils.GetTypeName(type);
                 int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper);
                 var affKeyFld = typeCfg.AffinityKeyFieldName ?? GetAffinityKeyFieldNameFromAttribute(type);
-                var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper);
+                var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper, _log);
 
                 AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer,
                     affKeyFld, type.IsEnum, typeCfg.EqualityComparer);
@@ -479,16 +588,25 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Gets the serializer.
         /// </summary>
-        private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg,
-            Type type, int typeId, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper)
+        private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, 
+            BinaryTypeConfiguration typeCfg, Type type, int typeId, IBinaryNameMapper nameMapper,
+            IBinaryIdMapper idMapper, ILogger log)
         {
-            var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer;
+            var serializer = (typeCfg != null ? typeCfg.Serializer : null) ??
+                             (cfg != null ? cfg.DefaultSerializer : null);
 
             if (serializer == null)
             {
                 if (type.GetInterfaces().Contains(typeof(IBinarizable)))
                     return BinarizableSerializer.Instance;
 
+                if (type.GetInterfaces().Contains(typeof(ISerializable)))
+                {
+                    LogSerializableWarning(type, log);
+
+                    return new SerializableSerializer(type);
+                }
+
                 serializer = new BinaryReflectiveSerializer();
             }
 
@@ -531,14 +649,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="affKeyFieldName">Affinity key field name.</param>
         /// <param name="isEnum">Enum flag.</param>
         /// <param name="comparer">Comparer.</param>
-        private void AddType(Type type, int typeId, string typeName, bool userType, 
+        private void AddType(Type type, int typeId, string typeName, bool userType,
             bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper,
-            IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum, 
+            IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum,
             IEqualityComparer<IBinaryObject> comparer)
         {
             long typeKey = BinaryUtils.TypeKey(userType, typeId);
 
-            IBinaryTypeDescriptor conflictingType;
+            BinaryFullTypeDescriptor conflictingType;
 
             if (_idToDesc.TryGetValue(typeKey, out conflictingType))
             {
@@ -548,8 +666,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                 var type2 = type != null ? type.AssemblyQualifiedName : typeName;
 
-                throw new BinaryObjectException(string.Format("Conflicting type IDs [type1='{0}', " +
-                                                              "type2='{1}', typeId={2}]", type1, type2, typeId));
+                ThrowConflictingTypeError(type1, type2, typeId);
             }
 
             if (userType && _typeNameToDesc.ContainsKey(typeName))
@@ -559,10 +676,10 @@ namespace Apache.Ignite.Core.Impl.Binary
                 serializer, keepDeserialized, affKeyFieldName, isEnum, comparer);
 
             if (type != null)
-                _typeToDesc[type] = descriptor;
+                _typeToDesc.GetOrAdd(type, x => descriptor);
 
             if (userType)
-                _typeNameToDesc[typeName] = descriptor;
+                _typeNameToDesc.GetOrAdd(typeName, x => descriptor);
 
             _idToDesc.GetOrAdd(typeKey, _ => descriptor);
         }
@@ -570,7 +687,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Adds a predefined system type.
         /// </summary>
-        private void AddSystemType<T>(int typeId, Func<BinaryReader, T> ctor, string affKeyFldName = null, 
+        private void AddSystemType<T>(int typeId, Func<BinaryReader, T> ctor, string affKeyFldName = null,
             IBinarySerializerInternal serializer = null)
             where T : IBinaryWriteAware
         {
@@ -599,10 +716,6 @@ namespace Apache.Ignite.Core.Impl.Binary
             AddSystemType(BinaryUtils.TypeComputeFuncJob, r => new ComputeFuncJob(r));
             AddSystemType(BinaryUtils.TypeComputeActionJob, r => new ComputeActionJob(r));
             AddSystemType(BinaryUtils.TypeContinuousQueryRemoteFilterHolder, r => new ContinuousQueryFilterHolder(r));
-            AddSystemType(BinaryUtils.TypeSerializableHolder, r => new SerializableObjectHolder(r),
-                serializer: new SerializableSerializer());
-            AddSystemType(BinaryUtils.TypeDateTimeHolder, r => new DateTimeHolder(r),
-                serializer: new DateTimeSerializer());
             AddSystemType(BinaryUtils.TypeCacheEntryProcessorHolder, r => new CacheEntryProcessorHolder(r));
             AddSystemType(BinaryUtils.TypeCacheEntryPredicateHolder, r => new CacheEntryFilterHolder(r));
             AddSystemType(BinaryUtils.TypeMessageListenerHolder, r => new MessageListenerHolder(r));
@@ -612,5 +725,20 @@ namespace Apache.Ignite.Core.Impl.Binary
             AddSystemType(0, r => new ObjectInfoHolder(r));
             AddSystemType(BinaryUtils.TypeIgniteUuid, r => new IgniteGuid(r));
         }
+
+        /// <summary>
+        /// Logs the warning about ISerializable pitfalls.
+        /// </summary>
+        private static void LogSerializableWarning(Type type, ILogger log)
+        {
+            if (log == null)
+                return;
+
+            log.GetLogger(typeof(Marshaller).Name)
+                .Warn("Type '{0}' implements '{1}'. It will be written in Ignite binary format, however, " +
+                      "the following limitations apply: " +
+                      "DateTime fields would not work in SQL; " +
+                      "sbyte, ushort, uint, ulong fields would not work in DML.", type, typeof(ISerializable));
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs
new file mode 100644
index 0000000..50c51a7
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs
@@ -0,0 +1,50 @@
+\ufeff/*
+ * 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.Reflection;
+
+    /// <summary>
+    /// Reflection utils.
+    /// </summary>
+    internal static class ReflectionUtils
+    {
+        /// <summary>
+        /// Gets all fields, including base classes.
+        /// </summary>
+        public static IEnumerable<FieldInfo> GetAllFields(Type type)
+        {
+            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public |
+                                       BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
+
+            var curType = type;
+
+            while (curType != null)
+            {
+                foreach (var field in curType.GetFields(flags))
+                {
+                    yield return field;
+                }
+
+                curType = curType.BaseType;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
deleted file mode 100644
index 26b1d5f..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
+++ /dev/null
@@ -1,96 +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.
- */
-
-namespace Apache.Ignite.Core.Impl.Binary
-{
-    using System.Diagnostics;
-    using System.Runtime.Serialization.Formatters.Binary;
-    using Apache.Ignite.Core.Binary;
-    using Apache.Ignite.Core.Impl.Binary.IO;
-
-    /// <summary>
-    /// Wraps Serializable item in a binarizable.
-    /// </summary>
-    internal class SerializableObjectHolder : IBinaryWriteAware
-    {
-        /** */
-        private readonly object _item;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SerializableObjectHolder"/> class.
-        /// </summary>
-        /// <param name="item">The item to wrap.</param>
-        public SerializableObjectHolder(object item)
-        {
-            _item = item;
-        }
-
-        /// <summary>
-        /// Gets the item to wrap.
-        /// </summary>
-        public object Item
-        {
-            get { return _item; }
-        }
-
-        /** <inheritDoc /> */
-        public void WriteBinary(IBinaryWriter writer)
-        {
-            Debug.Assert(writer != null);
-
-            var writer0 = (BinaryWriter)writer.GetRawWriter();
-
-            writer0.WithDetach(w =>
-            {
-                using (var streamAdapter = new BinaryStreamAdapter(w.Stream))
-                {
-                    new BinaryFormatter().Serialize(streamAdapter, Item);
-                }
-            });
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SerializableObjectHolder"/> class.
-        /// </summary>
-        /// <param name="reader">The reader.</param>
-        public SerializableObjectHolder(BinaryReader reader)
-        {
-            Debug.Assert(reader != null);
-
-            using (var streamAdapter = new BinaryStreamAdapter(reader.Stream))
-            {
-                _item = new BinaryFormatter().Deserialize(streamAdapter, null);
-            }
-        }
-
-        /** <inheritdoc /> */
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-
-            return Equals(_item, ((SerializableObjectHolder) obj)._item);
-        }
-
-        /** <inheritdoc /> */
-        public override int GetHashCode()
-        {
-            return _item != null ? _item.GetHashCode() : 0;
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
index 55ac3c0..6c7076a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
@@ -1,4 +1,4 @@
-/*
+\ufeff/*
  * 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.
@@ -18,31 +18,667 @@
 namespace Apache.Ignite.Core.Impl.Binary
 {
     using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary.Metadata;
     using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
-    /// Serializable serializer.
+    /// Serializes classes that implement <see cref="ISerializable"/>.
     /// </summary>
     internal class SerializableSerializer : IBinarySerializerInternal
     {
+        /** */
+        private readonly SerializableTypeDescriptor _serializableTypeDesc;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SerializableSerializer"/> class.
+        /// </summary>
+        public SerializableSerializer(Type type)
+        {
+            IgniteArgumentCheck.NotNull(type, "type");
+
+            _serializableTypeDesc = SerializableTypeDescriptor.Get(type);
+        }
+        
         /** <inheritdoc /> */
-        public void WriteBinary<T>(T obj, BinaryWriter writer)
+        public bool SupportsHandles
         {
-            TypeCaster<SerializableObjectHolder>.Cast(obj).WriteBinary(writer);
+            get { return true; }
         }
 
         /** <inheritdoc /> */
-        public T ReadBinary<T>(BinaryReader reader, Type type, int pos)
+        public void WriteBinary<T>(T obj, BinaryWriter writer)
         {
-            var holder = new SerializableObjectHolder(reader);
+            var ctx = GetStreamingContext(writer);
+            _serializableTypeDesc.OnSerializing(obj, ctx);
+
+            var serializable = (ISerializable) obj;
+            var objType = obj.GetType();
+
+            // Get field values and write them.
+            var serInfo = new SerializationInfo(objType, new FormatterConverter());
+            serializable.GetObjectData(serInfo, ctx);
 
-            return TypeCaster<T>.Cast(holder.Item);
+            var dotNetFields = WriteSerializationInfo(writer, serInfo);
+
+            // Check if there is any additional information to be written.
+            var customType = GetCustomType(serInfo, serializable);
+
+            if (dotNetFields != null || writer.Marshaller.Ignite == null || customType != null)
+            {
+                // Set custom type flag in object header.
+                writer.SetCustomTypeDataFlag(true);
+
+                // Write additional information in raw mode.
+                writer.GetRawWriter();
+
+                WriteFieldNames(writer, serInfo);
+
+                WriteCustomTypeInfo(writer, customType);
+
+                WriteDotNetFields(writer, dotNetFields);
+            }
+
+            _serializableTypeDesc.OnSerialized(obj, ctx);
         }
 
         /** <inheritdoc /> */
-        public bool SupportsHandles
+        public T ReadBinary<T>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos)
+        {
+            object res;
+            var ctx = GetStreamingContext(reader);
+            var callbackPushed = false;
+
+            // Read additional information from raw part, if flag is set.
+            IEnumerable<string> fieldNames;
+            Type customType = null;
+            ICollection<int> dotNetFields = null;
+
+            if (reader.GetCustomTypeDataFlag())
+            {
+                var oldPos = reader.Stream.Position;
+                reader.SeekToRaw();
+
+                fieldNames = ReadFieldNames(reader, desc);
+                customType = ReadCustomTypeInfo(reader);
+                dotNetFields = ReadDotNetFields(reader);
+
+                // Restore stream position.
+                reader.Stream.Seek(oldPos, SeekOrigin.Begin);
+            }
+            else
+            {
+                fieldNames = GetBinaryTypeFields(reader, desc);
+            }
+
+            try
+            {
+                if (customType != null)
+                {
+                    // Custom type is present, which returns original type via IObjectReference.
+                    var serInfo = ReadSerializationInfo(reader, fieldNames, desc, dotNetFields);
+
+                    res = ReadAsCustomType(customType, serInfo, ctx);
+
+                    // Handle is added after entire object is deserialized,
+                    // because handles should not point to a custom type wrapper.
+                    reader.AddHandle(pos, res);
+
+                    DeserializationCallbackProcessor.Push(res);
+                    callbackPushed = true;
+                }
+                else
+                {
+                    res = FormatterServices.GetUninitializedObject(desc.Type);
+
+                    _serializableTypeDesc.OnDeserializing(res, ctx);
+
+                    DeserializationCallbackProcessor.Push(res);
+                    callbackPushed = true;
+
+                    reader.AddHandle(pos, res);
+
+                    // Read actual data and call constructor.
+                    var serInfo = ReadSerializationInfo(reader, fieldNames, desc, dotNetFields);
+                    _serializableTypeDesc.SerializationCtorUninitialized(res, serInfo, ctx);
+                }
+
+                _serializableTypeDesc.OnDeserialized(res, ctx);
+            }
+            finally
+            {
+                if (callbackPushed)
+                    DeserializationCallbackProcessor.Pop();
+            }
+
+            return (T) res;
+        }
+
+        /// <summary>
+        /// Writes .NET-specific fields.
+        /// </summary>
+        private static void WriteDotNetFields(IBinaryRawWriter writer, ICollection<string> dotNetFields)
         {
-            get { return false; }
+            if (dotNetFields == null)
+            {
+                writer.WriteInt(0);
+
+                return;
+            }
+
+            writer.WriteInt(dotNetFields.Count);
+
+            foreach (var dotNetField in dotNetFields)
+            {
+                writer.WriteInt(BinaryUtils.GetStringHashCode(dotNetField));
+            }
+        }
+
+        /// <summary>
+        /// Writes .NET-specific fields.
+        /// </summary>
+        private static ICollection<int> ReadDotNetFields(IBinaryRawReader reader)
+        {
+            int count = reader.ReadInt();
+
+            if (count <= 0)
+                return null;
+
+            var res = new HashSet<int>();
+
+            for (int i = 0; i < count; i++)
+            {
+                res.Add(reader.ReadInt());
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        /// Writes the field names.
+        /// </summary>
+        private static void WriteFieldNames(BinaryWriter writer, SerializationInfo serInfo)
+        {
+            if (writer.Marshaller.Ignite != null)
+            {
+                // Online mode: field names are in binary metadata.
+                writer.WriteInt(-1);
+                return;
+            }
+
+            // Offline mode: write all field names.
+            // Even if MemberCount is 0, write empty array to denote offline mode.
+            writer.WriteInt(serInfo.MemberCount);
+
+            foreach (var entry in serInfo)
+            {
+                writer.WriteString(entry.Name);
+            }
+        }
+
+        /// <summary>
+        /// Gets the field names.
+        /// </summary>
+        private static IEnumerable<string> ReadFieldNames(BinaryReader reader, IBinaryTypeDescriptor desc)
+        {
+            var fieldCount = reader.ReadInt();
+
+            if (fieldCount == 0)
+                return Enumerable.Empty<string>();
+
+            if (fieldCount > 0)
+            {
+                var fieldNames = new string[fieldCount];
+
+                for (var i = 0; i < fieldCount; i++)
+                {
+                    fieldNames[i] = reader.ReadString();
+                }
+
+                return fieldNames;
+            }
+
+            // Negative field count: online mode.
+            return GetBinaryTypeFields(reader, desc);
+        }
+
+        /// <summary>
+        /// Gets the binary type fields.
+        /// </summary>
+        private static IEnumerable<string> GetBinaryTypeFields(BinaryReader reader, IBinaryTypeDescriptor desc)
+        {
+            var binaryType = reader.Marshaller.GetBinaryType(desc.TypeId);
+
+            if (binaryType == BinaryType.Empty)
+            {
+                // Object without fields.
+                return Enumerable.Empty<string>();
+            }
+
+            return binaryType.Fields;
+        }
+
+        /// <summary>
+        /// Writes the custom type information.
+        /// </summary>
+        private static void WriteCustomTypeInfo(BinaryWriter writer, Type customType)
+        {
+            var raw = writer.GetRawWriter();
+
+            if (customType != null)
+            {
+                raw.WriteBoolean(true);
+
+                var desc = writer.Marshaller.GetDescriptor(customType);
+
+                if (desc.IsRegistered)
+                {
+                    raw.WriteBoolean(true);
+                    raw.WriteInt(desc.TypeId);
+                }
+                else
+                {
+                    raw.WriteBoolean(false);
+                    raw.WriteString(customType.FullName);
+                }
+            }
+            else
+            {
+                raw.WriteBoolean(false);
+            }
+        }
+
+        /// <summary>
+        /// Gets the custom serialization type.
+        /// </summary>
+        private static Type GetCustomType(SerializationInfo serInfo, ISerializable serializable)
+        {
+            // ISerializable implementor may call SerializationInfo.SetType() or FullTypeName setter.
+            // In that case there is no serialization ctor on objType. 
+            // Instead, we should instantiate specified custom type and then call IObjectReference.GetRealObject().
+            if (serInfo.IsFullTypeNameSetExplicit)
+            {
+                return new TypeResolver().ResolveType(serInfo.FullTypeName, serInfo.AssemblyName);
+            }
+            
+            if (serInfo.ObjectType != serializable.GetType())
+            {
+                return serInfo.ObjectType;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Reads the custom type information.
+        /// </summary>
+        private static Type ReadCustomTypeInfo(BinaryReader reader)
+        {
+            if (!reader.ReadBoolean())
+                return null;
+
+            Type customType;
+
+            if (reader.ReadBoolean())
+            {
+                // Registered type written as type id.
+                var typeId = reader.ReadInt();
+                customType = reader.Marshaller.GetDescriptor(true, typeId, true).Type;
+
+                if (customType == null)
+                {
+                    throw new BinaryObjectException(string.Format(
+                        "Failed to resolve custom type provided by SerializationInfo: [typeId={0}]", typeId));
+                }
+            }
+            else
+            {
+                // Unregistered type written as type name.
+                var typeName = reader.ReadString();
+                customType = new TypeResolver().ResolveType(typeName);
+
+                if (customType == null)
+                {
+                    throw new BinaryObjectException(string.Format(
+                        "Failed to resolve custom type provided by SerializationInfo: [typeName={0}]", typeName));
+                }
+            }
+
+            return customType;
+        }
+
+        /// <summary>
+        /// Writes the serialization information.
+        /// </summary>
+        private static List<string> WriteSerializationInfo(IBinaryWriter writer, SerializationInfo serInfo)
+        {
+            List<string> dotNetFields = null;
+
+            // Write fields.
+            foreach (var entry in GetEntries(serInfo).OrderBy(x => x.Name))
+            {
+                WriteEntry(writer, entry);
+
+                var type = entry.Value == null ? null : entry.Value.GetType();
+
+                if (type == typeof(sbyte) || type == typeof(ushort) || type == typeof(uint) || type == typeof(ulong)
+                    || type == typeof(sbyte[]) || type == typeof(ushort[])
+                    || type == typeof(uint[]) || type == typeof(ulong[]))
+                {
+                    // Denote .NET-specific type.
+                    dotNetFields = dotNetFields ?? new List<string>();
+
+                    dotNetFields.Add(entry.Name);
+                }
+            }
+
+            return dotNetFields;
+        }
+
+        /// <summary>
+        /// Writes the serialization entry.
+        /// </summary>
+        private static void WriteEntry(IBinaryWriter writer, SerializationEntry entry)
+        {
+            unchecked
+            {
+                var type = entry.ObjectType;
+
+                if (type == typeof(byte))
+                {
+                    writer.WriteByte(entry.Name, (byte) entry.Value);
+                }
+                else if (type == typeof(byte[]))
+                {
+                    writer.WriteByteArray(entry.Name, (byte[]) entry.Value);
+                }
+                if (type == typeof(sbyte))
+                {
+                    writer.WriteByte(entry.Name, (byte) (sbyte) entry.Value);
+                }
+                else if (type == typeof(sbyte[]))
+                {
+                    writer.WriteByteArray(entry.Name, (byte[]) (Array) entry.Value);
+                }
+                else if (type == typeof(bool))
+                {
+                    writer.WriteBoolean(entry.Name, (bool) entry.Value);
+                }
+                else if (type == typeof(bool[]))
+                {
+                    writer.WriteBooleanArray(entry.Name, (bool[]) entry.Value);
+                }
+                else if (type == typeof(char))
+                {
+                    writer.WriteChar(entry.Name, (char) entry.Value);
+                }
+                else if (type == typeof(char[]))
+                {
+                    writer.WriteCharArray(entry.Name, (char[]) entry.Value);
+                }
+                else if (type == typeof(short))
+                {
+                    writer.WriteShort(entry.Name, (short) entry.Value);
+                }
+                else if (type == typeof(short[]))
+                {
+                    writer.WriteShortArray(entry.Name, (short[]) entry.Value);
+                }
+                else if (type == typeof(ushort))
+                {
+                    writer.WriteShort(entry.Name, (short) (ushort) entry.Value);
+                }
+                else if (type == typeof(ushort[]))
+                {
+                    writer.WriteShortArray(entry.Name, (short[]) (Array) entry.Value);
+                }
+                else if (type == typeof(int))
+                {
+                    writer.WriteInt(entry.Name, (int) entry.Value);
+                }
+                else if (type == typeof(int[]))
+                {
+                    writer.WriteIntArray(entry.Name, (int[]) entry.Value);
+                }
+                else if (type == typeof(uint))
+                {
+                    writer.WriteInt(entry.Name, (int) (uint) entry.Value);
+                }
+                else if (type == typeof(uint[]))
+                {
+                    writer.WriteIntArray(entry.Name, (int[]) (Array) entry.Value);
+                }
+                else if (type == typeof(long))
+                {
+                    writer.WriteLong(entry.Name, (long) entry.Value);
+                }
+                else if (type == typeof(long[]))
+                {
+                    writer.WriteLongArray(entry.Name, (long[]) entry.Value);
+                }
+                else if (type == typeof(ulong))
+                {
+                    writer.WriteLong(entry.Name, (long) (ulong) entry.Value);
+                }
+                else if (type == typeof(ulong[]))
+                {
+                    writer.WriteLongArray(entry.Name, (long[]) (Array) entry.Value);
+                }
+                else if (type == typeof(float))
+                {
+                    writer.WriteFloat(entry.Name, (float) entry.Value);
+                }
+                else if (type == typeof(float[]))
+                {
+                    writer.WriteFloatArray(entry.Name, (float[]) entry.Value);
+                }
+                else if (type == typeof(double))
+                {
+                    writer.WriteDouble(entry.Name, (double) entry.Value);
+                }
+                else if (type == typeof(double[]))
+                {
+                    writer.WriteDoubleArray(entry.Name, (double[]) entry.Value);
+                }
+                else if (type == typeof(decimal))
+                {
+                    writer.WriteDecimal(entry.Name, (decimal) entry.Value);
+                }
+                else if (type == typeof(decimal?))
+                {
+                    writer.WriteDecimal(entry.Name, (decimal?) entry.Value);
+                }
+                else if (type == typeof(decimal?[]))
+                {
+                    writer.WriteDecimalArray(entry.Name, (decimal?[]) entry.Value);
+                }
+                else if (type == typeof(string))
+                {
+                    writer.WriteString(entry.Name, (string) entry.Value);
+                }
+                else if (type == typeof(string[]))
+                {
+                    writer.WriteStringArray(entry.Name, (string[]) entry.Value);
+                }
+                else if (type == typeof(Guid))
+                {
+                    writer.WriteGuid(entry.Name, (Guid) entry.Value);
+                }
+                else if (type == typeof(Guid?))
+                {
+                    writer.WriteGuid(entry.Name, (Guid?) entry.Value);
+                }
+                else if (type == typeof(Guid?[]))
+                {
+                    writer.WriteGuidArray(entry.Name, (Guid?[]) entry.Value);
+                }
+                else
+                {
+                    writer.WriteObject(entry.Name, entry.Value);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the entries.
+        /// </summary>
+        private static IEnumerable<SerializationEntry> GetEntries(SerializationInfo serInfo)
+        {
+            foreach (var entry in serInfo)
+            {
+                yield return entry;
+            }
+        }
+
+        /// <summary>
+        /// Reads the serialization information.
+        /// </summary>
+        private static SerializationInfo ReadSerializationInfo(BinaryReader reader, 
+            IEnumerable<string> fieldNames, IBinaryTypeDescriptor desc, ICollection<int> dotNetFields)
+        {
+            var serInfo = new SerializationInfo(desc.Type, new FormatterConverter());
+
+            if (dotNetFields == null)
+            {
+                foreach (var fieldName in fieldNames)
+                {
+                    var fieldVal = reader.ReadObject<object>(fieldName);
+
+                    serInfo.AddValue(fieldName, fieldVal);
+                }
+            }
+            else
+            {
+                foreach (var fieldName in fieldNames)
+                {
+                    var fieldVal = ReadField(reader, fieldName, dotNetFields);
+
+                    serInfo.AddValue(fieldName, fieldVal);
+                }
+            }
+
+            return serInfo;
+        }
+
+        /// <summary>
+        /// Reads the object as a custom type.
+        /// </summary>
+        private static object ReadAsCustomType(Type customType, SerializationInfo serInfo, StreamingContext ctx)
+        {
+            var ctorFunc = SerializableTypeDescriptor.Get(customType).SerializationCtor;
+
+            var customObj = ctorFunc(serInfo, ctx);
+
+            var wrapper = customObj as IObjectReference;
+
+            return wrapper == null
+                ? customObj
+                : wrapper.GetRealObject(ctx);
+        }
+
+        /// <summary>
+        /// Gets the streaming context.
+        /// </summary>
+        private static StreamingContext GetStreamingContext(IBinaryReader reader)
+        {
+            return new StreamingContext(StreamingContextStates.All, reader);
+        }
+
+        /// <summary>
+        /// Gets the streaming context.
+        /// </summary>
+        private static StreamingContext GetStreamingContext(IBinaryWriter writer)
+        {
+            return new StreamingContext(StreamingContextStates.All, writer);
+        }
+
+        /// <summary>
+        /// Reads the field.
+        /// <para />
+        /// Java side does not have counterparts for byte, ushort, uint, ulong.
+        /// For such fields we write a special boolean field indicating the type.
+        /// If special field is present, then the value has to be converted to .NET-specific type.
+        /// </summary>
+        private static object ReadField(IBinaryReader reader, string fieldName, ICollection<int> dotNetFields)
+        {
+            var fieldVal = reader.ReadObject<object>(fieldName);
+
+            if (fieldVal == null)
+                return null;
+
+            var fieldType = fieldVal.GetType();
+
+            unchecked
+            {
+                if (fieldType == typeof(byte))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? (sbyte) (byte) fieldVal : fieldVal;
+                }
+
+                if (fieldType == typeof(short))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? (ushort) (short) fieldVal : fieldVal;
+                }
+
+                if (fieldType == typeof(int))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? (uint) (int) fieldVal : fieldVal;
+                }
+
+                if (fieldType == typeof(long))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? (ulong) (long) fieldVal : fieldVal;
+                }
+
+                if (fieldType == typeof(byte[]))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? ConvertArray<byte, sbyte>((byte[]) fieldVal) : fieldVal;
+                }
+
+                if (fieldType == typeof(short[]))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName))
+                        ? ConvertArray<short, ushort>((short[]) fieldVal) : fieldVal;
+                }
+
+                if (fieldType == typeof(int[]))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? ConvertArray<int, uint>((int[]) fieldVal) : fieldVal;
+                }
+
+                if (fieldType == typeof(long[]))
+                {
+                    return dotNetFields.Contains(BinaryUtils.GetStringHashCode(fieldName)) 
+                        ? ConvertArray<long, ulong>((long[]) fieldVal) : fieldVal;
+                }
+            }
+
+            return fieldVal;
+        }
+
+        /// <summary>
+        /// Converts the array.
+        /// </summary>
+        private static TU[] ConvertArray<T, TU>(T[] arr)
+        {
+            var res = new TU[arr.Length];
+
+            for (var i = 0; i < arr.Length; i++)
+            {
+                res[i] = TypeCaster<TU>.Cast(arr[i]);
+            }
+
+            return res;
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
index 340dac4..36dde4b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
@@ -50,6 +50,13 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             Debug.Assert(!string.IsNullOrEmpty(typeName));
 
+            // Fully-qualified name can be resolved with system mechanism.
+            var type = Type.GetType(typeName, false);
+
+            if (type != null)
+                return type;
+
+            // Partial names should be resolved by scanning assemblies.
             return ResolveType(assemblyName, typeName, AppDomain.CurrentDomain.GetAssemblies())
                 ?? ResolveTypeInReferencedAssemblies(assemblyName, typeName);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/UserSerializerProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/UserSerializerProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/UserSerializerProxy.cs
index de25e32..b0d393d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/UserSerializerProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/UserSerializerProxy.cs
@@ -17,7 +17,6 @@
 
 namespace Apache.Ignite.Core.Impl.Binary
 {
-    using System;
     using System.Diagnostics;
     using System.Runtime.Serialization;
     using Apache.Ignite.Core.Binary;
@@ -48,9 +47,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /** <inheritdoc /> */
-        public T ReadBinary<T>(BinaryReader reader, Type type, int pos)
+        public T ReadBinary<T>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos)
         {
-            var obj = FormatterServices.GetUninitializedObject(type);
+            var obj = FormatterServices.GetUninitializedObject(desc.Type);
 
             reader.AddHandle(pos, obj);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Affinity/AffinityFunctionSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Affinity/AffinityFunctionSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Affinity/AffinityFunctionSerializer.cs
index 5d940c5..73afe38 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Affinity/AffinityFunctionSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Affinity/AffinityFunctionSerializer.cs
@@ -255,9 +255,6 @@ namespace Apache.Ignite.Core.Impl.Cache.Affinity
                 return;
             }
 
-            if (func != null && !func.GetType().IsSerializable)
-                throw new IgniteException("AffinityFunction should be serializable.");
-
             writer.WriteObject(func);
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 a387e1b..2523cf7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
@@ -150,7 +150,8 @@ namespace Apache.Ignite.Core.Impl.Cache
         /** <inheritDoc /> */
         public CacheConfiguration GetConfiguration()
         {
-            return DoInOp((int) CacheOp.GetConfig, stream => new CacheConfiguration(Marshaller.StartUnmarshal(stream)));
+            return DoInOp((int) CacheOp.GetConfig, stream => new CacheConfiguration(
+                BinaryUtils.Marshaller.StartUnmarshal(stream)));
         }
 
         /** <inheritDoc /> */

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
index 01fc8a9..78cb8b6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+// ReSharper disable InconsistentlySynchronizedField
 namespace Apache.Ignite.Core.Impl.Common
 {
     using System;
@@ -69,5 +70,39 @@ namespace Apache.Ignite.Core.Impl.Common
                 return res;
             }
         }
+
+        /// <summary>
+        /// Sets a value for the key unconditionally.
+        /// </summary>
+        /// <param name="key">The key.</param>
+        /// <param name="value">The value.</param>
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods")]
+        public void Set(TKey key, TValue value)
+        {
+            lock (this)
+            {
+                var dict0 = new Dictionary<TKey, TValue>(_dict);
+
+                dict0[key] = value;
+
+                _dict = dict0;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified key exists in the dictionary.
+        /// </summary>
+        public bool ContainsKey(TKey key)
+        {
+            return _dict.ContainsKey(key);
+        }
+
+        /// <summary>
+        /// Gets the values.
+        /// </summary>
+        public ICollection<TValue> Values
+        {
+            get { return _dict.Values; }
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
index ff61e28..0407b62 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Impl.Common
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
     using System.Linq.Expressions;
     using System.Reflection;
     using System.Reflection.Emit;
@@ -203,13 +204,16 @@ namespace Apache.Ignite.Core.Impl.Common
         /// <typeparam name="T">Result func type.</typeparam>
         /// <param name="ctor">Contructor info.</param>
         /// <param name="argTypes">Argument types.</param>
-        /// <param name="convertResultToObject">if set to <c>true</c> [convert result to object].
+        /// <param name="convertResultToObject">
         /// Flag that indicates whether ctor return value should be converted to object.</param>
+        /// <param name="convertParamsFromObject">
+        /// Flag that indicates whether ctor args are object and should be converted to concrete type.</param>
         /// <returns>
         /// Compiled generic constructor.
         /// </returns>
         [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods")]
-        public static T CompileCtor<T>(ConstructorInfo ctor, Type[] argTypes, bool convertResultToObject = true)
+        public static T CompileCtor<T>(ConstructorInfo ctor, Type[] argTypes, bool convertResultToObject = true,
+            bool convertParamsFromObject = true)
         {
             Debug.Assert(ctor != null);
 
@@ -218,9 +222,16 @@ namespace Apache.Ignite.Core.Impl.Common
 
             for (var i = 0; i < argTypes.Length; i++)
             {
-                var arg = Expression.Parameter(typeof(object));
-                args[i] = arg;
-                argsConverted[i] = Expression.Convert(arg, argTypes[i]);
+                if (convertParamsFromObject)
+                {
+                    var arg = Expression.Parameter(typeof(object));
+                    args[i] = arg;
+                    argsConverted[i] = Expression.Convert(arg, argTypes[i]);
+                }
+                else
+                {
+                    argsConverted[i] = args[i] = Expression.Parameter(argTypes[i]);
+                }
             }
 
             Expression ctorExpr = Expression.New(ctor, argsConverted);  // ctor takes args of specific types
@@ -232,6 +243,50 @@ namespace Apache.Ignite.Core.Impl.Common
         }
 
         /// <summary>
+        /// Compiles a generic ctor with arbitrary number of arguments
+        /// that takes an uninitialized object as a first arguments.
+        /// </summary>
+        /// <typeparam name="T">Result func type.</typeparam>
+        /// <param name="ctor">Contructor info.</param>
+        /// <param name="argTypes">Argument types.</param>
+        /// <returns>
+        /// Compiled generic constructor.
+        /// </returns>
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods")]
+        public static T CompileUninitializedObjectCtor<T>(ConstructorInfo ctor, Type[] argTypes)
+        {
+            Debug.Assert(ctor != null);
+            Debug.Assert(ctor.DeclaringType != null);
+            Debug.Assert(argTypes != null);
+
+            argTypes = new[] {typeof(object)}.Concat(argTypes).ToArray();
+
+            var helperMethod = new DynamicMethod(string.Empty, typeof(void), argTypes, ctor.Module, true);
+            var il = helperMethod.GetILGenerator();
+
+            il.Emit(OpCodes.Ldarg_0);
+
+            if (ctor.DeclaringType.IsValueType)
+                il.Emit(OpCodes.Unbox, ctor.DeclaringType);   // modify boxed copy
+
+            if (argTypes.Length > 1)
+                il.Emit(OpCodes.Ldarg_1);
+
+            if (argTypes.Length > 2)
+                il.Emit(OpCodes.Ldarg_2);
+
+            if (argTypes.Length > 3)
+                throw new NotSupportedException("Not supported: too many ctor args.");
+
+            il.Emit(OpCodes.Call, ctor);
+            il.Emit(OpCodes.Ret);
+
+            var constructorInvoker = helperMethod.CreateDelegate(typeof(T));
+
+            return (T) (object) constructorInvoker;
+        }
+
+        /// <summary>
         /// Compiles a generic ctor with arbitrary number of arguments.
         /// </summary>
         /// <typeparam name="T">Result func type.</typeparam>
@@ -440,5 +495,30 @@ namespace Apache.Ignite.Core.Impl.Common
 
             return method;
         }
+
+        /// <summary>
+        /// Gets the constructor with exactly matching signature.
+        /// <para />
+        /// Type.GetConstructor matches compatible ones (i.e. taking object instead of concrete type).
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="types">The argument types.</param>
+        /// <returns>Constructor info.</returns>
+        public static ConstructorInfo GetConstructorExact(Type type, Type[] types)
+        {
+            Debug.Assert(type != null);
+            Debug.Assert(types != null);
+
+            foreach (var constructorInfo in type.GetConstructors(
+                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+            {
+                var ctorTypes = constructorInfo.GetParameters().Select(x => x.ParameterType);
+
+                if (ctorTypes.SequenceEqual(types))
+                    return constructorInfo;
+            }
+
+            return null;
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateTypeDescriptor.cs
index 2e837c4..4cd0678 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateTypeDescriptor.cs
@@ -19,7 +19,6 @@ namespace Apache.Ignite.Core.Impl.Common
 {
     using System;
     using System.Globalization;
-
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Event;
     using Apache.Ignite.Core.Compute;
@@ -37,7 +36,7 @@ namespace Apache.Ignite.Core.Impl.Common
     /// </summary>
     internal class DelegateTypeDescriptor
     {
-        /** Cached decriptors. */
+        /** Cached descriptors. */
         private static readonly CopyOnWriteConcurrentDictionary<Type, DelegateTypeDescriptor> Descriptors 
             = new CopyOnWriteConcurrentDictionary<Type, DelegateTypeDescriptor>();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/SerializableTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/SerializableTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/SerializableTypeDescriptor.cs
new file mode 100644
index 0000000..f16e32a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/SerializableTypeDescriptor.cs
@@ -0,0 +1,222 @@
+\ufeff/*
+ * 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.Common
+{
+    using System;
+    using System.Diagnostics;
+    using System.Reflection;
+    using System.Runtime.Serialization;
+
+    /// <summary>
+    /// Type descriptor with precompiled delegates to call serialization-related methods.
+    /// </summary>
+    internal class SerializableTypeDescriptor
+    {
+        /** Cached descriptors. */
+        private static readonly CopyOnWriteConcurrentDictionary<Type, SerializableTypeDescriptor> Descriptors 
+            = new CopyOnWriteConcurrentDictionary<Type, SerializableTypeDescriptor>();
+
+        /** */
+        private readonly Type _type;
+
+        /** */
+        private readonly Func<SerializationInfo, StreamingContext, object> _serializationCtor;
+
+        /** */
+        private readonly Action<object, SerializationInfo, StreamingContext> _serializationCtorUninitialized;
+
+        /** */
+        private readonly Action<object, StreamingContext> _onSerializing;
+
+        /** */
+        private readonly Action<object, StreamingContext> _onSerialized;
+
+        /** */
+        private readonly Action<object, StreamingContext> _onDeserializing;
+
+        /** */
+        private readonly Action<object, StreamingContext> _onDeserialized;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SerializableTypeDescriptor"/> class.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        private SerializableTypeDescriptor(Type type)
+        {
+            Debug.Assert(type != null);
+
+            _type = type;
+
+            // Check if there is a serialization ctor.
+            var argTypes = new[] {typeof(SerializationInfo), typeof(StreamingContext)};
+
+            var serializationCtorInfo = DelegateConverter.GetConstructorExact(type, argTypes);
+
+            if (serializationCtorInfo != null)
+            {
+                _serializationCtor = DelegateConverter.CompileCtor<Func<SerializationInfo, StreamingContext, object>>(
+                    serializationCtorInfo, argTypes, convertParamsFromObject: false);
+
+                _serializationCtorUninitialized = DelegateConverter.CompileUninitializedObjectCtor<
+                    Action<object, SerializationInfo, StreamingContext>>(serializationCtorInfo, argTypes);
+            }
+
+            // Scan methods for callback attributes.
+            // Initialize to empty delegates to avoid null checks.
+            _onSerializing = _onSerialized = _onDeserializing = _onDeserialized = (o, c) => { };
+
+            var baseType = type;
+
+            while (baseType != typeof(object) && baseType != null)
+            {
+                var methods = baseType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance
+                                                  | BindingFlags.NonPublic | BindingFlags.Public);
+
+                foreach (var method in methods)
+                {
+                    if (method.IsDefined(typeof(OnSerializingAttribute), false))
+                    {
+                        _onSerializing += CompileCallbackMethod(method);
+                    }
+
+                    if (method.IsDefined(typeof(OnSerializedAttribute), false))
+                    {
+                        _onSerialized += CompileCallbackMethod(method);
+                    }
+
+                    if (method.IsDefined(typeof(OnDeserializingAttribute), false))
+                    {
+                        _onDeserializing += CompileCallbackMethod(method);
+                    }
+
+                    if (method.IsDefined(typeof(OnDeserializedAttribute), false))
+                    {
+                        _onDeserialized += CompileCallbackMethod(method);
+                    }
+                }
+
+                baseType = baseType.BaseType;
+            }
+        }
+
+        /// <summary>
+        /// Gets the serialization ctor.
+        /// </summary>
+        public Func<SerializationInfo, StreamingContext, object> SerializationCtor
+        {
+            get
+            {
+                if (_serializationCtor == null)
+                    throw GetMissingCtorException();
+
+                return _serializationCtor;
+            }
+        }
+
+        /// <summary>
+        /// Gets the serialization ctor to call on an uninitialized instance.
+        /// </summary>
+        public Action<object, SerializationInfo, StreamingContext> SerializationCtorUninitialized
+        {
+            get
+            {
+                if (_serializationCtorUninitialized == null)
+                    throw GetMissingCtorException();
+
+                return _serializationCtorUninitialized;
+            }
+        }
+
+        /// <summary>
+        /// Gets the OnSerializing callback action.
+        /// </summary>
+        public Action<object, StreamingContext> OnSerializing
+        {
+            get { return _onSerializing; }
+        }
+
+        /// <summary>
+        /// Gets the OnSerialized callback action.
+        /// </summary>
+        public Action<object, StreamingContext> OnSerialized
+        {
+            get { return _onSerialized; }
+        }
+
+        /// <summary>
+        /// Gets the OnDeserializing callback action.
+        /// </summary>
+        public Action<object, StreamingContext> OnDeserializing
+        {
+            get { return _onDeserializing; }
+        }
+
+        /// <summary>
+        /// Gets the OnDeserialized callback action.
+        /// </summary>
+        public Action<object, StreamingContext> OnDeserialized
+        {
+            get { return _onDeserialized; }
+        }
+
+        /// <summary>
+        /// Gets the <see cref="DelegateTypeDescriptor" /> by type.
+        /// </summary>
+        public static SerializableTypeDescriptor Get(Type type)
+        {
+            SerializableTypeDescriptor result;
+
+            return Descriptors.TryGetValue(type, out result)
+                ? result
+                : Descriptors.GetOrAdd(type, t => new SerializableTypeDescriptor(t));
+        }
+                
+        /// <summary>
+        /// Gets the missing ctor exception.
+        /// </summary>
+        private SerializationException GetMissingCtorException()
+        {
+            // Same exception as .NET code throws.
+            return new SerializationException(
+                string.Format("The constructor to deserialize an object of type '{0}' was not found.", _type));
+        }
+                
+        /// <summary>
+        /// Checks that callback method has signature "void (StreamingContext)" and compiles it.
+        /// </summary>
+        private static Action<object, StreamingContext> CompileCallbackMethod(MethodInfo method)
+        {
+            Debug.Assert(method != null);
+            Debug.Assert(method.DeclaringType != null);
+
+            var parameters = method.GetParameters();
+
+            if (method.ReturnType != typeof(void) || parameters.Length != 1 ||
+                parameters[0].ParameterType != typeof(StreamingContext))
+            {
+                throw new TypeLoadException(
+                    string.Format("Type '{0}' in assembly '{1}' has method '{2}' with an incorrect " +
+                                  "signature for the serialization attribute that it is decorated with.",
+                        method.DeclaringType, method.DeclaringType.Assembly, method.Name));
+            }
+
+            return DelegateConverter.CompileFunc<Action<object, StreamingContext>>(
+                method.DeclaringType, method, new[] {typeof(StreamingContext)}, new[] {false, false});
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
index f79822d..c38cd95 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
@@ -157,7 +157,7 @@ namespace Apache.Ignite.Core.Impl
         {
             if (!string.IsNullOrEmpty(_cfg.SpringConfigUrl))
             {
-                // If there is a Spring config, use setting from Spring, 
+                // If there is a Spring config, use setting from Spring,
                 // since we ignore .NET config in legacy mode.
                 var cfg0 = GetConfiguration().BinaryConfiguration;
 
@@ -424,7 +424,7 @@ namespace Apache.Ignite.Core.Impl
 
             using (var stream = IgniteManager.Memory.Allocate().GetStream())
             {
-                var writer = Marshaller.StartMarshal(stream);
+                var writer = BinaryUtils.Marshaller.StartMarshal(stream);
 
                 configuration.Write(writer);
 
@@ -463,7 +463,8 @@ namespace Apache.Ignite.Core.Impl
 
             using (var stream = IgniteManager.Memory.Allocate().GetStream())
             {
-                var writer = Marshaller.StartMarshal(stream);
+                // Use system marshaller: full footers, always unregistered mode.
+                var writer = BinaryUtils.Marshaller.StartMarshal(stream);
 
                 configuration.Write(writer);
 
@@ -639,6 +640,8 @@ namespace Apache.Ignite.Core.Impl
 
                 writer.Write(initialValue);
 
+                Marshaller.FinishMarshal(writer);
+
                 var memPtr = stream.SynchronizeOutput();
 
                 return UU.ProcessorAtomicReference(_proc, name, memPtr, true);
@@ -654,7 +657,7 @@ namespace Apache.Ignite.Core.Impl
 
                 stream.SynchronizeInput();
 
-                return new IgniteConfiguration(_marsh.StartUnmarshal(stream), _cfg);
+                return new IgniteConfiguration(BinaryUtils.Marshaller.StartUnmarshal(stream), _cfg);
             }
         }
 
@@ -724,7 +727,7 @@ namespace Apache.Ignite.Core.Impl
 
             using (var stream = IgniteManager.Memory.Allocate().GetStream())
             {
-                var writer = Marshaller.StartMarshal(stream);
+                var writer = BinaryUtils.Marshaller.StartMarshal(stream);
 
                 configuration.Write(writer);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
index 8e44360..2fd020e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
@@ -118,6 +118,8 @@ namespace Apache.Ignite.Core.Impl.Services
             var writer = marsh.StartMarshal(stream);
 
             BinaryUtils.WriteInvocationResult(writer, invocationError == null, invocationError ?? methodResult);
+
+            marsh.FinishMarshal(writer);
         }
 
         /// <summary>
@@ -182,7 +184,7 @@ namespace Apache.Ignite.Core.Impl.Services
 
             var handler = BinarySystemHandlers.GetWriteHandler(type);
 
-            if (handler != null && !handler.IsSerializable)
+            if (handler != null)
                 return null;
 
             if (type.IsArray)

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
index 91ffabb..3028f08 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -376,7 +376,11 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
                 {
                     stream.Reset();
 
-                    _ignite.Marshaller.StartMarshal(stream).WriteObject(e);
+                    var writer = _ignite.Marshaller.StartMarshal(stream);
+
+                    writer.WriteObject(e);
+
+                    _ignite.Marshaller.FinishMarshal(writer);
 
                     return -1;
                 }
@@ -1164,7 +1168,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
         {
             using (var stream = IgniteManager.Memory.Get(memPtr).GetStream())
             {
-                var reader = _ignite.Marshaller.StartUnmarshal(stream);
+                var reader = BinaryUtils.Marshaller.StartUnmarshal(stream);
 
                 var func = reader.ReadObjectEx<IAffinityFunction>();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/ComputeExample.linq
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/ComputeExample.linq b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/ComputeExample.linq
index 2ed0493..6886ddb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/ComputeExample.linq
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/ComputeExample.linq
@@ -57,7 +57,6 @@ void Main()
 /// <summary>
 /// Closure counting characters in a string.
 /// </summary>
-[Serializable]
 public class CharacterCountClosure : IComputeFunc<string, int>
 {
 	/// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/PutGetExample.linq
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/PutGetExample.linq b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/PutGetExample.linq
index 7c77d09..ea396da 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/PutGetExample.linq
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/PutGetExample.linq
@@ -35,11 +35,8 @@ void Main()
 	// Force new LINQPad query process to reinit JVM
 	Util.NewProcess = true;
 	
-    // Configure cacheable types
-    var cfg = new IgniteConfiguration {BinaryConfiguration = new BinaryConfiguration(typeof(Organization))};
-
     // Start instance
-    using (var ignite = Ignition.Start(cfg))
+    using (var ignite = Ignition.Start())
     {
         // Create new cache
         var cache = ignite.GetOrCreateCache<int, Organization>("orgs");

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/QueryExample.linq
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/QueryExample.linq b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/QueryExample.linq
index 2a2454e..8a7dd10 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/QueryExample.linq
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/NuGet/LINQPad/QueryExample.linq
@@ -38,11 +38,8 @@ void Main()
 	// Force new LINQPad query process to reinit JVM
 	Util.NewProcess = true;
 	
-	// Configure cacheable types
-    var cfg = new IgniteConfiguration { BinaryConfiguration = new BinaryConfiguration(typeof(Organization), typeof(Person))	};
-
     // Start instance
-    using (var ignite = Ignition.Start(cfg))
+    using (var ignite = Ignition.Start())
     {
         // Create and populate organization cache
         var orgs = ignite.GetOrCreateCache<int, Organization>(new CacheConfiguration("orgs-sql", 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Linq/NuGet/LINQPad/QueryExample.linq
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/NuGet/LINQPad/QueryExample.linq b/modules/platforms/dotnet/Apache.Ignite.Linq/NuGet/LINQPad/QueryExample.linq
index 6a28f1f..fb44b12 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/NuGet/LINQPad/QueryExample.linq
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/NuGet/LINQPad/QueryExample.linq
@@ -39,11 +39,8 @@ void Main()
 	// Force new LINQPad query process to reinit JVM
 	Util.NewProcess = true;
 	
-	// Configure cacheable types
-    var cfg = new IgniteConfiguration { BinaryConfiguration = new BinaryConfiguration(typeof(Organization), typeof(Person))	};
-
 	// Start instance
-	using (var ignite = Ignition.Start(cfg))
+	using (var ignite = Ignition.Start())
 	{
 		// Create and populate organization cache
 		var orgs = ignite.GetOrCreateCache<int, Organization>(new CacheConfiguration("orgs-linq",

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config
index 13f0d86..e3bc79d 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config
@@ -27,22 +27,8 @@
     </runtime>
 
     <igniteConfiguration xmlns="http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection">
-        <binaryConfiguration>
-            <typeConfigurations>
-                <binaryTypeConfiguration typeName="Apache.Ignite.ExamplesDll.Binary.OrganizationType" isEnum="true" />
-            </typeConfigurations>
-            <types>
-                <string>Apache.Ignite.ExamplesDll.Binary.Account</string>
-                <string>Apache.Ignite.ExamplesDll.Binary.Address</string>
-                <string>Apache.Ignite.ExamplesDll.Binary.Employee</string>
-                <string>Apache.Ignite.ExamplesDll.Binary.EmployeeKey</string>
-                <string>Apache.Ignite.ExamplesDll.Binary.Organization</string>
-                <string>Apache.Ignite.ExamplesDll.Compute.AverageSalaryJob</string>
-            </types>
-        </binaryConfiguration>
-
         <atomicConfiguration atomicSequenceReserveSize="10" />
-        
+
         <discoverySpi type="TcpDiscoverySpi">
             <ipFinder type="TcpDiscoveryMulticastIpFinder">
                 <endpoints>


[3/5] ignite git commit: IGNITE-2703 .NET: Dynamic type registration

Posted by pt...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
index 19e68a6..56a17a3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
@@ -131,7 +131,7 @@ namespace Apache.Ignite.Core.Tests.Examples
 
                 var proc = new IgniteProcess(args.ToArray());
 
-                Assert.IsTrue(ignite.WaitTopology(2), 
+                Assert.IsTrue(ignite.WaitTopology(2),
                     string.Format("Standalone node failed to join topology: [{0}]", proc.GetInfo()));
 
                 Assert.IsTrue(proc.Alive, string.Format("Standalone node stopped unexpectedly: [{0}]",

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs
index 636e0fe..0aebd78 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs
@@ -49,28 +49,6 @@ namespace Apache.Ignite.Core.Tests
         private IIgnite _grid;
 
         /// <summary>
-        /// Test fixture set-up routine.
-        /// </summary>
-        [TestFixtureSetUp]
-        public void TestFixtureSetUp()
-        {
-            TestUtils.KillProcesses();
-
-            _grid = Ignition.Start(Configuration(SpringCfgPath));
-        }
-
-        /// <summary>
-        /// Test fixture tear-down routine.
-        /// </summary>
-        [TestFixtureTearDown]
-        public void TestFixtureTearDown()
-        {
-            Ignition.StopAll(true);
-
-            TestUtils.KillProcesses();
-        }
-
-        /// <summary>
         /// Set-up routine.
         /// </summary>
         [SetUp]
@@ -78,6 +56,8 @@ namespace Apache.Ignite.Core.Tests
         {
             TestUtils.KillProcesses();
 
+            _grid = Ignition.Start(Configuration(SpringCfgPath));
+
             Assert.IsTrue(_grid.WaitTopology(1));
 
             IgniteProcess.SaveConfigurationBackup();
@@ -89,6 +69,10 @@ namespace Apache.Ignite.Core.Tests
         [TearDown]
         public void TearDown()
         {
+            Ignition.StopAll(true);
+
+            TestUtils.KillProcesses();
+
             IgniteProcess.RestoreConfigurationBackup();
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/SerializationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/SerializationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/SerializationTest.cs
deleted file mode 100644
index 2812468..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/SerializationTest.cs
+++ /dev/null
@@ -1,240 +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.
- */
-
-namespace Apache.Ignite.Core.Tests
-{
-    using System;
-    using System.Collections.Generic;
-    using System.Linq;
-    using System.Reflection;
-    using System.Reflection.Emit;
-    using System.Runtime.Serialization;
-    using System.Xml;
-    using Apache.Ignite.Core.Cluster;
-    using Apache.Ignite.Core.Compute;
-    using Apache.Ignite.Core.Impl;
-    using NUnit.Framework;
-
-    /// <summary>
-    /// Tests for native serialization.
-    /// </summary>
-    public class SerializationTest
-    {
-        /** Grid name. */
-        private const string GridName = "SerializationTest";
-
-        /// <summary>
-        /// Set up routine.
-        /// </summary>
-        [TestFixtureSetUp]
-        public void SetUp()
-        {
-            var cfg = new IgniteConfiguration
-            {
-                IgniteInstanceName = GridName,
-                JvmClasspath = TestUtils.CreateTestClasspath(),
-                JvmOptions = TestUtils.TestJavaOptions(),
-                SpringConfigUrl = "config\\native-client-test-cache.xml"
-            };
-
-            Ignition.Start(cfg);
-        }
-
-        /// <summary>
-        /// Tear down routine.
-        /// </summary>
-        [TestFixtureTearDown]
-        public void TearDown()
-        {
-            Ignition.StopAll(true);
-        }
-
-        /// <summary>
-        /// Test complex file serialization.
-        /// </summary>
-        [Test]
-        public void TestSerializableXmlDoc()
-        {
-            var grid = Ignition.GetIgnite(GridName);
-            var cache = grid.GetCache<int, SerializableXmlDoc>("replicated");
-
-            var doc = new SerializableXmlDoc();
-
-            doc.LoadXml("<document><test1>val</test1><test2 attr=\"x\" /></document>");
-
-            for (var i = 0; i < 50; i++)
-            {
-                // Test cache
-                cache.Put(i, doc);
-
-                var resultDoc = cache.Get(i);
-
-                Assert.AreEqual(doc.OuterXml, resultDoc.OuterXml);
-
-                // Test task with document arg
-                CheckTask(grid, doc);
-            }
-        }
-
-        /// <summary>
-        /// Checks task execution.
-        /// </summary>
-        /// <param name="grid">Grid.</param>
-        /// <param name="arg">Task arg.</param>
-        private static void CheckTask(IIgnite grid, object arg)
-        {
-            var jobResult = grid.GetCompute().Execute(new CombineStringsTask(), arg);
-
-            var nodeCount = grid.GetCluster().GetNodes().Count;
-
-            var expectedRes =
-                CombineStringsTask.CombineStrings(Enumerable.Range(0, nodeCount).Select(x => arg.ToString()));
-
-            Assert.AreEqual(expectedRes, jobResult.InnerXml);
-        }
-
-        /// <summary>
-        /// Tests custom serialization binder.
-        /// </summary>
-        [Test]
-        public void TestSerializationBinder()
-        {
-            const int count = 50;
-
-            var cache = Ignition.GetIgnite(GridName).GetCache<int, object>("local");
-
-            // Put multiple objects from muliple same-named assemblies to cache
-            for (var i = 0; i < count; i++)
-            {
-                dynamic val = Activator.CreateInstance(GenerateDynamicType());
-                
-                val.Id = i;
-                val.Name = "Name_" + i;
-
-                cache.Put(i, val);
-            }
-
-            // Verify correct deserialization
-            for (var i = 0; i < count; i++)
-            {
-                dynamic val = cache.Get(i);
-
-                Assert.AreEqual(val.Id, i);
-                Assert.AreEqual(val.Name, "Name_" + i);
-            }
-        }
-
-        /// <summary>
-        /// Generates a Type in runtime, puts it into a dynamic assembly.
-        /// </summary>
-        /// <returns></returns>
-        public static Type GenerateDynamicType()
-        {
-            var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
-                new AssemblyName("GridSerializationTestDynamicAssembly"), AssemblyBuilderAccess.Run);
-
-            var moduleBuilder = asmBuilder.DefineDynamicModule("GridSerializationTestDynamicModule");
-
-            var typeBuilder = moduleBuilder.DefineType("GridSerializationTestDynamicType",
-                TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Serializable);
-
-            typeBuilder.DefineField("Id", typeof (int), FieldAttributes.Public);
-            
-            typeBuilder.DefineField("Name", typeof (string), FieldAttributes.Public);
-
-            return typeBuilder.CreateType();
-        }
-    }
-
-    [Serializable]
-    [DataContract]
-    public sealed class SerializableXmlDoc : XmlDocument, ISerializable
-    {
-        /// <summary>
-        /// Default ctor.
-        /// </summary>
-        public SerializableXmlDoc()
-        {
-            // No-op
-        }
-
-        /// <summary>
-        /// Serialization ctor.
-        /// </summary>
-        private SerializableXmlDoc(SerializationInfo info, StreamingContext context)
-        {
-            LoadXml(info.GetString("xmlDocument"));
-        }
-
-        /** <inheritdoc /> */
-        public void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            info.AddValue("xmlDocument", OuterXml, typeof(string));
-        }
-    }
-
-    [Serializable]
-    public class CombineStringsTask : IComputeTask<object, string, SerializableXmlDoc>
-    {
-        public IDictionary<IComputeJob<string>, IClusterNode> Map(IList<IClusterNode> subgrid, object arg)
-        {
-            return subgrid.ToDictionary(x => (IComputeJob<string>) new ToStringJob {Arg = arg}, x => x);
-        }
-
-        public ComputeJobResultPolicy OnResult(IComputeJobResult<string> res, IList<IComputeJobResult<string>> rcvd)
-        {
-            return ComputeJobResultPolicy.Wait;
-        }
-
-        public SerializableXmlDoc Reduce(IList<IComputeJobResult<string>> results)
-        {
-            var result = new SerializableXmlDoc();
-
-            result.LoadXml(CombineStrings(results.Select(x => x.Data)));
-
-            return result;
-        }
-
-        public static string CombineStrings(IEnumerable<string> strings)
-        {
-            var text = string.Concat(strings.Select(x => string.Format("<val>{0}</val>", x)));
-
-            return string.Format("<document>{0}</document>", text);
-        }
-    }
-
-    [Serializable]
-    public class ToStringJob : IComputeJob<string>
-    {
-        /// <summary>
-        /// Job argument.
-        /// </summary>
-        public object Arg { get; set; }
-
-        /** <inheritdoc /> */
-        public string Execute()
-        {
-            return Arg.ToString();
-        }
-
-        /** <inheritdoc /> */
-        public void Cancel()
-        {
-            // No-op.
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 dcb5393..eb6192d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
@@ -110,8 +110,13 @@ namespace Apache.Ignite.Core.Tests.Services
             Assert.IsNull(_svc.ObjProp);
 
             prx.ObjProp = new TestClass {Prop = "prop2"};
-            Assert.AreEqual("prop2", ((TestClass)prx.ObjProp).Prop);
-            Assert.AreEqual("prop2", ((TestClass)_svc.ObjProp).Prop);
+
+            var propVal = KeepBinary
+                ? ((IBinaryObject) prx.ObjProp).Deserialize<TestClass>().Prop
+                : ((TestClass) prx.ObjProp).Prop;
+
+            Assert.AreEqual("prop2", propVal);
+            Assert.AreEqual("prop2", ((TestClass) _svc.ObjProp).Prop);
         }
 
         /// <summary>
@@ -191,10 +196,19 @@ namespace Apache.Ignite.Core.Tests.Services
             var prx = GetProxy();
 
             var err = Assert.Throws<ServiceInvocationException>(prx.ExceptionMethod);
-            Assert.AreEqual("Expected exception", err.InnerException.Message);
 
-            var ex = Assert.Throws<ServiceInvocationException>(() => prx.CustomExceptionMethod());
-            Assert.IsTrue(ex.ToString().Contains("+CustomException"));
+            if (KeepBinary)
+            {
+                Assert.IsNotNull(err.BinaryCause);
+                Assert.AreEqual("Expected exception", err.BinaryCause.Deserialize<Exception>().Message);
+            }
+            else
+            {
+                Assert.IsNotNull(err.InnerException);
+                Assert.AreEqual("Expected exception", err.InnerException.Message);
+            }
+
+            Assert.Throws<ServiceInvocationException>(() => prx.CustomExceptionMethod());
         }
 
         [Test]
@@ -243,7 +257,7 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Creates the proxy.
         /// </summary>
-        protected T GetProxy<T>()
+        private T GetProxy<T>()
         {
             _svc = new TestIgniteService(Binary);
 
@@ -591,9 +605,19 @@ namespace Apache.Ignite.Core.Tests.Services
         /// <summary>
         /// Custom non-serializable exception.
         /// </summary>
-        private class CustomException : Exception
+        private class CustomException : Exception, IBinarizable
         {
-            
+            /** <inheritDoc /> */
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                throw new BinaryObjectException("Expected");
+            }
+
+            /** <inheritDoc /> */
+            public void ReadBinary(IBinaryReader reader)
+            {
+                throw new BinaryObjectException("Expected");
+            }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
index 8360bf1..0bb3b7f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
@@ -27,6 +27,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Static;
     using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Tests.Process;
     using NUnit.Framework;
@@ -370,5 +371,15 @@ namespace Apache.Ignite.Core.Tests
             Assert.IsTrue(proc.WaitForExit(15000));
             Assert.AreEqual(0, proc.ExitCode);
         }
+
+        /// <summary>
+        /// Serializes and deserializes back an object.
+        /// </summary>
+        public static T SerializeDeserialize<T>(T obj)
+        {
+            var marsh = new Marshaller(null) {CompactFooter = false};
+
+            return marsh.Unmarshal<T>(marsh.Marshal(obj));
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 333b9bc..2a174eb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -186,11 +186,12 @@
     <Compile Include="Common\IgniteFutureCancelledException.cs" />
     <Compile Include="Common\IgniteGuid.cs" />
     <Compile Include="Common\Package-Info.cs" />
-    <Compile Include="Impl\Binary\DateTimeSerializer.cs" />
     <Compile Include="Impl\Binary\IO\IBinaryStreamProcessor.cs" />
     <Compile Include="Impl\Binary\Metadata\BinaryField.cs" />
     <Compile Include="Impl\Binary\SerializableSerializer.cs" />
     <Compile Include="Impl\Binary\BinaryWriterExtensions.cs" />
+    <Compile Include="Impl\Binary\DeserializationCallbackProcessor.cs" />
+    <Compile Include="Impl\Binary\ReflectionUtils.cs" />
     <Compile Include="Cache\Affinity\AffinityFunctionBase.cs" />
     <Compile Include="Impl\Cache\Store\CacheStore.cs" />
     <Compile Include="Impl\Cache\Store\ICacheStoreInternal.cs" />
@@ -319,6 +320,7 @@
     <Compile Include="Impl\Common\CopyOnWriteConcurrentDictionary.cs" />
     <Compile Include="Impl\Common\DelegateConverter.cs" />
     <Compile Include="Impl\Common\DelegateTypeDescriptor.cs" />
+    <Compile Include="Impl\Common\SerializableTypeDescriptor.cs" />
     <Compile Include="Impl\Events\EventTypeConverter.cs" />
     <Compile Include="Impl\Common\Fnv1Hash.cs" />
     <Compile Include="Impl\Common\Future.cs" />
@@ -385,11 +387,9 @@
     <Compile Include="Impl\Messaging\MessageListenerHolder.cs" />
     <Compile Include="Impl\Messaging\Messaging.cs" />
     <Compile Include="Impl\NativeMethods.cs" />
-    <Compile Include="Impl\Binary\DateTimeHolder.cs" />
     <Compile Include="Impl\Binary\IO\IBinaryStream.cs" />
     <Compile Include="Impl\Binary\IO\BinaryStreamBase.cs" />
     <Compile Include="Impl\Binary\IO\BinaryHeapStream.cs" />
-    <Compile Include="Impl\Binary\IO\BinaryStreamAdapter.cs" />
     <Compile Include="Impl\Binary\IBinaryTypeDescriptor.cs" />
     <Compile Include="Impl\Binary\IBinaryWriteAware.cs" />
     <Compile Include="Impl\Binary\Metadata\IBinaryTypeHandler.cs" />
@@ -419,7 +419,6 @@
     <Compile Include="Impl\Binary\BinaryObject.cs" />
     <Compile Include="Impl\Binary\BinaryUtils.cs" />
     <Compile Include="Impl\Binary\BinaryWriter.cs" />
-    <Compile Include="Impl\Binary\SerializableObjectHolder.cs" />
     <Compile Include="Impl\Binary\Structure\BinaryStructure.cs" />
     <Compile Include="Impl\Binary\Structure\BinaryStructureEntry.cs" />
     <Compile Include="Impl\Binary\Structure\BinaryStructureJumpTable.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
index 29d2ee3..4f48ea5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
@@ -235,6 +235,9 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// <param name="reader">The reader.</param>
         internal CacheConfiguration(IBinaryRawReader reader)
         {
+            // Make sure system marshaller is used.
+            Debug.Assert(((BinaryReader) reader).Marshaller == BinaryUtils.Marshaller);
+
             AtomicityMode = (CacheAtomicityMode) reader.ReadInt();
             AtomicWriteOrderMode = (CacheAtomicWriteOrderMode) reader.ReadInt();
             Backups = reader.ReadInt();
@@ -297,6 +300,9 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// <param name="writer">The writer.</param>
         internal void Write(IBinaryRawWriter writer)
         {
+            // Make sure system marshaller is used.
+            Debug.Assert(((BinaryWriter) writer).Marshaller == BinaryUtils.Marshaller);
+
             writer.WriteInt((int) AtomicityMode);
             writer.WriteInt((int) AtomicWriteOrderMode);
             writer.WriteInt(Backups);
@@ -740,7 +746,7 @@ namespace Apache.Ignite.Core.Cache.Configuration
         public IAffinityFunction AffinityFunction { get; set; }
 
         /// <summary>
-        /// Gets or sets the factory for <see cref="IExpiryPolicy"/> to be used for all cache operations, 
+        /// Gets or sets the factory for <see cref="IExpiryPolicy"/> to be used for all cache operations,
         /// unless <see cref="ICache{TK,TV}.WithExpiryPolicy"/> is called.
         /// <para />
         /// Default is null, which means no expiration.

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index d3bd50c..28842e9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -159,7 +159,7 @@
 
             using (var stream = IgniteManager.Memory.Allocate().GetStream())
             {
-                var marsh = new Marshaller(configuration.BinaryConfiguration);
+                var marsh = BinaryUtils.Marshaller;
 
                 configuration.Write(marsh.StartMarshal(stream));
 
@@ -276,15 +276,26 @@
 
                 // Send only descriptors with non-null EqualityComparer to preserve old behavior where
                 // remote nodes can have no BinaryConfiguration.
-                var types = writer.Marshaller.GetUserTypeDescriptors().Where(x => x.EqualityComparer != null).ToList();
 
-                writer.WriteInt(types.Count);
+                if (BinaryConfiguration.TypeConfigurations != null &&
+                    BinaryConfiguration.TypeConfigurations.Any(x => x.EqualityComparer != null))
+                {
+                    // Create a new marshaller to reuse type name resolver mechanism.
+                    var types = new Marshaller(BinaryConfiguration).GetUserTypeDescriptors()
+                        .Where(x => x.EqualityComparer != null).ToList();
+
+                    writer.WriteInt(types.Count);
 
-                foreach (var type in types)
+                    foreach (var type in types)
+                    {
+                        writer.WriteString(BinaryUtils.SimpleTypeName(type.TypeName));
+                        writer.WriteBoolean(type.IsEnum);
+                        BinaryEqualityComparerSerializer.Write(writer, type.EqualityComparer);
+                    }
+                }
+                else
                 {
-                    writer.WriteString(BinaryUtils.SimpleTypeName(type.TypeName));
-                    writer.WriteBoolean(type.IsEnum);
-                    BinaryEqualityComparerSerializer.Write(writer, type.EqualityComparer);
+                    writer.WriteInt(0);
                 }
             }
             else

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 1190c14..f590794 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
@@ -359,11 +359,11 @@ namespace Apache.Ignite.Core
             if (cfg.BinaryConfiguration == null)
                 cfg.BinaryConfiguration = binaryCfg;
 
-            _startup.Marshaller = new Marshaller(cfg.BinaryConfiguration);
+            _startup.Marshaller = new Marshaller(cfg.BinaryConfiguration, log);
 
             // 3. Send configuration details to Java
             cfg.Validate(log);
-            cfg.Write(_startup.Marshaller.StartMarshal(outStream));
+            cfg.Write(BinaryUtils.Marshaller.StartMarshal(outStream));  // Use system marshaller.
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarizableSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarizableSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarizableSerializer.cs
index dcb261f..2273a93 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarizableSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarizableSerializer.cs
@@ -17,7 +17,6 @@
 
 namespace Apache.Ignite.Core.Impl.Binary
 {
-    using System;
     using System.Runtime.Serialization;
     using Apache.Ignite.Core.Binary;
 
@@ -39,9 +38,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /** <inheritdoc /> */
-        public T ReadBinary<T>(BinaryReader reader, Type type, int pos)
+        public T ReadBinary<T>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos)
         {
-            var obj = (T) FormatterServices.GetUninitializedObject(type);
+            var obj = (T) FormatterServices.GetUninitializedObject(desc.Type);
 
             reader.AddHandle(pos, obj);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
index d88e7a9..6a911ad 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
@@ -62,7 +62,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         private volatile BinaryStructure _readerTypeStructure = BinaryStructure.CreateEmpty();
         
         /** Type schema. */
-        private readonly BinaryObjectSchema _schema = new BinaryObjectSchema();
+        private readonly BinaryObjectSchema _schema;
 
         /** Enum flag. */
         private readonly bool _isEnum;
@@ -70,6 +70,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Comparer. */
         private readonly IBinaryEqualityComparer _equalityComparer;
 
+        /** Register flag. */
+        private readonly bool _isRegistered;
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -84,6 +87,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="affKeyFieldName">Affinity field key name.</param>
         /// <param name="isEnum">Enum flag.</param>
         /// <param name="comparer">Equality comparer.</param>
+        /// <param name="isRegistered">Registered flag.</param>
         public BinaryFullTypeDescriptor(
             Type type, 
             int typeId, 
@@ -94,8 +98,9 @@ namespace Apache.Ignite.Core.Impl.Binary
             IBinarySerializerInternal serializer, 
             bool keepDeserialized, 
             string affKeyFieldName,
-            bool isEnum, 
-            IEqualityComparer<IBinaryObject> comparer)
+            bool isEnum,
+            IEqualityComparer<IBinaryObject> comparer,
+            bool isRegistered = true)
         {
             _type = type;
             _typeId = typeId;
@@ -114,6 +119,38 @@ namespace Apache.Ignite.Core.Impl.Binary
                 throw new IgniteException(string.Format("Unsupported IEqualityComparer<IBinaryObject> " +
                                                         "implementation: {0}. Only predefined implementations " +
                                                         "are supported.", comparer.GetType()));
+
+            _isRegistered = isRegistered;
+            _schema = new BinaryObjectSchema();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryFullTypeDescriptor"/> class,
+        /// copying values from specified descriptor.
+        /// </summary>
+        /// <param name="desc">The descriptor to copy from.</param>
+        /// <param name="type">Type.</param>
+        /// <param name="serializer">Serializer.</param>
+        /// <param name="isRegistered">Registered flag.</param>
+        public BinaryFullTypeDescriptor(BinaryFullTypeDescriptor desc, Type type,
+            IBinarySerializerInternal serializer, bool isRegistered)
+        {
+            _type = type;
+            _typeId = desc._typeId;
+            _typeName = desc._typeName;
+            _userType = desc._userType;
+            _nameMapper = desc._nameMapper;
+            _idMapper = desc._idMapper;
+            _serializer = serializer;
+            _keepDeserialized = desc._keepDeserialized;
+            _affKeyFieldName = desc._affKeyFieldName;
+            _isEnum = desc._isEnum;
+            _equalityComparer = desc._equalityComparer;
+            _isRegistered = isRegistered;
+
+            _schema = desc._schema;
+            _writerTypeStruct = desc._writerTypeStruct;
+            _readerTypeStructure = desc._readerTypeStructure;
         }
 
         /// <summary>
@@ -237,5 +274,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             get { return _schema; }
         }
+
+        /** <inheritDoc /> */
+        public bool IsRegistered
+        {
+            get { return _isRegistered; }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
index e77cbae..e4fb10a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
@@ -676,6 +676,9 @@ namespace Apache.Ignite.Core.Impl.Binary
                                 ? BinaryObjectHeader.Flag.UserType
                                 : BinaryObjectHeader.Flag.None;
 
+                            if (inHeader.IsCustomDotNetType)
+                                flags |= BinaryObjectHeader.Flag.CustomDotNetType;
+
                             // Write raw data.
                             int outRawOff = outStream.Position - outStartPos;
 
@@ -936,8 +939,6 @@ namespace Apache.Ignite.Core.Impl.Binary
                 case BinaryUtils.TypeArrayString:
                 case BinaryUtils.TypeArrayGuid:
                 case BinaryUtils.TypeArrayTimestamp:
-                case BinaryUtils.TypeArrayEnum:
-                case BinaryUtils.TypeArray:
                     int arrLen = inStream.ReadInt();
 
                     outStream.WriteInt(arrLen);
@@ -947,6 +948,28 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                     break;
 
+                case BinaryUtils.TypeArrayEnum:
+                case BinaryUtils.TypeArray:
+                    int type = inStream.ReadInt();
+
+                    outStream.WriteInt(type);
+
+                    if (type == BinaryUtils.TypeUnregistered)
+                    {
+                        outStream.WriteByte(inStream.ReadByte());  // String header.
+
+                        BinaryUtils.WriteString(BinaryUtils.ReadString(inStream), outStream);  // String data.
+                    }
+
+                    arrLen = inStream.ReadInt();
+
+                    outStream.WriteInt(arrLen);
+
+                    for (int i = 0; i < arrLen; i++)
+                        Mutate0(ctx, inStream, outStream, false, EmptyVals);
+
+                    break;
+
                 case BinaryUtils.TypeCollection:
                     int colLen = inStream.ReadInt();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
index 636b177..0f0fafe 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
@@ -58,7 +58,10 @@ namespace Apache.Ignite.Core.Impl.Binary
             OffsetTwoBytes  = 0x10,
 
             /** Flag: compact footer, no field IDs. */
-            CompactFooter   = 0x20
+            CompactFooter   = 0x20,
+
+            /** Flag: raw data contains .NET type information. */
+            CustomDotNetType   = 0x40
         }
 
         /** Actual header layout */
@@ -164,6 +167,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Gets the custom .NET type flag.
+        /// </summary>
+        public bool IsCustomDotNetType
+        {
+            get { return (Flags & Flag.CustomDotNetType) == Flag.CustomDotNetType; }
+        }
+
+        /// <summary>
         /// Gets the size of the schema field offset (1, 2 or 4 bytes).
         /// </summary>
         public int SchemaFieldOffsetSize

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaSerializer.cs
index f1d2f6a..e2f9ea7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaSerializer.cs
@@ -249,6 +249,8 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             if (fieldIds == null)
             {
+                Debug.Assert(hdr.TypeId != BinaryUtils.TypeUnregistered);
+
                 if (marsh.Ignite != null)
                     fieldIds = marsh.Ignite.BinaryProcessor.GetSchema(hdr.TypeId, hdr.SchemaId);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
index f5bc370..555a042 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
@@ -17,6 +17,7 @@
 
 namespace Apache.Ignite.Core.Impl.Binary
 {
+    using System;
     using System.Collections.Generic;
     using System.Diagnostics;
     using Apache.Ignite.Core.Binary;
@@ -36,7 +37,9 @@ namespace Apache.Ignite.Core.Impl.Binary
             GetMeta = 1,
             GetAllMeta = 2,
             PutMeta = 3,
-            GetSchema = 4
+            GetSchema = 4,
+            RegisterType = 5,
+            GetType = 6
         }
 
         /// <summary>
@@ -101,7 +104,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// Put binary types to Grid.
         /// </summary>
         /// <param name="types">Binary types.</param>
-        internal void PutBinaryTypes(ICollection<BinaryType> types)
+        public void PutBinaryTypes(ICollection<BinaryType> types)
         {
             DoOutOp((int) Op.PutMeta, w =>
             {
@@ -153,5 +156,36 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             Marshaller.OnBinaryTypesSent(types);
         }
+
+        /// <summary>
+        /// Registers the type.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>True if registration succeeded; otherwise, false.</returns>
+        public bool RegisterType(int id, Type type)
+        {
+            Debug.Assert(type != null);
+            Debug.Assert(id != BinaryUtils.TypeUnregistered);
+
+            return DoOutOp((int) Op.RegisterType, w =>
+            {
+                w.WriteInt(id);
+                w.WriteString(type.AssemblyQualifiedName);
+            }) == True;
+        }
+
+        /// <summary>
+        /// Gets the type by id.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Type or null.</returns>
+        public Type GetType(int id)
+        {
+            var typeName = DoOutInOp((int) Op.GetType, w => w.WriteInt(id),
+                r => Marshaller.StartUnmarshal(r).ReadString());
+
+            return new TypeResolver().ResolveType(typeName);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
index 092eb72..49bab77 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
@@ -20,6 +20,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System;
     using System.Collections;
     using System.Collections.Generic;
+    using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
     using System.IO;
     using Apache.Ignite.Core.Binary;
@@ -79,6 +80,14 @@ namespace Apache.Ignite.Core.Impl.Binary
             get { return _marsh; }
         }
 
+        /// <summary>
+        /// Gets the mode.
+        /// </summary>
+        public BinaryMode Mode
+        {
+            get { return _mode; }
+        }
+
         /** <inheritdoc /> */
         public IBinaryRawReader GetRawReader()
         {
@@ -572,6 +581,14 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             throw new BinaryObjectException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']');
         }
+                
+        /// <summary>
+        /// Gets the flag indicating that there is custom type information in raw region.
+        /// </summary>
+        public bool GetCustomTypeDataFlag()
+        {
+            return _frame.Hdr.IsCustomDotNetType;
+        }
 
         /// <summary>
         /// Reads the binary object.
@@ -676,7 +693,9 @@ namespace Apache.Ignite.Core.Impl.Binary
                 else
                 {
                     // Find descriptor.
-                    var desc = _marsh.GetDescriptor(hdr.IsUserType, hdr.TypeId);
+                    var desc = hdr.TypeId == BinaryUtils.TypeUnregistered
+                        ? _marsh.GetDescriptor(Type.GetType(ReadString(), true))
+                        : _marsh.GetDescriptor(hdr.IsUserType, hdr.TypeId, true);
 
                     // Instantiate object. 
                     if (desc.Type == null)
@@ -707,7 +726,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                     _frame.Raw = false;
 
                     // Read object.
-                    var obj = desc.Serializer.ReadBinary<T>(this, desc.Type, pos);
+                    var obj = desc.Serializer.ReadBinary<T>(this, desc, pos);
 
                     _frame.Struct.UpdateReaderStructure();
 
@@ -758,8 +777,10 @@ namespace Apache.Ignite.Core.Impl.Binary
                 // Get schema from Java
                 var ignite = Marshaller.Ignite;
 
-                var schema = ignite == null 
-                    ? null 
+                Debug.Assert(typeId != BinaryUtils.TypeUnregistered);
+
+                var schema = ignite == null
+                    ? null
                     : ignite.BinaryProcessor.GetSchema(_frame.Hdr.TypeId, _frame.Hdr.SchemaId);
 
                 if (schema == null)
@@ -850,6 +871,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Seeks to raw data.
+        /// </summary>
+        internal void SeekToRaw()
+        {
+            Stream.Seek(_frame.Pos + _frame.Hdr.GetRawOffset(Stream, _frame.Pos), SeekOrigin.Begin);
+        }
+
+        /// <summary>
         /// Mark current output as raw. 
         /// </summary>
         private void MarkRaw()
@@ -858,7 +887,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             {
                 _frame.Raw = true;
 
-                Stream.Seek(_frame.Pos + _frame.Hdr.GetRawOffset(Stream, _frame.Pos), SeekOrigin.Begin);
+                SeekToRaw();
             }
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
index 795f8ac..907b465 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
@@ -722,7 +722,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             // Assign field value
             var targetParam = Expression.Parameter(typeof(object));
-            var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+            var targetParamConverted = Expression.Convert(targetParam, typeof(object));
             var assignExpr = Expression.Call(DelegateConverter.GetWriteFieldMethod(field), targetParamConverted, 
                 readExpr);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs
index c9fd3cc..e160559 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs
@@ -20,19 +20,17 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System;
     using System.Collections.Generic;
     using System.Diagnostics;
+    using System.Linq;
     using System.Reflection;
     using System.Runtime.Serialization;
     using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
     /// Internal reflective serializer.
     /// </summary>
     internal sealed class BinaryReflectiveSerializerInternal : IBinarySerializerInternal
     {
-        /** Cached binding flags. */
-        private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public |
-                                           BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
-
         /** Raw mode flag. */
         private readonly bool _rawMode;
 
@@ -42,6 +40,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Read actions to be performed. */
         private readonly BinaryReflectiveReadAction[] _rActions;
 
+        /** Callback type descriptor. */
+        private readonly SerializableTypeDescriptor _serializableDescriptor;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="BinaryReflectiveSerializer"/> class.
         /// </summary>
@@ -53,36 +54,64 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Initializes a new instance of the <see cref="BinaryReflectiveSerializer"/> class.
         /// </summary>
-        private BinaryReflectiveSerializerInternal(BinaryReflectiveWriteAction[] wActions, BinaryReflectiveReadAction[] rActions, bool raw)
+        private BinaryReflectiveSerializerInternal(BinaryReflectiveWriteAction[] wActions, 
+            BinaryReflectiveReadAction[] rActions, bool raw, SerializableTypeDescriptor serializableDescriptor)
         {
             Debug.Assert(wActions != null);
             Debug.Assert(rActions != null);
+            Debug.Assert(serializableDescriptor != null);
 
             _wActions = wActions;
             _rActions = rActions;
             _rawMode = raw;
+            _serializableDescriptor = serializableDescriptor;
         }
 
         /** <inheritdoc /> */
         void IBinarySerializerInternal.WriteBinary<T>(T obj, BinaryWriter writer)
         {
             Debug.Assert(_wActions != null);
+            Debug.Assert(writer != null);
+
+            var ctx = GetStreamingContext(writer);
+
+            _serializableDescriptor.OnSerializing(obj, ctx);
 
             foreach (var action in _wActions)
                 action(obj, writer);
+
+            _serializableDescriptor.OnSerialized(obj, ctx);
         }
 
         /** <inheritdoc /> */
-        T IBinarySerializerInternal.ReadBinary<T>(BinaryReader reader, Type type, int pos)
+        T IBinarySerializerInternal.ReadBinary<T>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos)
         {
             Debug.Assert(_rActions != null);
+            Debug.Assert(reader != null);
+            Debug.Assert(desc != null);
+
+            var obj = FormatterServices.GetUninitializedObject(desc.Type);
+
+            var ctx = GetStreamingContext(reader);
+
+            _serializableDescriptor.OnDeserializing(obj, ctx);
 
-            var obj = FormatterServices.GetUninitializedObject(type);
+            DeserializationCallbackProcessor.Push(obj);
 
-            reader.AddHandle(pos, obj);
+            try
+            {
+                reader.AddHandle(pos, obj);
+
+                foreach (var action in _rActions)
+                    action(obj, reader);
 
-            foreach (var action in _rActions)
-                action(obj, reader);
+                _serializableDescriptor.OnDeserialized(obj, ctx);
+
+            }
+            finally
+            {
+                DeserializationCallbackProcessor.Pop();
+            }
 
             return (T) obj;
         }
@@ -103,20 +132,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             Debug.Assert(_wActions == null && _rActions == null);
 
-            List<FieldInfo> fields = new List<FieldInfo>();
-
-            Type curType = type;
-
-            while (curType != null)
-            {
-                foreach (FieldInfo field in curType.GetFields(Flags))
-                {
-                    if (!field.IsNotSerialized)
-                        fields.Add(field);
-                }
-
-                curType = curType.BaseType;
-            }
+            var fields = ReflectionUtils.GetAllFields(type).Where(x => !x.IsNotSerialized).ToList();
 
             IDictionary<int, string> idMap = new Dictionary<int, string>();
 
@@ -152,7 +168,9 @@ namespace Apache.Ignite.Core.Impl.Binary
                 rActions[i] = readAction;
             }
 
-            return new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode);
+            var serDesc = SerializableTypeDescriptor.Get(type);
+
+            return new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode, serDesc);
         }
 
         /// <summary>
@@ -165,5 +183,21 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             return string.Compare(name1, name2, StringComparison.OrdinalIgnoreCase);
         }
+                
+        /// <summary>
+        /// Gets the streaming context.
+        /// </summary>
+        private static StreamingContext GetStreamingContext(IBinaryReader reader)
+        {
+            return new StreamingContext(StreamingContextStates.All, reader);
+        }
+
+        /// <summary>
+        /// Gets the streaming context.
+        /// </summary>
+        private static StreamingContext GetStreamingContext(IBinaryWriter writer)
+        {
+            return new StreamingContext(StreamingContextStates.All, writer);
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
index adba577..8c7e5e9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
@@ -19,6 +19,7 @@ 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.Structure;
 
@@ -51,10 +52,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="cfg">Configuration.</param>
         /// <param name="id">Type ID.</param>
-        public BinarySurrogateTypeDescriptor(BinaryConfiguration cfg, int id)
+        /// <param name="typeName">Name of the type.</param>
+        public BinarySurrogateTypeDescriptor(BinaryConfiguration cfg, int id, string typeName)
         {
+            Debug.Assert(cfg != null);
+
             _cfg = cfg;
             _id = id;
+            _name = typeName;
         }
 
         /// <summary>
@@ -170,5 +175,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             get { return _schema; }
         }
+
+        /** <inheritDoc /> */
+        public bool IsRegistered
+        {
+            get { return false; }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index beb2668..60bbb46 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -22,7 +22,6 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
-    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Common;
 
@@ -169,8 +168,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                 var handler = FindWriteHandler(t, out supportsHandles);
 
-                return handler == null ? null : new BinarySystemWriteHandler(handler, supportsHandles, 
-                    handler == WriteSerializable);
+                return handler == null ? null : new BinarySystemWriteHandler(handler, supportsHandles);
             });
         }
 
@@ -191,8 +189,6 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return WriteString;
             if (type == typeof(decimal))
                 return WriteDecimal;
-            if (type == typeof(DateTime))
-                return WriteDate;
             if (type == typeof(Guid))
                 return WriteGuid;
             if (type == typeof (BinaryObject))
@@ -251,16 +247,11 @@ namespace Apache.Ignite.Core.Impl.Binary
                 // Enums.
                 if (elemType.IsEnum || elemType == typeof(BinaryEnum))
                     return WriteEnumArray;
-                
+
                 // Object array.
-                if (elemType == typeof (object) || elemType == typeof (IBinaryObject) ||
-                    elemType == typeof (BinaryObject))
-                    return WriteArray;
+                return WriteArray;
             }
 
-            if (type.IsSerializable)
-                return WriteSerializable;
-
             return null;
         }
 
@@ -315,16 +306,6 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
         
         /// <summary>
-        /// Write date.
-        /// </summary>
-        /// <param name="ctx">Context.</param>
-        /// <param name="obj">Value.</param>
-        private static void WriteDate(BinaryWriter ctx, object obj)
-        {
-            ctx.Write(new DateTimeHolder((DateTime) obj));
-        }
-        
-        /// <summary>
         /// Write string.
         /// </summary>
         /// <param name="ctx">Context.</param>
@@ -535,21 +516,17 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayEnum);
 
-            var desc = ctx.Marshaller.GetDescriptor(obj.GetType());
-
-            int typeId = desc == null ? BinaryUtils.ObjTypeId : desc.TypeId;
-
-            BinaryUtils.WriteArray((Array)obj, ctx, typeId);
+            BinaryUtils.WriteArray((Array) obj, ctx);
         }
 
-        /**
-         * <summary>Write array.</summary>
-         */
+        /// <summary>
+        /// Writes the array.
+        /// </summary>
         private static void WriteArray(BinaryWriter ctx, object obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArray);
 
-            BinaryUtils.WriteArray((Array)obj, ctx);
+            BinaryUtils.WriteArray((Array) obj, ctx);
         }
 
         /**
@@ -603,16 +580,6 @@ namespace Apache.Ignite.Core.Impl.Binary
             ctx.WriteInt(binEnum.EnumValue);
         }
 
-        /// <summary>
-        /// Writes serializable.
-        /// </summary>
-        /// <param name="writer">The writer.</param>
-        /// <param name="o">The object.</param>
-        private static void WriteSerializable(BinaryWriter writer, object o)
-        {
-            writer.Write(new SerializableObjectHolder(o));
-        }
-
         /**
          * <summary>Read enum array.</summary>
          */
@@ -623,13 +590,36 @@ namespace Apache.Ignite.Core.Impl.Binary
             return BinaryUtils.ReadTypedArray(ctx, true, elemType);
         }
 
-        /**
-         * <summary>Read array.</summary>
-         */
+        /// <summary>
+        /// Reads the array.
+        /// </summary>
         private static object ReadArray(BinaryReader ctx, Type type)
         {
-            var elemType = type.GetElementType() ?? typeof(object);
+            var elemType = type.GetElementType();
+
+            if (elemType == null)
+            {
+                if (ctx.Mode == BinaryMode.ForceBinary)
+                {
+                    // Forced binary mode: use object because primitives are not represented as IBinaryObject.
+                    elemType = typeof(object);
+                }
+                else
+                {
+                    // Infer element type from typeId.
+                    var typeId = ctx.ReadInt();
+
+                    if (typeId != BinaryUtils.ObjTypeId)
+                    {
+                        elemType = ctx.Marshaller.GetDescriptor(true, typeId, true).Type;
+                    }
+
+                    return BinaryUtils.ReadTypedArray(ctx, false, elemType ?? typeof(object));
+                }
+            }
 
+            // Element type is known, no need to check typeId.
+            // In case of incompatible types we'll get exception either way.
             return BinaryUtils.ReadTypedArray(ctx, true, elemType);
         }
 
@@ -798,23 +788,17 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** */
         private readonly bool _supportsHandles;
 
-        /** */
-        private readonly bool _isSerializable;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="BinarySystemWriteHandler" /> class.
         /// </summary>
         /// <param name="writeAction">The write action.</param>
         /// <param name="supportsHandles">Handles flag.</param>
-        /// <param name="isSerializable">Determines whether this handler writes objects as serializable.</param>
-        public BinarySystemWriteHandler(Action<BinaryWriter, object> writeAction, bool supportsHandles, 
-            bool isSerializable)
+        public BinarySystemWriteHandler(Action<BinaryWriter, object> writeAction, bool supportsHandles)
         {
             Debug.Assert(writeAction != null);
 
             _writeAction = writeAction;
             _supportsHandles = supportsHandles;
-            _isSerializable = isSerializable;
         }
 
         /// <summary>
@@ -834,13 +818,5 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             get { return _supportsHandles; }
         }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this handler writes objects as serializable
-        /// </summary>
-        public bool IsSerializable
-        {
-            get { return _isSerializable; }
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemTypeSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemTypeSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemTypeSerializer.cs
index b416848..1ea1f0b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemTypeSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemTypeSerializer.cs
@@ -48,7 +48,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /** <inheritDoc /> */
-        public T1 ReadBinary<T1>(BinaryReader reader, Type type, int pos)
+        public T1 ReadBinary<T1>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos)
         {
             return TypeCaster<T1>.Cast(_ctor(reader));
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/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 2050f67..bb58ea5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -52,6 +52,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Type: object. */
         public const byte TypeObject = HdrFull;
 
+        /** Type: unregistered. */
+        public const byte TypeUnregistered = 0;
+
         /** Type: unsigned byte. */
         public const byte TypeByte = 1;
 
@@ -166,12 +169,6 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Type: Compute job wrapper. */
         public const byte TypeComputeJobWrapper = 86;
 
-        /** Type: Serializable wrapper. */
-        public const byte TypeSerializableHolder = 87;
-
-        /** Type: DateTime wrapper. */
-        public const byte TypeDateTimeHolder = 93;
-
         /** Type: action wrapper. */
         public const byte TypeComputeActionJob = 88;
 
@@ -235,8 +232,12 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Bindig flags for static search. */
         private const BindingFlags BindFlagsStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
 
-        /** Default poratble marshaller. */
-        private static readonly Marshaller Marsh = new Marshaller(null);
+        /** System marshaller. */
+        private static readonly Marshaller Marsh = new Marshaller(
+            new BinaryConfiguration {CompactFooter = false})
+        {
+            RegistrationDisabled = true
+        };
 
         /** Method: ReadArray. */
         public static readonly MethodInfo MtdhReadArray =
@@ -1265,14 +1266,31 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="val">Array.</param>
         /// <param name="ctx">Write context.</param>
-        /// <param name="elementType">Type of the array element.</param>
-        public static void WriteArray(Array val, BinaryWriter ctx, int elementType = ObjTypeId)
+        /// <param name="elemTypeId">The element type id.</param>
+        public static void WriteArray(Array val, BinaryWriter ctx, int? elemTypeId = null)
         {
             Debug.Assert(val != null && ctx != null);
 
             IBinaryStream stream = ctx.Stream;
 
-            stream.WriteInt(elementType);
+            if (elemTypeId != null && elemTypeId != TypeUnregistered)
+            {
+                stream.WriteInt(elemTypeId.Value);
+            }
+            else
+            {
+                var elemType = val.GetType().GetElementType();
+
+                var typeId = ObjTypeId;
+
+                if (elemType != typeof(object))
+                    typeId = ctx.Marshaller.GetDescriptor(elemType).TypeId;
+
+                stream.WriteInt(typeId);
+
+                if (typeId == TypeUnregistered)
+                    ctx.WriteString(elemType.FullName);
+            }
 
             stream.WriteInt(val.Length);
 
@@ -1313,7 +1331,12 @@ namespace Apache.Ignite.Core.Impl.Binary
             var pos = stream.Position;
 
             if (typed)
-                stream.ReadInt();
+            {
+                int typeId = stream.ReadInt();
+
+                if (typeId == TypeUnregistered)
+                    ctx.ReadString();
+            }
 
             int len = stream.ReadInt();
 
@@ -1538,7 +1561,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             {
                 var desc = marshaller.GetDescriptor(enumType);
 
-                return desc == null ? ObjTypeId : desc.TypeId;
+                return desc.TypeId;
             }
 
             throw new BinaryObjectException("Only Int32 underlying type is supported for enums: " +
@@ -1559,10 +1582,10 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return TypeCaster<T>.Cast(value);
 
             // All enums are user types
-            var desc = marsh.GetDescriptor(true, typeId);
+            var desc = marsh.GetDescriptor(true, typeId, true);
 
             if (desc == null || desc.Type == null)
-                throw new BinaryObjectException("Unknown enum type id: " + typeId);
+                return TypeCaster<T>.Cast(value);
 
             return (T)Enum.ToObject(desc.Type, value);
         }
@@ -1743,7 +1766,6 @@ namespace Apache.Ignite.Core.Impl.Binary
         public static int FieldId(int typeId, string fieldName, IBinaryNameMapper nameMapper,
             IBinaryIdMapper idMapper)
         {
-            Debug.Assert(typeId != 0);
             Debug.Assert(fieldName != null);
 
             fieldName = ConvertFieldName(fieldName, nameMapper);

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index 0490ec8..1388d16 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -48,27 +48,12 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Metadatas collected during this write session. */
         private IDictionary<int, BinaryType> _metas;
 
-        /** Current type ID. */
-        private int _curTypeId;
-
-        /** Current name converter */
-        private IBinaryNameMapper _curConverter;
-
-        /** Current mapper. */
-        private IBinaryIdMapper _curMapper;
-        
-        /** Current object start position. */
-        private int _curPos;
-
-        /** Current raw position. */
-        private int _curRawPos;
+        /** Current stack frame. */
+        private Frame _frame;
 
         /** Whether we are currently detaching an object. */
         private bool _detaching;
 
-        /** Current type structure tracker, */
-        private BinaryStructureTracker _curStruct;
-
         /** Schema holder. */
         private readonly BinaryObjectSchemaHolder _schema = BinaryObjectSchemaHolder.Current;
 
@@ -150,7 +135,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="val">Byte value.</param>
         public void WriteByte(string fieldName, byte val)
         {
-            WriteFieldId(fieldName, BinaryUtils.TypeBool);
+            WriteFieldId(fieldName, BinaryUtils.TypeByte);
             WriteByteField(val);
         }
 
@@ -875,23 +860,13 @@ namespace Apache.Ignite.Core.Impl.Binary
             {
                 var desc = _marsh.GetDescriptor(val.GetType());
 
-                if (desc != null)
-                {
-                    var metaHnd = _marsh.GetBinaryTypeHandler(desc);
+                var metaHnd = _marsh.GetBinaryTypeHandler(desc);
 
-                    _stream.WriteByte(BinaryUtils.TypeEnum);
+                _stream.WriteByte(BinaryUtils.TypeEnum);
 
-                    BinaryUtils.WriteEnum(this, val);
+                BinaryUtils.WriteEnum(this, val);
 
-                    SaveMetadata(desc, metaHnd.OnObjectWriteFinished());
-                }
-                else
-                {
-                    // Unregistered enum, write with object type id.
-                    _stream.WriteByte(BinaryUtils.TypeEnum);
-                    _stream.WriteInt(BinaryUtils.ObjTypeId);
-                    _stream.WriteInt(TypeCaster<int>.Cast(val));
-                }
+                SaveMetadata(desc, metaHnd.OnObjectWriteFinished());
             }
         }
 
@@ -931,9 +906,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             {
                 _stream.WriteByte(BinaryUtils.TypeArrayEnum);
 
-                var elTypeId = elementTypeId ?? BinaryUtils.GetEnumTypeId(val.GetType().GetElementType(), Marshaller);
-
-                BinaryUtils.WriteArray(val, this, elTypeId);
+                BinaryUtils.WriteArray(val, this, elementTypeId);
             }
         }
 
@@ -1089,8 +1062,8 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </returns>
         public IBinaryRawWriter GetRawWriter()
         {
-            if (_curRawPos == 0)
-                _curRawPos = _stream.Position;
+            if (_frame.RawPos == 0)
+                _frame.RawPos = _stream.Position;
 
             return this;
         }
@@ -1159,121 +1132,122 @@ namespace Apache.Ignite.Core.Impl.Binary
             if (WriteBuilderSpecials(obj))
                 return;
 
-            // Suppose that we faced normal object and perform descriptor lookup.
-            IBinaryTypeDescriptor desc = _marsh.GetDescriptor(type);
+            // Are we dealing with a well-known type?
+            var handler = BinarySystemHandlers.GetWriteHandler(type);
 
-            if (desc != null)
+            if (handler != null)
             {
-                // Writing normal object.
-                var pos = _stream.Position;
-
-                // Dealing with handles.
-                if (desc.Serializer.SupportsHandles && WriteHandle(pos, obj))
+                if (handler.SupportsHandles && WriteHandle(_stream.Position, obj))
                     return;
 
-                // Skip header length as not everything is known now
-                _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current);
-
-                // Preserve old frame.
-                int oldTypeId = _curTypeId;
-                IBinaryNameMapper oldConverter = _curConverter;
-                IBinaryIdMapper oldMapper = _curMapper;
-                int oldRawPos = _curRawPos;
-                var oldPos = _curPos;
-                
-                var oldStruct = _curStruct;
+                handler.Write(this, obj);
 
-                // Push new frame.
-                _curTypeId = desc.TypeId;
-                _curConverter = desc.NameMapper;
-                _curMapper = desc.IdMapper;
-                _curRawPos = 0;
-                _curPos = pos;
+                return;
+            }
 
-                _curStruct = new BinaryStructureTracker(desc, desc.WriterTypeStructure);
-                var schemaIdx = _schema.PushSchema();
+            // Suppose that we faced normal object and perform descriptor lookup.
+            var desc = _marsh.GetDescriptor(type);
 
-                try
-                {
-                    // Write object fields.
-                    desc.Serializer.WriteBinary(obj, this);
-                    var dataEnd = _stream.Position;
+            // Writing normal object.
+            var pos = _stream.Position;
 
-                    // Write schema
-                    var schemaOffset = dataEnd - pos;
+            // Dealing with handles.
+            if (desc.Serializer.SupportsHandles && WriteHandle(pos, obj))
+                return;
 
-                    int schemaId;
-                    
-                    var flags = desc.UserType
-                        ? BinaryObjectHeader.Flag.UserType
-                        : BinaryObjectHeader.Flag.None;
+            // Skip header length as not everything is known now
+            _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current);
 
-                    if (Marshaller.CompactFooter && desc.UserType)
-                        flags |= BinaryObjectHeader.Flag.CompactFooter;
+            // Write type name for unregistered types
+            if (!desc.IsRegistered)
+                WriteString(type.AssemblyQualifiedName);
 
-                    var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags);
+            var headerSize = _stream.Position - pos;
 
-                    if (hasSchema)
-                    {
-                        flags |= BinaryObjectHeader.Flag.HasSchema;
+            // Preserve old frame.
+            var oldFrame = _frame;
 
-                        // Calculate and write header.
-                        if (_curRawPos > 0)
-                            _stream.WriteInt(_curRawPos - pos); // raw offset is in the last 4 bytes
+            // Push new frame.
+            _frame.RawPos = 0;
+            _frame.Pos = pos;
+            _frame.Struct = new BinaryStructureTracker(desc, desc.WriterTypeStructure);
+            _frame.HasCustomTypeData = false;
 
-                        // Update schema in type descriptor
-                        if (desc.Schema.Get(schemaId) == null)
-                            desc.Schema.Add(schemaId, _schema.GetSchema(schemaIdx));
-                    }
-                    else
-                        schemaOffset = BinaryObjectHeader.Size;
+            var schemaIdx = _schema.PushSchema();
 
-                    if (_curRawPos > 0)
-                        flags |= BinaryObjectHeader.Flag.HasRaw;
+            try
+            {
+                // Write object fields.
+                desc.Serializer.WriteBinary(obj, this);
+                var dataEnd = _stream.Position;
 
-                    var len = _stream.Position - pos;
+                // Write schema
+                var schemaOffset = dataEnd - pos;
 
-                    var comparer = BinaryUtils.GetEqualityComparer(desc);
+                int schemaId;
+                    
+                var flags = desc.UserType
+                    ? BinaryObjectHeader.Flag.UserType
+                    : BinaryObjectHeader.Flag.None;
 
-                    var hashCode = comparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size,
-                            dataEnd - pos - BinaryObjectHeader.Size, _schema, schemaIdx, _marsh, desc);
+                if (_frame.HasCustomTypeData)
+                    flags |= BinaryObjectHeader.Flag.CustomDotNetType;
 
-                    var header = new BinaryObjectHeader(desc.TypeId, hashCode, len, schemaId, schemaOffset, flags);
+                if (Marshaller.CompactFooter && desc.UserType)
+                    flags |= BinaryObjectHeader.Flag.CompactFooter;
 
-                    BinaryObjectHeader.Write(header, _stream, pos);
+                var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags);
 
-                    Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end
-                }
-                finally
+                if (hasSchema)
                 {
-                    _schema.PopSchema(schemaIdx);
+                    flags |= BinaryObjectHeader.Flag.HasSchema;
+
+                    // Calculate and write header.
+                    if (_frame.RawPos > 0)
+                        _stream.WriteInt(_frame.RawPos - pos); // raw offset is in the last 4 bytes
+
+                    // Update schema in type descriptor
+                    if (desc.Schema.Get(schemaId) == null)
+                        desc.Schema.Add(schemaId, _schema.GetSchema(schemaIdx));
                 }
+                else
+                    schemaOffset = headerSize;
+
+                if (_frame.RawPos > 0)
+                    flags |= BinaryObjectHeader.Flag.HasRaw;
+
+                var len = _stream.Position - pos;
+
+                    var comparer = BinaryUtils.GetEqualityComparer(desc);
+
+                    var hashCode = comparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size,
+                            dataEnd - pos - BinaryObjectHeader.Size, _schema, schemaIdx, _marsh, desc);
 
-                // Apply structure updates if any.
-                _curStruct.UpdateWriterStructure(this);
+                    var header = new BinaryObjectHeader(desc.IsRegistered ? desc.TypeId : BinaryUtils.TypeUnregistered,
+                        hashCode, len, schemaId, schemaOffset, flags);
 
-                // Restore old frame.
-                _curTypeId = oldTypeId;
-                _curConverter = oldConverter;
-                _curMapper = oldMapper;
-                _curRawPos = oldRawPos;
-                _curPos = oldPos;
+                BinaryObjectHeader.Write(header, _stream, pos);
 
-                _curStruct = oldStruct;
+                Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end
             }
-            else
+            finally
             {
-                // Are we dealing with a well-known type?
-                var handler = BinarySystemHandlers.GetWriteHandler(type);
+                _schema.PopSchema(schemaIdx);
+            }
 
-                if (handler == null) // We did our best, object cannot be marshalled.
-                    throw BinaryUtils.GetUnsupportedTypeException(type, obj);
-                
-                if (handler.SupportsHandles && WriteHandle(_stream.Position, obj))
-                    return;
+            // Apply structure updates if any.
+            _frame.Struct.UpdateWriterStructure(this);
 
-                handler.Write(this, obj);
-            }
+            // Restore old frame.
+            _frame = oldFrame;
+        }
+
+        /// <summary>
+        /// Marks current object with a custom type data flag.
+        /// </summary>
+        public void SetCustomTypeDataFlag(bool hasCustomTypeData)
+        {
+            _frame.HasCustomTypeData = hasCustomTypeData;
         }
 
         /// <summary>
@@ -1455,12 +1429,12 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="fieldTypeId">Field type ID.</param>
         private void WriteFieldId(string fieldName, byte fieldTypeId)
         {
-            if (_curRawPos != 0)
+            if (_frame.RawPos != 0)
                 throw new BinaryObjectException("Cannot write named fields after raw data is written.");
 
-            var fieldId = _curStruct.GetFieldId(fieldName, fieldTypeId);
+            var fieldId = _frame.Struct.GetFieldId(fieldName, fieldTypeId);
 
-            _schema.PushField(fieldId, _stream.Position - _curPos);
+            _schema.PushField(fieldId, _stream.Position - _frame.Pos);
         }
 
         /// <summary>
@@ -1489,5 +1463,23 @@ namespace Apache.Ignite.Core.Impl.Binary
                     _metas[desc.TypeId] = new BinaryType(desc, fields);
             }
         }
+
+        /// <summary>
+        /// Stores current writer stack frame.
+        /// </summary>
+        private struct Frame
+        {
+            /** Current object start position. */
+            public int Pos;
+
+            /** Current raw position. */
+            public int RawPos;
+
+            /** Current type structure tracker. */
+            public BinaryStructureTracker Struct;
+
+            /** Custom type data. */
+            public bool HasCustomTypeData;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
deleted file mode 100644
index 21c56a9..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
+++ /dev/null
@@ -1,101 +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.
- */
-
-namespace Apache.Ignite.Core.Impl.Binary
-{
-    using System;
-    using System.Diagnostics;
-    using Apache.Ignite.Core.Binary;
-
-    /// <summary>
-    /// Wraps DateTime item in a binarizable.
-    /// </summary>
-    internal struct DateTimeHolder : IBinaryWriteAware
-    {
-        /** */
-        private readonly DateTime _item;
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="item">The item to wrap.</param>
-        public DateTimeHolder(DateTime item)
-        {
-            _item = item;
-        }
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="reader">The reader.</param>
-        public DateTimeHolder(IBinaryRawReader reader)
-        {
-            Debug.Assert(reader != null);
-
-            _item = DateTime.FromBinary(reader.ReadLong());
-        }
-
-        /// <summary>
-        /// Gets the item to wrap.
-        /// </summary>
-        public DateTime Item
-        {
-            get { return _item; }
-        }
-
-        /** <inheritDoc /> */
-        public void WriteBinary(IBinaryWriter writer)
-        {
-            Debug.Assert(writer != null);
-
-            writer.GetRawWriter().WriteLong(_item.ToBinary());
-        }
-
-        /** <inheritDoc /> */
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            return obj is DateTimeHolder && Equals((DateTimeHolder) obj);
-        }
-
-        /** <inheritDoc /> */
-        public override int GetHashCode()
-        {
-            return _item.GetHashCode();
-        }
-
-        /** <inheritDoc /> */
-        public static bool operator ==(DateTimeHolder left, DateTimeHolder right)
-        {
-            return left.Equals(right);
-        }
-
-        /** <inheritDoc /> */
-        public static bool operator !=(DateTimeHolder left, DateTimeHolder right)
-        {
-            return !left.Equals(right);
-        }
-
-        /// <summary>
-        /// Checks equality.
-        /// </summary>
-        private bool Equals(DateTimeHolder other)
-        {
-            return _item.Equals(other._item);
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeSerializer.cs
deleted file mode 100644
index bea7d58..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeSerializer.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-\ufeff/*
- * 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 Apache.Ignite.Core.Impl.Common;
-
-    /// <summary>
-    /// DateTime serializer.
-    /// </summary>
-    internal class DateTimeSerializer : IBinarySerializerInternal
-    {
-        /** <inheritdoc /> */
-        public void WriteBinary<T>(T obj, BinaryWriter writer)
-        {
-            TypeCaster<DateTimeHolder>.Cast(obj).WriteBinary(writer);
-        }
-
-        /** <inheritdoc /> */
-        public T ReadBinary<T>(BinaryReader reader, Type type, int pos)
-        {
-            var holder = new DateTimeHolder(reader);
-
-            return TypeCaster<T>.Cast(holder.Item);
-        }
-
-        /** <inheritdoc /> */
-        public bool SupportsHandles
-        {
-            get { return false; }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DeserializationCallbackProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DeserializationCallbackProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DeserializationCallbackProcessor.cs
new file mode 100644
index 0000000..3b21946
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DeserializationCallbackProcessor.cs
@@ -0,0 +1,102 @@
+\ufeff/*
+ * 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.Collections.Generic;
+    using System.Runtime.Serialization;
+    using System.Threading;
+
+    /// <summary>
+    /// Tracks object graph and invokes <see cref="IDeserializationCallback" />.
+    /// <para />
+    /// <see cref="IDeserializationCallback.OnDeserialization" /> must be called after entire object graph has been
+    /// deserialized. We preserve all objects in a thread-local list and invoke callbacks once all objects
+    /// are fully deserialized.
+    /// </summary>
+    internal static class DeserializationCallbackProcessor
+    {
+        /// <summary>
+        /// Object graph for current thread.
+        /// </summary>
+        private static readonly ThreadLocal<ObjectGraph> Graph 
+            = new ThreadLocal<ObjectGraph>(() => new ObjectGraph());
+
+        /// <summary>
+        /// Register an object for deserialization callback.
+        /// </summary>
+        /// <param name="obj">The object.</param>
+        /// <returns>Id of the object.</returns>
+        public static void Push(object obj)
+        {
+            var graph = Graph.Value;
+
+            graph.Depth++;
+
+            var cb = obj as IDeserializationCallback;
+
+            if (cb != null)
+            {
+                graph.Objects.Add(cb);
+            }
+        }
+
+        /// <summary>
+        /// Called when deserialization of an object has completed.
+        /// When Pop() has been called for all registered objects, all callbacks are invoked.
+        /// </summary>
+        public static void Pop()
+        {
+            var graph = Graph.Value;
+
+            graph.Depth--;
+
+            if (graph.Depth == 0)
+            {
+                // Entire graph has been deserialized: invoke callbacks in direct order (like BinaryFormatter does).
+                foreach (var obj in graph.Objects)
+                {
+                    obj.OnDeserialization(null);
+                }
+
+                graph.Objects.Clear();
+            }
+        }
+
+        /// <summary>
+        /// Object graph.
+        /// </summary>
+        private class ObjectGraph
+        {
+            /** */
+            private readonly List<IDeserializationCallback> _objects = new List<IDeserializationCallback>();
+
+            /// <summary>
+            /// Gets or sets the depth.
+            /// </summary>
+            public int Depth { get; set; }
+
+            /// <summary>
+            /// Gets the objects.
+            /// </summary>
+            public List<IDeserializationCallback> Objects
+            {
+                get { return _objects; }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinarySerializerInternal.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinarySerializerInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinarySerializerInternal.cs
index 58844d6..b775999 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinarySerializerInternal.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinarySerializerInternal.cs
@@ -17,8 +17,6 @@
 
 namespace Apache.Ignite.Core.Impl.Binary
 {
-    using System;
-
     /// <summary>
     /// Internal generic serializer interface.
     /// </summary>
@@ -32,7 +30,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Read binary object.
         /// </summary>
-        T ReadBinary<T>(BinaryReader reader, Type type, int pos);
+        T ReadBinary<T>(BinaryReader reader, IBinaryTypeDescriptor desc, int pos);
 
         /// <summary>
         /// Gets a value indicating whether this serializer supports handles.

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
index 6c7e360..6bec70f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
@@ -112,5 +112,13 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// Gets the schema.
         /// </summary>
         BinaryObjectSchema Schema { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether this descriptor is registered in the cluster.
+        /// </summary>
+        /// <value>
+        /// <c>true</c> if this instance is registered; otherwise, <c>false</c>.
+        /// </value>
+        bool IsRegistered { get; }
     }
 }