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

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

IGNITE-2703 .NET: Dynamic type registration

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


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

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

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


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

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

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

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

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

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
new file mode 100644
index 0000000..3f37833
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestDynamicRegistration.cs
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Binary builder self test with dynamic type registration.
+    /// </summary>
+    public class BinaryBuilderSelfTestDynamicRegistration : BinaryBuilderSelfTest
+    {
+        /** <inheritdoc /> */
+        protected override ICollection<BinaryTypeConfiguration> GetTypeConfigurations()
+        {
+            // The only type to be registered is TestEnumRegistered,
+            // because unregistered enums are handled differently.
+
+            return new []
+            {
+                new BinaryTypeConfiguration(typeof(TestEnumRegistered))
+            };
+        }
+    }
+}
\ No newline at end of file

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

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

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

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
new file mode 100644
index 0000000..9af5c35
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/JavaBinaryInteropTest.cs
@@ -0,0 +1,182 @@
+\ufeff/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Linq;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests binary type interoperability between .NET and Java code.
+    /// </summary>
+    public class JavaBinaryInteropTest
+    {
+        /// <summary>
+        /// Tests that all kinds of values from .NET can be handled properly on Java side.
+        /// </summary>
+        [Test]
+        public void TestValueRoundtrip()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                ignite.CreateCache<int, object>((string) null);
+
+                // Basic types.
+                // Types which map directly to Java are returned properly when retrieved as object.
+                // Non-directly mapped types are returned as their counterpart.
+                CheckValueCaching((char) 128);
+                CheckValueCaching((byte) 255);
+                CheckValueCaching((sbyte) -10, false);
+                CheckValueCaching((short) -32000);
+                CheckValueCaching((ushort) 65350, false);
+                CheckValueCaching(int.MinValue);
+                CheckValueCaching(uint.MaxValue, false);
+                CheckValueCaching(long.MinValue);
+                CheckValueCaching(ulong.MaxValue, false);
+
+                CheckValueCaching((float) 1.1);
+                CheckValueCaching(2.2);
+
+                CheckValueCaching((decimal) 3.3, asArray: false);
+                CheckValueCaching(Guid.NewGuid(), asArray: false);
+                CheckValueCaching(DateTime.Now, asArray: false);
+
+                CheckValueCaching("foobar");
+
+                // Special arrays.
+                CheckValueCaching(new[] {Guid.Empty, Guid.NewGuid()}, false);
+                CheckValueCaching(new Guid?[] {Guid.Empty, Guid.NewGuid()});
+
+                CheckValueCaching(new[] {1.2m, -3.4m}, false);
+                CheckValueCaching(new decimal?[] {1.2m, -3.4m});
+
+                CheckValueCaching(new[] {DateTime.Now}, false);
+
+                // Custom types.
+                CheckValueCaching(new Foo {X = 10}, asArray: false);
+                CheckValueCaching(new Bar {X = 20}, asArray: false);
+
+                // Collections.
+                CheckValueCaching(new List<Foo>(GetFoo()));
+                CheckValueCaching(new List<Bar>(GetBar()));
+
+                CheckValueCaching(new HashSet<Foo>(GetFoo()));
+                CheckValueCaching(new HashSet<Bar>(GetBar()));
+
+                CheckValueCaching(GetFoo().ToDictionary(x => x.X, x => x));
+                CheckValueCaching(GetBar().ToDictionary(x => x.X, x => x));
+
+                // Custom type arrays.
+                // Array type is lost, because in binary mode on Java side we receive the value as Object[].
+                CheckValueCaching(new[] {new Foo {X = -1}, new Foo {X = 1}}, false);
+                CheckValueCaching(new[] {new Bar {X = -10}, new Bar {X = 10}}, false);
+            }
+        }
+
+        /// <summary>
+        /// Checks caching of a value with generic cache.
+        /// </summary>
+        private static void CheckValueCaching<T>(T val, bool asObject = true, bool asArray = true)
+        {
+            var cache = Ignition.GetIgnite(null).GetCache<int, T>(null);
+
+            cache[1] = val;
+            Assert.AreEqual(val, cache[1]);
+
+            if (asObject)
+            {
+                CheckValueCachingAsObject(val);
+            }
+
+            // Array of T
+            if (asArray && !(val is IEnumerable))
+            {
+                CheckValueCaching(new[] {val}, asObject, false);
+            }
+        }
+
+        /// <summary>
+        /// Checks caching of a value with object cache.
+        /// </summary>
+        private static void CheckValueCachingAsObject<T>(T val)
+        {
+            var cache = Ignition.GetIgnite(null).GetCache<int, object>(null);
+
+            cache[1] = val;
+            Assert.AreEqual(val, (T) cache[1]);
+        }
+
+        /// <summary>
+        /// Gets Foo collection.
+        /// </summary>
+        private static IEnumerable<Foo> GetFoo()
+        {
+            return Enumerable.Range(-50, 100).Select(x => new Foo {X = x});
+        }
+
+        /// <summary>
+        /// Gets Bar collection.
+        /// </summary>
+        private static IEnumerable<Bar> GetBar()
+        {
+            return Enumerable.Range(-50, 100).Select(x => new Bar {X = x});
+        }
+
+        /// <summary>
+        /// Test custom class.
+        /// </summary>
+        private class Foo
+        {
+            public int X { get; set; }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) return false;
+                if (ReferenceEquals(this, obj)) return true;
+                if (obj.GetType() != GetType()) return false;
+                return X == ((Foo) obj).X;
+            }
+
+            public override int GetHashCode()
+            {
+                return X;
+            }
+        }
+
+        /// <summary>
+        /// Test custom struct.
+        /// </summary>
+        private struct Bar
+        {
+            public int X { get; set; }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) return false;
+                return obj is Bar && X == ((Bar) obj).X;
+            }
+
+            public override int GetHashCode()
+            {
+                return X;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
new file mode 100644
index 0000000..c96d111
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/AdvancedSerializationTest.cs
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary.Serializable
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Reflection;
+    using System.Reflection.Emit;
+    using System.Runtime.Serialization;
+    using System.Xml;
+    using Apache.Ignite.Core.Cluster;
+    using Apache.Ignite.Core.Compute;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests additional [Serializable] scenarios.
+    /// </summary>
+    public class AdvancedSerializationTest
+    {
+        /// <summary>
+        /// Set up routine.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void SetUp()
+        {
+            Ignition.Start(TestUtils.GetTestConfiguration());
+        }
+
+        /// <summary>
+        /// Tear down routine.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void TearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Test complex file serialization.
+        /// </summary>
+        [Test]
+        public void TestSerializableXmlDoc()
+        {
+            var grid = Ignition.GetIgnite(null);
+            var cache = grid.GetOrCreateCache<int, SerializableXmlDoc>("cache");
+
+            var doc = new SerializableXmlDoc();
+
+            doc.LoadXml("<document><test1>val</test1><test2 attr=\"x\" /></document>");
+
+            for (var i = 0; i < 50; i++)
+            {
+                // Test cache
+                cache.Put(i, doc);
+
+                var resultDoc = cache.Get(i);
+
+                Assert.AreEqual(doc.OuterXml, resultDoc.OuterXml);
+
+                // Test task with document arg
+                CheckTask(grid, doc);
+            }
+        }
+
+        /// <summary>
+        /// Checks task execution.
+        /// </summary>
+        /// <param name="grid">Grid.</param>
+        /// <param name="arg">Task arg.</param>
+        private static void CheckTask(IIgnite grid, object arg)
+        {
+            var jobResult = grid.GetCompute().Execute(new CombineStringsTask(), arg);
+
+            var nodeCount = grid.GetCluster().GetNodes().Count;
+
+            var expectedRes =
+                CombineStringsTask.CombineStrings(Enumerable.Range(0, nodeCount).Select(x => arg.ToString()));
+
+            Assert.AreEqual(expectedRes, jobResult.InnerXml);
+        }
+
+        /// <summary>
+        /// Tests custom serialization binder.
+        /// </summary>
+        [Test]
+        public void TestSerializationBinder()
+        {
+            const int count = 50;
+
+            var cache = Ignition.GetIgnite(null).GetOrCreateCache<int, object>("cache");
+
+            // Put multiple objects from multiple same-named assemblies to cache
+            for (var i = 0; i < count; i++)
+            {
+                dynamic val = Activator.CreateInstance(GenerateDynamicType());
+                
+                val.Id = i;
+                val.Name = "Name_" + i;
+
+                cache.Put(i, val);
+            }
+
+            // Verify correct deserialization
+            for (var i = 0; i < count; i++)
+            {
+                dynamic val = cache.Get(i);
+
+                Assert.AreEqual(val.Id, i);
+                Assert.AreEqual(val.Name, "Name_" + i);
+            }
+        }
+
+        /// <summary>
+        /// Generates a Type in runtime, puts it into a dynamic assembly.
+        /// </summary>
+        /// <returns></returns>
+        private static Type GenerateDynamicType()
+        {
+            var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
+                new AssemblyName("GridSerializationTestDynamicAssembly"), AssemblyBuilderAccess.Run);
+
+            var moduleBuilder = asmBuilder.DefineDynamicModule("GridSerializationTestDynamicModule");
+
+            var typeBuilder = moduleBuilder.DefineType("GridSerializationTestDynamicType",
+                TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Serializable);
+
+            typeBuilder.DefineField("Id", typeof (int), FieldAttributes.Public);
+            
+            typeBuilder.DefineField("Name", typeof (string), FieldAttributes.Public);
+
+            return typeBuilder.CreateType();
+        }
+    }
+
+    [Serializable]
+    [DataContract]
+    public sealed class SerializableXmlDoc : XmlDocument, ISerializable
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public SerializableXmlDoc()
+        {
+            // No-op
+        }
+
+        /// <summary>
+        /// Serialization ctor.
+        /// </summary>
+        private SerializableXmlDoc(SerializationInfo info, StreamingContext context)
+        {
+            LoadXml(info.GetString("xmlDocument"));
+        }
+
+        /** <inheritdoc /> */
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            info.AddValue("xmlDocument", OuterXml, typeof(string));
+        }
+    }
+
+    [Serializable]
+    public class CombineStringsTask : IComputeTask<object, string, SerializableXmlDoc>
+    {
+        public IDictionary<IComputeJob<string>, IClusterNode> Map(IList<IClusterNode> subgrid, object arg)
+        {
+            return subgrid.ToDictionary(x => (IComputeJob<string>) new ToStringJob {Arg = arg}, x => x);
+        }
+
+        public ComputeJobResultPolicy OnResult(IComputeJobResult<string> res, IList<IComputeJobResult<string>> rcvd)
+        {
+            return ComputeJobResultPolicy.Wait;
+        }
+
+        public SerializableXmlDoc Reduce(IList<IComputeJobResult<string>> results)
+        {
+            var result = new SerializableXmlDoc();
+
+            result.LoadXml(CombineStrings(results.Select(x => x.Data)));
+
+            return result;
+        }
+
+        public static string CombineStrings(IEnumerable<string> strings)
+        {
+            var text = string.Concat(strings.Select(x => string.Format("<val>{0}</val>", x)));
+
+            return string.Format("<document>{0}</document>", text);
+        }
+    }
+
+    [Serializable]
+    public class ToStringJob : IComputeJob<string>
+    {
+        /// <summary>
+        /// Job argument.
+        /// </summary>
+        public object Arg { get; set; }
+
+        /** <inheritdoc /> */
+        public string Execute()
+        {
+            return Arg.ToString();
+        }
+
+        /** <inheritdoc /> */
+        public void Cancel()
+        {
+            // No-op.
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/79bac4f8/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
new file mode 100644
index 0000000..82deb3c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
@@ -0,0 +1,124 @@
+\ufeff/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary.Serializable
+{
+    using System;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests basic ISerializable scenarios.
+    /// </summary>
+    public class BasicSerializableObjectsTest
+    {
+        /// <summary>
+        /// Tests the object with no fields.
+        /// </summary>
+        [Test]
+        public void TestEmptyObject()
+        {
+            var res = TestUtils.SerializeDeserialize(new EmptyObject());
+
+            Assert.IsNotNull(res);
+        }
+
+        /// <summary>
+        /// Tests the object with no fields.
+        /// </summary>
+        [Test]
+        public void TestEmptyObjectOnline()
+        {
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var cache = ignite.CreateCache<int, EmptyObject>("c");
+
+                cache[1] = new EmptyObject();
+
+                var res = cache[1];
+
+                Assert.IsNotNull(res);
+            }
+        }
+
+        /// <summary>
+        /// Tests ISerializable without serialization ctor.
+        /// </summary>
+        [Test]
+        public void TestMissingCtor()
+        {
+            var ex = Assert.Throws<SerializationException>(() => TestUtils.SerializeDeserialize(new MissingCtor()));
+            Assert.AreEqual(string.Format("The constructor to deserialize an object of type '{0}' was not found.", 
+                typeof(MissingCtor)), ex.Message);
+        }
+
+        /// <summary>
+        /// Tests <see cref="Type"/> serialization.
+        /// </summary>
+        [Test]
+        public void TestTypes()
+        {
+            var type = GetType();
+
+            var res = TestUtils.SerializeDeserialize(type);
+
+            Assert.AreEqual(type, res);
+        }
+
+        /// <summary>
+        /// Missing serialization ctor.
+        /// </summary>
+        private class MissingCtor : ISerializable
+        {
+            /** <inheritdoc /> */
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                // No-op.
+            }
+        }
+
+        /// <summary>
+        /// Object with no fields.
+        /// </summary>
+        [Serializable]
+        private class EmptyObject : ISerializable
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see cref="EmptyObject"/> class.
+            /// </summary>
+            public EmptyObject()
+            {
+                // No-op.
+            }
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="EmptyObject"/> class.
+            /// </summary>
+            private EmptyObject(SerializationInfo info, StreamingContext context)
+            {
+                Assert.IsInstanceOf<IBinaryReader>(context.Context);
+            }
+
+            /** <inheritdoc /> */
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                Assert.IsInstanceOf<IBinaryWriter>(context.Context);
+            }
+        }
+    }
+}