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:45 UTC

[11/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/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>