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

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

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; }
     }
 }