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

ignite git commit: IGNITE-4441 Define plugin API in .NET

Repository: ignite
Updated Branches:
  refs/heads/ignite-2.0 4cd332b78 -> d0a6c57aa


IGNITE-4441 Define plugin API in .NET

This closes #1362


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

Branch: refs/heads/ignite-2.0
Commit: d0a6c57aa26bca64ef68370c0ebdb5ce45bcc765
Parents: 4cd332b
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Thu Jan 19 17:10:41 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Thu Jan 19 17:10:41 2017 +0300

----------------------------------------------------------------------
 .../ignite/internal/GridKernalContextImpl.java  |   5 +-
 .../apache/ignite/internal/IgniteKernal.java    |   4 +
 .../callback/PlatformCallbackGateway.java       |  28 +++
 .../platform/callback/PlatformCallbackOp.java   |   6 +
 .../plugin/PlatformPluginProcessor.java         |  46 ++++
 .../Apache.Ignite.Core.Tests.csproj             |   4 +
 .../IgniteConfigurationSerializerTest.cs        |  14 +-
 .../IgniteConfigurationTest.cs                  |  13 +-
 .../Plugin/PluginTest.cs                        | 212 +++++++++++++++++
 .../Plugin/TestIgnitePlugin.cs                  |  39 +++
 .../Plugin/TestIgnitePluginConfiguration.cs     |  33 +++
 .../Plugin/TestIgnitePluginProvider.cs          | 132 +++++++++++
 .../Apache.Ignite.Core.csproj                   |   9 +
 .../dotnet/Apache.Ignite.Core/IIgnite.cs        |  10 +
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |   8 +
 .../IgniteConfigurationSection.xsd              |  21 ++
 .../Common/IgniteConfigurationXmlSerializer.cs  |   3 +
 .../dotnet/Apache.Ignite.Core/Impl/Ignite.cs    |  24 ++
 .../Apache.Ignite.Core/Impl/IgniteProxy.cs      |   6 +
 .../Impl/Plugin/IPluginProviderProxy.cs         |  74 ++++++
 .../Impl/Plugin/PluginContext.cs                |  60 +++++
 .../Impl/Plugin/PluginProcessor.cs              | 235 +++++++++++++++++++
 .../Impl/Plugin/PluginProviderProxy.cs          |  90 +++++++
 .../Impl/Unmanaged/UnmanagedCallbackOp.cs       |   4 +-
 .../Impl/Unmanaged/UnmanagedCallbacks.cs        |  25 +-
 .../Plugin/IPluginConfiguration.cs              |  48 ++++
 .../Apache.Ignite.Core/Plugin/IPluginContext.cs |  40 ++++
 .../Plugin/IPluginProvider.cs                   |  69 ++++++
 .../Plugin/PluginNotFoundException.cs           |  65 +++++
 .../Plugin/PluginProviderTypeAttribute.cs       |  51 ++++
 30 files changed, 1369 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index 2f681ac..569460e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -70,6 +70,7 @@ import org.apache.ignite.internal.processors.nodevalidation.DiscoveryNodeValidat
 import org.apache.ignite.internal.processors.odbc.OdbcProcessor;
 import org.apache.ignite.internal.processors.offheap.GridOffHeapProcessor;
 import org.apache.ignite.internal.processors.platform.PlatformProcessor;
+import org.apache.ignite.internal.processors.platform.plugin.PlatformPluginProcessor;
 import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
 import org.apache.ignite.internal.processors.pool.PoolProcessor;
 import org.apache.ignite.internal.processors.port.GridPortProcessor;
@@ -563,7 +564,9 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
             platformProc = (PlatformProcessor)comp;
         else if (comp instanceof PoolProcessor)
             poolProc = (PoolProcessor) comp;
-        else if (!(comp instanceof DiscoveryNodeValidationProcessor || comp instanceof GridMarshallerMappingProcessor))
+        else if (!(comp instanceof DiscoveryNodeValidationProcessor
+                || comp instanceof GridMarshallerMappingProcessor
+                || comp instanceof PlatformPluginProcessor))
             assert (comp instanceof GridPluginComponent) : "Unknown manager class: " + comp.getClass();
 
         if (addToList)

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 20926f9..d883ff1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -125,6 +125,7 @@ import org.apache.ignite.internal.processors.odbc.OdbcProcessor;
 import org.apache.ignite.internal.processors.offheap.GridOffHeapProcessor;
 import org.apache.ignite.internal.processors.platform.PlatformNoopProcessor;
 import org.apache.ignite.internal.processors.platform.PlatformProcessor;
+import org.apache.ignite.internal.processors.platform.plugin.PlatformPluginProcessor;
 import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
 import org.apache.ignite.internal.processors.pool.PoolProcessor;
 import org.apache.ignite.internal.processors.port.GridPortProcessor;
@@ -913,6 +914,9 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
                 provider.start(ctx.plugins().pluginContextForProvider(provider));
             }
 
+            // Start platform plugins.
+            startProcessor(new PlatformPluginProcessor(ctx));
+
             fillNodeAttributes(clusterProc.updateNotifierEnabled());
 
             gw.writeLock();

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
index a9268fe..9842068 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
@@ -1117,6 +1117,34 @@ public class PlatformCallbackGateway {
     }
 
     /**
+     * Stops plugin processor.
+     */
+    public void pluginProcessorStop(boolean cancel) {
+        enter();
+
+        try {
+            PlatformCallbackUtils.inLongOutLong(envPtr, PlatformCallbackOp.PluginProcessorStop, cancel ? 1 : 0);
+        }
+        finally {
+            leave();
+        }
+    }
+
+    /**
+     * Notifies plugin processor about Ignite stop.
+     */
+    public void pluginProcessorIgniteStop(boolean cancel) {
+        enter();
+
+        try {
+            PlatformCallbackUtils.inLongOutLong(envPtr, PlatformCallbackOp.PluginProcessorIgniteStop, cancel ? 1 : 0);
+        }
+        finally {
+            leave();
+        }
+    }
+
+    /**
      * Redirects the console output to platform.
      *
      * @param str String to write.

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
index 973ba51..b0bd3a5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
@@ -203,4 +203,10 @@ class PlatformCallbackOp {
 
     /** */
     public static final int ComputeJobExecuteLocal = 61;
+
+    /** */
+    public static final int PluginProcessorStop = 62;
+
+    /** */
+    public static final int PluginProcessorIgniteStop = 63;
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
new file mode 100644
index 0000000..458ec31
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.processors.platform.plugin;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.GridProcessorAdapter;
+
+/**
+ * Platform plugin processor
+ */
+public class PlatformPluginProcessor extends GridProcessorAdapter {
+    /**
+     * Ctor.
+     *
+     * @param ctx Kernal context.
+     */
+    public PlatformPluginProcessor(GridKernalContext ctx) {
+        super(ctx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop(boolean cancel) throws IgniteCheckedException {
+        ctx.platform().context().gateway().pluginProcessorStop(cancel);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onKernalStop(boolean cancel) {
+        ctx.platform().context().gateway().pluginProcessorIgniteStop(cancel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/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 e09c682..d48c8c8 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
@@ -89,6 +89,10 @@
     <Compile Include="Log\DefaultLoggerTest.cs" />
     <Compile Include="Log\Log4NetLoggerTest.cs" />
     <Compile Include="Log\NLogLoggerTest.cs" />
+    <Compile Include="Plugin\PluginTest.cs" />
+    <Compile Include="Plugin\TestIgnitePlugin.cs" />
+    <Compile Include="Plugin\TestIgnitePluginConfiguration.cs" />
+    <Compile Include="Plugin\TestIgnitePluginProvider.cs" />
     <Compile Include="TestAppConfig.cs" />
     <Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" />
     <Compile Include="Binary\BinaryCompactFooterInteropTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
index 26e04a9..3a0a4b5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
@@ -51,6 +51,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Log;
     using Apache.Ignite.Core.SwapSpace.File;
     using Apache.Ignite.Core.Tests.Binary;
+    using Apache.Ignite.Core.Tests.Plugin;
     using Apache.Ignite.Core.Transactions;
     using Apache.Ignite.NLog;
     using NUnit.Framework;
@@ -128,6 +129,9 @@ namespace Apache.Ignite.Core.Tests
                             <transactionConfiguration defaultTransactionConcurrency='Optimistic' defaultTransactionIsolation='RepeatableRead' defaultTimeout='0:1:2' pessimisticTransactionLogSize='15' pessimisticTransactionLogLinger='0:0:33' />
                             <logger type='Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+TestLogger, Apache.Ignite.Core.Tests' />
                             <swapSpaceSpi type='FileSwapSpaceSpi' baseDirectory='abcd' maximumSparsity='0.7' maximumWriteQueueSize='25' readStripesNumber='36' writeBufferSize='47' />
+                            <pluginConfigurations>
+                                <iPluginConfiguration type='Apache.Ignite.Core.Tests.Plugin.TestIgnitePluginConfiguration, Apache.Ignite.Core.Tests' />
+                            </pluginConfigurations>
                         </igniteConfig>";
 
             var cfg = IgniteConfiguration.FromXml(xml);
@@ -234,6 +238,10 @@ namespace Apache.Ignite.Core.Tests
             Assert.IsInstanceOf<IdMapper>(binType.IdMapper);
             Assert.IsInstanceOf<NameMapper>(binType.NameMapper);
             Assert.IsInstanceOf<TestSerializer>(binType.Serializer);
+
+            var plugins = cfg.PluginConfigurations;
+            Assert.IsNotNull(plugins);
+            Assert.IsNotNull(plugins.Cast<TestIgnitePluginConfiguration>().SingleOrDefault());
         }
 
         /// <summary>
@@ -278,6 +286,9 @@ namespace Apache.Ignite.Core.Tests
 
             foreach (var prop in type.GetProperties())
             {
+                if (!prop.CanWrite)
+                    continue;  // Read-only properties are not configured in XML.
+
                 var propType = prop.PropertyType;
 
                 var isCollection = propType.IsGenericType &&
@@ -761,7 +772,8 @@ namespace Apache.Ignite.Core.Tests
                     WriteBufferSize = 66,
                     ReadStripesNumber = 77,
                     BaseDirectory = "test"
-                }
+                },
+                PluginConfigurations = new[] {new TestIgnitePluginConfiguration() }
             };
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 86ece98..3d9732d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -36,6 +36,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Impl;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.SwapSpace.File;
+    using Apache.Ignite.Core.Tests.Plugin;
     using Apache.Ignite.Core.Transactions;
     using NUnit.Framework;
 
@@ -192,8 +193,11 @@ namespace Apache.Ignite.Core.Tests
                 Assert.AreEqual("affKey", typ.AffinityKeyFieldName);
                 Assert.AreEqual(false, typ.KeepDeserialized);
 
-                CollectionAssert.AreEqual(new[] {"fld1", "fld2"}, 
+                CollectionAssert.AreEqual(new[] {"fld1", "fld2"},
                     ((BinaryFieldEqualityComparer)typ.EqualityComparer).FieldNames);
+
+                Assert.IsNotNull(resCfg.PluginConfigurations);
+                Assert.AreEqual(cfg.PluginConfigurations, resCfg.PluginConfigurations);
             }
         }
 
@@ -481,7 +485,7 @@ namespace Apache.Ignite.Core.Tests
                 JvmOptions = TestUtils.TestJavaOptions(),
                 JvmClasspath = TestUtils.CreateTestClasspath(),
                 Localhost = "127.0.0.1",
-                IsDaemon = true,
+                IsDaemon = false,
                 IsLateAffinityAssignment = false,
                 UserAttributes = Enumerable.Range(1, 10).ToDictionary(x => x.ToString(), x => (object) x),
                 AtomicConfiguration = new AtomicConfiguration
@@ -525,7 +529,7 @@ namespace Apache.Ignite.Core.Tests
                     MaximumWriteQueueSize = 8,
                     WriteBufferSize = 9,
                     BaseDirectory = Path.GetTempPath(),
-                    MaximumSparsity = 11.22f
+                    MaximumSparsity = 0.123f
                 },
                 BinaryConfiguration = new BinaryConfiguration
                 {
@@ -541,7 +545,8 @@ namespace Apache.Ignite.Core.Tests
                             EqualityComparer = new BinaryFieldEqualityComparer("fld1", "fld2")
                         }
                     }
-                }
+                },
+                PluginConfigurations = new[] { new TestIgnitePluginConfiguration() }
             };
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
new file mode 100644
index 0000000..44ba196
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
@@ -0,0 +1,212 @@
+\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.Plugin
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Plugin;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Ignite plugin test.
+    /// </summary>
+    public class PluginTest
+    {
+        /** Plugin log. */
+        private static readonly List<string> PluginLog = new List<string>();
+
+        /// <summary>
+        /// Tests the plugin life cycle.
+        /// </summary>
+        [Test]
+        public void TestIgniteStartStop()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                PluginConfigurations = new[] {new TestIgnitePluginConfiguration {PluginProperty = "barbaz"}}
+            };
+
+            TestIgnitePlugin plugin;
+
+            using (var ignite = Ignition.Start(cfg))
+            {
+                Assert.Throws<PluginNotFoundException>(() => ignite.GetPlugin<object>("foobar"));
+                Assert.Throws<Exception>(() => ignite.GetPlugin<string>(TestIgnitePluginProvider.PluginName));
+
+                plugin = ignite.GetPlugin<TestIgnitePlugin>(TestIgnitePluginProvider.PluginName);
+                Assert.IsNotNull(plugin);
+
+                var prov = plugin.Provider;
+                Assert.IsTrue(prov.Started);
+                Assert.AreEqual(null, prov.Stopped);
+                Assert.AreEqual(TestIgnitePluginProvider.PluginName, prov.Name);
+                Assert.IsNotNullOrEmpty(prov.Copyright);
+                Assert.IsNotNull(prov.Context);
+
+                var ctx = prov.Context;
+                Assert.IsNotNull(ctx.Ignite);
+                Assert.AreEqual(cfg, ctx.IgniteConfiguration);
+                Assert.AreEqual("barbaz", ctx.PluginConfiguration.PluginProperty);
+
+                var plugin2 = ignite.GetPlugin<TestIgnitePlugin>(TestIgnitePluginProvider.PluginName);
+                Assert.AreEqual(plugin, plugin2);
+            }
+
+            Assert.AreEqual(true, plugin.Provider.Stopped);
+            Assert.AreEqual(true, plugin.Provider.IgniteStopped);
+        }
+
+        /// <summary>
+        /// Tests invalid plugins.
+        /// </summary>
+        [Test]
+        public void TestInvalidPlugins()
+        {
+            Action<ICollection<IPluginConfiguration>> check = x => Ignition.Start(
+                new IgniteConfiguration(TestUtils.GetTestConfiguration()) {PluginConfigurations = x});
+
+            // Missing attribute.
+            var ex = Assert.Throws<IgniteException>(() => check(new[] { new NoAttributeConfig(),  }));
+            Assert.AreEqual(string.Format("{0} of type {1} has no {2}", typeof(IPluginConfiguration),
+                typeof(NoAttributeConfig), typeof(PluginProviderTypeAttribute)), ex.Message);
+
+            // Empty plugin name.
+            ex = Assert.Throws<IgniteException>(() => check(new[] {new EmptyNameConfig()}));
+            Assert.AreEqual(string.Format("{0}.Name should not be null or empty: {1}", typeof(IPluginProvider<>),
+                typeof(EmptyNamePluginProvider)), ex.Message);
+
+            // Duplicate plugin name.
+            ex = Assert.Throws<IgniteException>(() => check(new[]
+            {
+                new TestIgnitePluginConfiguration(),
+                new TestIgnitePluginConfiguration()
+            }));
+            Assert.AreEqual(string.Format("Duplicate plugin name 'TestPlugin1' is used by plugin providers " +
+                                          "'{0}' and '{0}'", typeof(TestIgnitePluginProvider)), ex.Message);
+
+            // Provider throws an exception.
+            PluginLog.Clear();
+
+            var ioex = Assert.Throws<IOException>(() => check(new IPluginConfiguration[]
+            {
+                new NormalConfig(), new ExceptionConfig()
+            }));
+            Assert.AreEqual("Failure in plugin provider", ioex.Message);
+
+            // Verify that plugins are started and stopped in correct order:
+            Assert.AreEqual(
+                new[]
+                {
+                    "normalPlugin.Start", "errPlugin.Start",
+                    "errPlugin.OnIgniteStop", "normalPlugin.OnIgniteStop",
+                    "errPlugin.Stop", "normalPlugin.Stop"
+                }, PluginLog);
+        }
+
+        private class NoAttributeConfig : IPluginConfiguration
+        {
+            // No-op.
+        }
+
+        [PluginProviderType(typeof(EmptyNamePluginProvider))]
+        private class EmptyNameConfig : IPluginConfiguration
+        {
+            // No-op.
+        }
+
+        private class EmptyNamePluginProvider : IPluginProvider<EmptyNameConfig>
+        {
+            public string Name { get { return null; } }
+            public string Copyright { get { return null; } }
+            public T GetPlugin<T>() where T : class { return default(T); }
+            public void Start(IPluginContext<EmptyNameConfig> context) { /* No-op. */ }
+            public void Stop(bool cancel) { /* No-op. */ }
+            public void OnIgniteStart() { /* No-op. */ }
+            public void OnIgniteStop(bool cancel) { /* No-op. */ }
+        }
+
+        [PluginProviderType(typeof(ExceptionPluginProvider))]
+        private class ExceptionConfig : IPluginConfiguration
+        {
+            // No-op.
+        }
+
+        private class ExceptionPluginProvider : IPluginProvider<ExceptionConfig>
+        {
+            public string Name { get { return "errPlugin"; } }
+            public string Copyright { get { return null; } }
+            public T GetPlugin<T>() where T : class { return default(T); }
+
+            public void Stop(bool cancel)
+            {
+                PluginLog.Add(Name + ".Stop");
+            }
+
+            public void OnIgniteStart()
+            {
+                PluginLog.Add(Name + ".OnIgniteStart");
+            }
+
+            public void OnIgniteStop(bool cancel)
+            {
+                PluginLog.Add(Name + ".OnIgniteStop");
+            }
+
+            public void Start(IPluginContext<ExceptionConfig> context)
+            {
+                PluginLog.Add(Name + ".Start");
+                throw new IOException("Failure in plugin provider");
+            }
+        }
+
+        [PluginProviderType(typeof(NormalPluginProvider))]
+        private class NormalConfig : IPluginConfiguration
+        {
+            // No-op.
+        }
+
+        private class NormalPluginProvider : IPluginProvider<NormalConfig>
+        {
+            public string Name { get { return "normalPlugin"; } }
+            public string Copyright { get { return null; } }
+            public T GetPlugin<T>() where T : class { return default(T); }
+
+            public void Stop(bool cancel)
+            {
+                PluginLog.Add(Name + ".Stop");
+            }
+
+            public void OnIgniteStart()
+            {
+                PluginLog.Add(Name + ".OnIgniteStart");
+            }
+
+            public void OnIgniteStop(bool cancel)
+            {
+                PluginLog.Add(Name + ".OnIgniteStop");
+            }
+
+            public void Start(IPluginContext<NormalConfig> context)
+            {
+                PluginLog.Add(Name + ".Start");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
new file mode 100644
index 0000000..2a876ab
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
@@ -0,0 +1,39 @@
+\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.Plugin
+{
+    /// <summary>
+    /// Test Ignite plugin.
+    /// </summary>
+    public class TestIgnitePlugin
+    {
+        /// <summary>
+        /// Gets the provider.
+        /// </summary>
+        public TestIgnitePluginProvider Provider { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TestIgnitePlugin"/> class.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        public TestIgnitePlugin(TestIgnitePluginProvider provider)
+        {
+            Provider = provider;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
new file mode 100644
index 0000000..4856ccb
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
@@ -0,0 +1,33 @@
+\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.Plugin
+{
+    using Apache.Ignite.Core.Plugin;
+
+    /// <summary>
+    /// Plugin configuration.
+    /// </summary>
+    [PluginProviderType(typeof(TestIgnitePluginProvider))]
+    public class TestIgnitePluginConfiguration : IPluginConfiguration
+    {
+        /// <summary>
+        /// Custom plugin property.
+        /// </summary>
+        public string PluginProperty { get; set; }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
new file mode 100644
index 0000000..bc21540
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
@@ -0,0 +1,132 @@
+\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.Plugin
+{
+    using System;
+    using Apache.Ignite.Core.Plugin;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Test provider.
+    /// </summary>
+    // ReSharper disable once ClassNeverInstantiated.Global
+    public class TestIgnitePluginProvider : IPluginProvider<TestIgnitePluginConfiguration>
+    {
+        /** */
+        public const string PluginName = "TestPlugin1";
+
+        /** */
+        private readonly TestIgnitePlugin _plugin;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TestIgnitePluginProvider"/> class.
+        /// </summary>
+        public TestIgnitePluginProvider()
+        {
+            Name = PluginName;
+            _plugin = new TestIgnitePlugin(this);
+        }
+        
+        /** <inheritdoc /> */
+        public string Name { get; set; }
+
+        /** <inheritdoc /> */
+        public string Copyright
+        {
+            get { return "Copyright (c) FooBar."; }
+        }
+
+        /** <inheritdoc /> */
+        public T GetPlugin<T>() where T : class
+        {
+            var p = _plugin as T;
+
+            if (p != null)
+                return p;
+
+            throw new Exception("Invalid plugin type: " + typeof(T));
+        }
+
+        /** <inheritdoc /> */
+        public void Start(IPluginContext<TestIgnitePluginConfiguration> context)
+        {
+            Context = context;
+
+            EnsureIgniteWorks();
+        }
+
+        /** <inheritdoc /> */
+        public void Stop(bool cancel)
+        {
+            Stopped = cancel;
+
+            EnsureIgniteWorks();
+        }
+
+        /** <inheritdoc /> */
+        public void OnIgniteStart()
+        {
+            Started = true;
+
+            EnsureIgniteWorks();
+        }
+
+        /** <inheritdoc /> */
+        public void OnIgniteStop(bool cancel)
+        {
+            IgniteStopped = cancel;
+
+            EnsureIgniteWorks();
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is started.
+        /// </summary>
+        public bool Started { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is stopped.
+        /// </summary>
+        public bool? Stopped { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is stopped.
+        /// </summary>
+        public bool? IgniteStopped { get; set; }
+
+        /// <summary>
+        /// Gets the context.
+        /// </summary>
+        public IPluginContext<TestIgnitePluginConfiguration> Context { get; private set; }
+
+        /// <summary>
+        /// Ensures that Ignite instance is functional.
+        /// </summary>
+        private void EnsureIgniteWorks()
+        {
+            Assert.NotNull(Context);
+            Assert.NotNull(Context.Ignite);
+            Assert.NotNull(Context.IgniteConfiguration);
+            Assert.NotNull(Context.PluginConfiguration);
+
+            var cache = Context.Ignite.GetOrCreateCache<int, int>("pluginCache");
+
+            Assert.AreEqual(0, cache.GetSize());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index d58c872..5c0ac94 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -420,6 +420,10 @@
     <Compile Include="Impl\Binary\Structure\BinaryStructureJumpTable.cs" />
     <Compile Include="Impl\Binary\Structure\BinaryStructureUpdate.cs" />
     <Compile Include="Impl\Binary\TypeResolver.cs" />
+    <Compile Include="Impl\Plugin\IPluginProviderProxy.cs" />
+    <Compile Include="Impl\Plugin\PluginContext.cs" />
+    <Compile Include="Impl\Plugin\PluginProcessor.cs" />
+    <Compile Include="Impl\Plugin\PluginProviderProxy.cs" />
     <Compile Include="Impl\Resource\IResourceInjector.cs" />
     <Compile Include="Impl\Resource\ResourceFieldInjector.cs" />
     <Compile Include="Impl\Resource\ResourceMethodInjector.cs" />
@@ -476,6 +480,11 @@
     <Compile Include="Binary\BinaryObjectException.cs" />
     <Compile Include="Binary\BinaryTypeConfiguration.cs" />
     <Compile Include="Binary\BinaryTypeNames.cs" />
+    <Compile Include="Plugin\IPluginConfiguration.cs" />
+    <Compile Include="Plugin\IPluginContext.cs" />
+    <Compile Include="Plugin\IPluginProvider.cs" />
+    <Compile Include="Plugin\PluginNotFoundException.cs" />
+    <Compile Include="Plugin\PluginProviderTypeAttribute.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Resource\InstanceResourceAttribute.cs" />
     <Compile Include="Resource\Package-Info.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index 91aa1dd..2996039 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -32,6 +32,7 @@ namespace Apache.Ignite.Core
     using Apache.Ignite.Core.Log;
     using Apache.Ignite.Core.Lifecycle;
     using Apache.Ignite.Core.Messaging;
+    using Apache.Ignite.Core.Plugin;
     using Apache.Ignite.Core.Services;
     using Apache.Ignite.Core.Transactions;
 
@@ -307,5 +308,14 @@ namespace Apache.Ignite.Core
         /// runs in client mode (<see cref="IgniteConfiguration.ClientMode"/>).
         /// </summary>
         event EventHandler<ClientReconnectEventArgs> ClientReconnected;
+
+        /// <summary>
+        /// Gets the plugin by name.
+        /// </summary>
+        /// <typeparam name="T">Plugin type</typeparam>
+        /// <param name="name">Plugin name.</param>
+        /// <exception cref="PluginNotFoundException">When plugin with specified name has not been found.</exception>
+        /// <returns>Plugin instance.</returns>
+        T GetPlugin<T>(string name) where T : class;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index ce9fcf6..036b05f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -42,6 +42,7 @@
     using Apache.Ignite.Core.Impl.SwapSpace;
     using Apache.Ignite.Core.Lifecycle;
     using Apache.Ignite.Core.Log;
+    using Apache.Ignite.Core.Plugin;
     using Apache.Ignite.Core.SwapSpace;
     using Apache.Ignite.Core.Transactions;
     using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader;
@@ -488,6 +489,7 @@
             Logger = cfg.Logger;
             JvmInitialMemoryMb = cfg.JvmInitialMemoryMb;
             JvmMaxMemoryMb = cfg.JvmMaxMemoryMb;
+            PluginConfigurations = cfg.PluginConfigurations;
         }
 
         /// <summary>
@@ -856,5 +858,11 @@
         /// Gets or sets the swap space SPI.
         /// </summary>
         public ISwapSpaceSpi SwapSpaceSpi { get; set; }
+
+        /// <summary>
+        /// Gets or sets the configurations for plugins to be started.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<IPluginConfiguration> PluginConfigurations { get; set; }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
index d54a200..7ba02c1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -1180,6 +1180,27 @@
                         </xs:attribute>
                     </xs:complexType>
                 </xs:element>
+                <xs:element name="pluginConfigurations" minOccurs="0">
+                    <xs:annotation>
+                        <xs:documentation>Plugin configurations.</xs:documentation>
+                    </xs:annotation>
+                    <xs:complexType>
+                        <xs:sequence>
+                            <xs:element name="iPluginConfiguration" maxOccurs="unbounded">
+                                <xs:annotation>
+                                    <xs:documentation>Plugin configuration.</xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:attribute name="type" type="xs:string" use="required">
+                                        <xs:annotation>
+                                            <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                        </xs:annotation>
+                                    </xs:attribute>
+                                </xs:complexType>
+                            </xs:element>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
             </xs:all>
             <xs:attribute name="gridName" type="xs:string">
                 <xs:annotation>

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
index bb9cbfc..7ca654f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
@@ -84,6 +84,9 @@ namespace Apache.Ignite.Core.Impl.Common
         private static void WriteElement(object obj, XmlWriter writer, string rootElementName, Type valueType, 
             PropertyInfo property = null)
         {
+            if (property != null && !property.CanWrite)
+                return;
+
             if (valueType == typeof(IgniteConfiguration))
                 writer.WriteStartElement(rootElementName, Schema);  // write xmlns for the root element
             else

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/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 1747df2..651fb83 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
@@ -39,6 +39,7 @@ namespace Apache.Ignite.Core.Impl
     using Apache.Ignite.Core.Impl.Datastream;
     using Apache.Ignite.Core.Impl.DataStructures;
     using Apache.Ignite.Core.Impl.Handle;
+    using Apache.Ignite.Core.Impl.Plugin;
     using Apache.Ignite.Core.Impl.Transactions;
     using Apache.Ignite.Core.Impl.Unmanaged;
     using Apache.Ignite.Core.Lifecycle;
@@ -97,6 +98,9 @@ namespace Apache.Ignite.Core.Impl
         private volatile TaskCompletionSource<bool> _clientReconnectTaskCompletionSource = 
             new TaskCompletionSource<bool>();
 
+        /** Plugin processor. */
+        private readonly PluginProcessor _pluginProcessor;
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -142,6 +146,8 @@ namespace Apache.Ignite.Core.Impl
             _clientReconnectTaskCompletionSource.SetResult(false);
 
             SetCompactFooter();
+
+            _pluginProcessor = new PluginProcessor(this);
         }
 
         /// <summary>
@@ -165,6 +171,8 @@ namespace Apache.Ignite.Core.Impl
         /// </summary>
         internal void OnStart()
         {
+            PluginProcessor.OnIgniteStart();
+
             foreach (var lifecycleBean in _lifecycleBeans)
                 lifecycleBean.OnStart(this);
         }
@@ -698,6 +706,14 @@ namespace Apache.Ignite.Core.Impl
         /** <inheritdoc /> */
         public event EventHandler<ClientReconnectEventArgs> ClientReconnected;
 
+        /** <inheritdoc /> */
+        public T GetPlugin<T>(string name) where T : class
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+
+            return PluginProcessor.GetProvider(name).GetPlugin<T>();
+        }
+
         /// <summary>
         /// Gets or creates near cache.
         /// </summary>
@@ -818,5 +834,13 @@ namespace Apache.Ignite.Core.Impl
             if (handler != null)
                 handler.Invoke(this, new ClientReconnectEventArgs(clusterRestarted));
         }
+
+        /// <summary>
+        /// Gets the plugin processor.
+        /// </summary>
+        internal PluginProcessor PluginProcessor
+        {
+            get { return _pluginProcessor; }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
index 98a2d47..5e17853 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
@@ -427,6 +427,12 @@ namespace Apache.Ignite.Core.Impl
         }
 
         /** <inheritdoc /> */
+        public T GetPlugin<T>(string name) where T : class
+        {
+            return _ignite.GetPlugin<T>(name);
+        }
+
+        /** <inheritdoc /> */
         public IAtomicSequence GetAtomicSequence(string name, long initialValue, bool create)
         {
             return _ignite.GetAtomicSequence(name, initialValue, create);

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
new file mode 100644
index 0000000..91e0e45
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
@@ -0,0 +1,74 @@
+/*
+ * 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.Plugin
+{
+    using Apache.Ignite.Core.Plugin;
+
+    /// <summary>
+    /// Non-generic proxy interface.
+    /// </summary>
+    internal interface IPluginProviderProxy
+    {
+        /// <summary>
+        /// Gets the plugin name. Plugins can be retrieved by name via <see cref="IIgnite.GetPlugin{T}"/>.
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Gets the copyright information.
+        /// </summary>
+        string Copyright { get; }
+
+        /// <summary>
+        /// Gets the plugin instance.
+        /// </summary>
+        /// <typeparam name="T">Plugin instance type.</typeparam>
+        /// <returns>Plugin instance.</returns>
+        T GetPlugin<T>() where T : class;
+
+        /// <summary>
+        /// Starts the plugin provider.
+        /// <para />
+        /// <see cref="IPluginContext{T}.Ignite"/> can be null until <see cref="OnIgniteStart"/> is called.
+        /// </summary>
+        /// <param name="processor">Plugin processor.</param>
+        void Start(PluginProcessor processor);
+
+        /// <summary>
+        /// Stops the plugin provider.
+        /// </summary>
+        /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+        void Stop(bool cancel);
+
+        /// <summary>
+        /// Called when Ignite has been started and is fully functional.
+        /// </summary>
+        void OnIgniteStart();
+
+        /// <summary>
+        /// Callback to notify that Ignite is about to stop.
+        /// </summary>
+        /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+        void OnIgniteStop(bool cancel);
+
+        /// <summary>
+        /// Gets the underlying provider.
+        /// </summary>
+        object Provider { get; }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
new file mode 100644
index 0000000..6b3eaca
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
@@ -0,0 +1,60 @@
+\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.Plugin
+{
+    using Apache.Ignite.Core.Plugin;
+
+    /// <summary>
+    /// Plugin context.
+    /// </summary>
+    internal class PluginContext<T> : IPluginContext<T> where T : IPluginConfiguration
+    {
+        /** */
+        private readonly T _pluginConfiguration;
+
+        /** */
+        private readonly PluginProcessor _pluginProcessor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginContext{T}"/> class.
+        /// </summary>
+        public PluginContext(PluginProcessor pluginProcessor, T pluginConfiguration)
+        {
+            _pluginProcessor = pluginProcessor;
+            _pluginConfiguration = pluginConfiguration;
+        }
+
+        /** <inheritdoc /> */
+        public IIgnite Ignite
+        {
+            get { return _pluginProcessor.Ignite; }
+        }
+
+        /** <inheritdoc /> */
+        public IgniteConfiguration IgniteConfiguration
+        {
+            get { return _pluginProcessor.IgniteConfiguration; }
+        }
+
+        /** <inheritdoc /> */
+        public T PluginConfiguration
+        {
+            get { return _pluginConfiguration; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
new file mode 100644
index 0000000..ba2d401
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
@@ -0,0 +1,235 @@
+\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.Plugin
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Linq;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Log;
+    using Apache.Ignite.Core.Plugin;
+
+    /// <summary>
+    /// Plugin processor.
+    /// </summary>
+    internal class PluginProcessor
+    {
+        /** Ordered list of plugin providers. */
+        private readonly IList<IPluginProviderProxy> _pluginProviders = new List<IPluginProviderProxy>();
+
+        /** Plugin providers by name. */
+        private readonly Dictionary<string, IPluginProviderProxy> _pluginProvidersByName
+            = new Dictionary<string, IPluginProviderProxy>();
+
+        /** */
+        private readonly Ignite _ignite;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginProcessor"/> class.
+        /// </summary>
+        /// <param name="ignite">The ignite.</param>
+        public PluginProcessor(Ignite ignite)
+        {
+            Debug.Assert(ignite != null);
+
+            _ignite = ignite;
+        }
+
+        /// <summary>
+        /// Gets the Ignite.
+        /// </summary>
+        public IIgnite Ignite
+        {
+            get { return _ignite; }
+        }
+
+        /// <summary>
+        /// Gets the Ignite configuration.
+        /// </summary>
+        public IgniteConfiguration IgniteConfiguration
+        {
+            get { return _ignite.Configuration; }
+        }
+
+        /// <summary>
+        /// Called when Ignite has started.
+        /// </summary>
+        public void OnIgniteStart()
+        {
+            LoadPlugins();
+
+            // Notify plugins.
+            foreach (var provider in _pluginProviders)
+                provider.OnIgniteStart();
+        }
+
+        /// <summary>
+        /// Stops the plugin processor.
+        /// </summary>
+        public void Stop(bool cancel)
+        {
+            foreach (var provider in _pluginProviders.Reverse())
+                provider.Stop(cancel);
+        }
+
+        /// <summary>
+        /// Called when Ignite is about to stop.
+        /// </summary>
+        public void OnIgniteStop(bool cancel)
+        {
+            foreach (var provider in _pluginProviders.Reverse())
+                provider.OnIgniteStop(cancel);
+        }
+
+        /// <summary>
+        /// Gets the provider.
+        /// </summary>
+        public IPluginProviderProxy GetProvider(string name)
+        {
+            Debug.Assert(!string.IsNullOrEmpty(name));
+
+            IPluginProviderProxy provider;
+
+            if (!_pluginProvidersByName.TryGetValue(name, out provider))
+                throw new PluginNotFoundException(
+                    string.Format("Ignite plugin with name '{0}' not found. Make sure that containing assembly " +
+                                  "is in '{1}' folder or configure IgniteConfiguration.PluginPaths.", 
+                                  name, GetType().Assembly.Location));
+
+            return provider;
+        }
+
+        /// <summary>
+        /// Loads the plugins.
+        /// </summary>
+        private void LoadPlugins()
+        {
+            var log = _ignite.Logger.GetLogger(GetType().Name);
+
+            log.Info("Configured .NET plugins:");
+
+            var pluginConfigurations = IgniteConfiguration.PluginConfigurations;
+
+            if (pluginConfigurations != null && pluginConfigurations.Count > 0)
+            {
+                foreach (var cfg in pluginConfigurations)
+                {
+                    var provider = CreateProviderProxy(cfg);
+
+                    ValidateProvider(provider, _pluginProvidersByName);
+
+                    LogProviderInfo(log, provider);
+
+                    _pluginProviders.Add(provider);
+                    _pluginProvidersByName[provider.Name] = provider;
+
+                    provider.Start(this);
+                }
+            }
+            else
+            {
+                log.Info("  ^-- None");
+            }
+        }
+
+        /// <summary>
+        /// Logs the provider information.
+        /// </summary>
+        private static void LogProviderInfo(ILogger log, IPluginProviderProxy provider)
+        {
+            log.Info("  ^-- " + provider.Name + " " + provider.GetType().Assembly.GetName().Version);
+
+            if (!string.IsNullOrEmpty(provider.Copyright))
+                log.Info("  ^-- " + provider.Copyright);
+
+            log.Info(string.Empty);
+        }
+
+        /// <summary>
+        /// Validates the provider.
+        /// </summary>
+        private static void ValidateProvider(IPluginProviderProxy provider, 
+            Dictionary<string, IPluginProviderProxy> res)
+        {
+            if (provider == null)
+            {
+                throw new IgniteException(string.Format("{0}.CreateProvider can not return null",
+                    typeof(IPluginConfiguration).Name));
+            }
+
+            if (string.IsNullOrEmpty(provider.Name))
+            {
+                throw new IgniteException(string.Format("{0}.Name should not be null or empty: {1}",
+                    typeof(IPluginProvider<>), provider.Provider.GetType()));
+            }
+
+            if (res.ContainsKey(provider.Name))
+            {
+                throw new IgniteException(string.Format("Duplicate plugin name '{0}' is used by " +
+                                                        "plugin providers '{1}' and '{2}'", provider.Name,
+                    provider.Provider.GetType(), res[provider.Name].Provider.GetType()));
+            }
+        }
+
+        /// <summary>
+        /// Creates the provider proxy.
+        /// </summary>
+        private static IPluginProviderProxy CreateProviderProxy(IPluginConfiguration pluginConfiguration)
+        {
+            Debug.Assert(pluginConfiguration != null);
+
+            var cfgType = pluginConfiguration.GetType();
+
+            var attributes = cfgType.GetCustomAttributes(true).OfType<PluginProviderTypeAttribute>().ToArray();
+
+            if (attributes.Length == 0)
+            {
+                throw new IgniteException(string.Format("{0} of type {1} has no {2}",
+                    typeof(IPluginConfiguration), cfgType, typeof(PluginProviderTypeAttribute)));
+
+            }
+
+            if (attributes.Length > 1)
+            {
+                throw new IgniteException(string.Format("{0} of type {1} has more than one {2}",
+                    typeof(IPluginConfiguration), cfgType, typeof(PluginProviderTypeAttribute)));
+            }
+
+            var providerType = attributes[0].PluginProviderType;
+
+            var iface = providerType.GetInterfaces()
+                .SingleOrDefault(i => i.IsGenericType &&
+                                      i.GetGenericTypeDefinition() == typeof(IPluginProvider<>) &&
+                                      i.GetGenericArguments()[0] == cfgType);
+
+            if (iface == null)
+            {
+                throw new IgniteException(string.Format("{0} does not implement {1}",
+                    providerType, typeof(IPluginProvider<>).MakeGenericType(cfgType)));
+            }
+
+            var pluginProvider = Activator.CreateInstance(providerType);
+
+            var providerProxyType = typeof(PluginProviderProxy<>).MakeGenericType(cfgType);
+
+            return (IPluginProviderProxy) Activator.CreateInstance(
+                providerProxyType, pluginConfiguration, pluginProvider);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
new file mode 100644
index 0000000..dff7c4e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
@@ -0,0 +1,90 @@
+\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.Plugin
+{
+    using Apache.Ignite.Core.Plugin;
+
+    /// <summary>
+    /// Wraps user-defined generic <see cref="IPluginProvider{TConfig}"/>.
+    /// </summary>
+    internal class PluginProviderProxy<T> : IPluginProviderProxy where T : IPluginConfiguration
+    {
+        /** */
+        private readonly T _pluginConfiguration;
+
+        /** */
+        private readonly IPluginProvider<T> _pluginProvider;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginProviderProxy{T}"/> class.
+        /// </summary>
+        public PluginProviderProxy(T pluginConfiguration, IPluginProvider<T> pluginProvider)
+        {
+            _pluginConfiguration = pluginConfiguration;
+            _pluginProvider = pluginProvider;
+        }
+
+        /** <inheritdoc /> */
+        public void Start(PluginProcessor pluginProcessor)
+        {
+            _pluginProvider.Start(new PluginContext<T>(pluginProcessor, _pluginConfiguration));
+        }
+
+        /** <inheritdoc /> */
+        public string Name
+        {
+            get { return _pluginProvider.Name; }
+        }
+
+        /** <inheritdoc /> */
+        public string Copyright
+        {
+            get { return _pluginProvider.Copyright; }
+        }
+
+        /** <inheritdoc /> */
+        public TPlugin GetPlugin<TPlugin>() where TPlugin : class
+        {
+            return _pluginProvider.GetPlugin<TPlugin>();
+        }
+
+        /** <inheritdoc /> */
+        public void Stop(bool cancel)
+        {
+            _pluginProvider.Stop(cancel);
+        }
+
+        /** <inheritdoc /> */
+        public void OnIgniteStart()
+        {
+            _pluginProvider.OnIgniteStart();
+        }
+
+        /** <inheritdoc /> */
+        public void OnIgniteStop(bool cancel)
+        {
+            _pluginProvider.OnIgniteStop(cancel);
+        }
+        
+        /** <inheritdoc /> */
+        public object Provider
+        {
+            get { return _pluginProvider; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
index 0b766de..da61319 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
@@ -81,6 +81,8 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
         AffinityFunctionRemoveNode = 58,
         AffinityFunctionDestroy = 59,
         ComputeTaskLocalJobResult = 60,
-        ComputeJobExecuteLocal = 61
+        ComputeJobExecuteLocal = 61,
+        PluginProcessorStop = 62,
+        PluginProcessorIgniteStop = 63
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/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 09933be..a42342b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
     using System.Globalization;
+    using System.Linq;
     using System.Runtime.InteropServices;
     using System.Threading;
     using Apache.Ignite.Core.Cache.Affinity;
@@ -78,12 +79,15 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
         // ReSharper disable once CollectionNeverQueried.Local
         private readonly List<Delegate> _delegates = new List<Delegate>(5);
 
+        /** Max op code. */
+        private static readonly int MaxOpCode = Enum.GetValues(typeof(UnmanagedCallbackOp)).Cast<int>().Max();
+
         /** Handlers array. */
-        private readonly InLongOutLongHandler[] _inLongOutLongHandlers = new InLongOutLongHandler[62];
+        private readonly InLongOutLongHandler[] _inLongOutLongHandlers = new InLongOutLongHandler[MaxOpCode + 1];
 
         /** Handlers array. */
         private readonly InLongLongLongObjectOutLongHandler[] _inLongLongLongObjectOutLongHandlers
-            = new InLongLongLongObjectOutLongHandler[62];
+            = new InLongLongLongObjectOutLongHandler[MaxOpCode + 1];
 
         /** Initialized flag. */
         private readonly ManualResetEventSlim _initEvent = new ManualResetEventSlim(false);
@@ -133,6 +137,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
         public UnmanagedCallbacks(ILogger log)
         {
             Debug.Assert(log != null);
+
             _log = log;
 
             var cbs = new UnmanagedCallbackHandlers
@@ -232,6 +237,8 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
             AddHandler(UnmanagedCallbackOp.AffinityFunctionDestroy, AffinityFunctionDestroy);
             AddHandler(UnmanagedCallbackOp.ComputeTaskLocalJobResult, ComputeTaskLocalJobResult);
             AddHandler(UnmanagedCallbackOp.ComputeJobExecuteLocal, ComputeJobExecuteLocal);
+            AddHandler(UnmanagedCallbackOp.PluginProcessorStop, PluginProcessorStop);
+            AddHandler(UnmanagedCallbackOp.PluginProcessorIgniteStop, PluginProcessorIgniteStop);
         }
 
         /// <summary>
@@ -1126,6 +1133,20 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
             }
         }
 
+        private long PluginProcessorIgniteStop(long val)
+        {
+            _ignite.PluginProcessor.OnIgniteStop(val != 0);
+
+            return 0;
+        }
+
+        private long PluginProcessorStop(long val)
+        {
+            _ignite.PluginProcessor.Stop(val != 0);
+
+            return 0;
+        }
+
         #endregion
 
         #region AffinityFunction

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
new file mode 100644
index 0000000..09f3f4a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
@@ -0,0 +1,48 @@
+\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.Plugin
+{
+    using System.Diagnostics.CodeAnalysis;
+
+    /// <summary>
+    /// Plugin configuration marker interface.
+    /// <para />
+    /// Implementations should be linked to corresponding <see cref="IPluginProvider{TConfig}"/>
+    /// via <see cref="PluginProviderTypeAttribute"/>.
+    /// <example>
+    /// Example plugin implementation:
+    /// <code>
+    /// [PluginProviderType(typeof(MyPluginProvider))]
+    /// class MyPluginConfig : IPluginConfiguration
+    /// {
+    ///     int CustomProperty { get; set; }
+    /// }
+    /// 
+    /// class MyPluginProvider : IPluginProvider&lt;MyPluginConfig&gt;
+    /// {
+    ///     ...
+    /// }
+    /// </code>
+    /// </example>
+    /// </summary>
+    [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")]
+    public interface IPluginConfiguration
+    {
+        // No-op.
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
new file mode 100644
index 0000000..e91bdbf
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
@@ -0,0 +1,40 @@
+\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.Plugin
+{
+    /// <summary>
+    /// Plugin execution context.
+    /// </summary>
+    public interface IPluginContext<out T> where T : IPluginConfiguration
+    {
+        /// <summary>
+        /// Gets the Ignite.
+        /// </summary>
+        IIgnite Ignite { get; }
+
+        /// <summary>
+        /// Gets the Ignite configuration.
+        /// </summary>
+        IgniteConfiguration IgniteConfiguration { get; }
+
+        /// <summary>
+        /// Gets the plugin configuration.
+        /// </summary>
+        T PluginConfiguration { get; }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
new file mode 100644
index 0000000..3ea5cff
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
@@ -0,0 +1,69 @@
+\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.Plugin
+{
+    /// <summary>
+    /// Pluggable Ignite component. Should have parameterless constructor.
+    /// <para />
+    /// Ignite plugins are loaded according to <see cref="IgniteConfiguration.PluginConfigurations"/>.
+    /// </summary>
+    public interface IPluginProvider<in TConfig> where TConfig : IPluginConfiguration
+    {
+        /// <summary>
+        /// Gets the plugin name. Plugins can be retrieved by name via <see cref="IIgnite.GetPlugin{T}"/>.
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Gets the copyright information.
+        /// </summary>
+        string Copyright { get; }
+
+        /// <summary>
+        /// Gets the plugin instance.
+        /// </summary>
+        /// <typeparam name="T">Plugin instance type.</typeparam>
+        /// <returns>Plugin instance.</returns>
+        T GetPlugin<T>() where T : class;
+
+        /// <summary>
+        /// Starts the plugin provider.
+        /// <para />
+        /// <see cref="IPluginContext{T}.Ignite"/> can be null until <see cref="OnIgniteStart"/> is called.
+        /// </summary>
+        /// <param name="context">The context.</param>
+        void Start(IPluginContext<TConfig> context);
+
+        /// <summary>
+        /// Stops the plugin provider.
+        /// </summary>
+        /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+        void Stop(bool cancel);
+
+        /// <summary>
+        /// Called when Ignite has been started and is fully functional.
+        /// </summary>
+        void OnIgniteStart();
+
+        /// <summary>
+        /// Callback to notify that Ignite is about to stop.
+        /// </summary>
+        /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+        void OnIgniteStop(bool cancel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
new file mode 100644
index 0000000..e6c869f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
@@ -0,0 +1,65 @@
+\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.Plugin
+{
+    using System;
+    using System.Runtime.Serialization;
+
+    /// <summary>
+    /// Indicates missing Ignite plugin.
+    /// </summary>
+    [Serializable]
+    public class PluginNotFoundException : Exception
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+        /// </summary>
+        public PluginNotFoundException()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+        /// </summary>
+        /// <param name="message">The message that describes the error.</param>
+        public PluginNotFoundException(string message) : base(message)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+        /// </summary>
+        /// <param name="message">The error message that explains the reason for the exception.</param>
+        /// <param name="innerException">The exception that is the cause of the current exception, 
+        /// or a null reference if no inner exception is specified.</param>
+        public PluginNotFoundException(string message, Exception innerException) : base(message, innerException)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+        /// </summary>
+        protected PluginNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+            // No-op.
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
new file mode 100644
index 0000000..64dcfd4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
@@ -0,0 +1,51 @@
+\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.Plugin
+{
+    using System;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// When applied to <see cref="IPluginConfiguration"/>, defines the type of
+    /// <see cref="IPluginProvider{T}"/> to instantiate.
+    /// </summary>
+    public class PluginProviderTypeAttribute : Attribute
+    {
+        /** */
+        private readonly Type _pluginProviderType;
+
+        /// <summary>
+        /// Initializes new instance of <see cref="PluginProviderTypeAttribute"/> class.
+        /// </summary>
+        /// <param name="pluginProviderType">Type of the plugin provider.</param>
+        public PluginProviderTypeAttribute(Type pluginProviderType)
+        {
+            IgniteArgumentCheck.NotNull(pluginProviderType, "pluginProviderType");
+
+            _pluginProviderType = pluginProviderType;
+        }
+
+        /// <summary>
+        /// Gets the plugin provider type.
+        /// </summary>
+        public Type PluginProviderType
+        {
+            get { return _pluginProviderType; }
+        }
+    }
+}
\ No newline at end of file