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 2016/02/04 11:09:24 UTC

[21/50] [abbrv] ignite git commit: IGNITE-1906: .NET: Implemented programmatic configuration.

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
new file mode 100644
index 0000000..b319be9
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
@@ -0,0 +1,601 @@
+/*
+ * 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 MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+namespace Apache.Ignite.Core.Cache.Configuration
+{
+    using System;
+    using System.Collections.Generic;
+    using System.ComponentModel;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Store;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Binary;
+
+    /// <summary>
+    /// Defines grid cache configuration.
+    /// </summary>
+    public class CacheConfiguration
+    {
+        /// <summary> Default size of rebalance thread pool. </summary>
+        public const int DefaultRebalanceThreadPoolSize = 2;
+
+        /// <summary> Default rebalance timeout.</summary>
+        public static readonly TimeSpan DefaultRebalanceTimeout = TimeSpan.FromMilliseconds(10000);
+
+        /// <summary> Time to wait between rebalance messages to avoid overloading CPU. </summary>
+        public static readonly TimeSpan DefaultRebalanceThrottle = TimeSpan.Zero;
+
+        /// <summary> Default number of backups. </summary>
+        public const int DefaultBackups = 0;
+
+        /// <summary> Default caching mode. </summary>
+        public const CacheMode DefaultCacheMode = CacheMode.Partitioned;
+
+        /// <summary> Default atomicity mode. </summary>
+        public const CacheAtomicityMode DefaultAtomicityMode = CacheAtomicityMode.Atomic;
+
+        /// <summary> Default lock timeout. </summary>
+        public static readonly TimeSpan DefaultLockTimeout = TimeSpan.Zero;
+
+        /// <summary> Initial default cache size. </summary>
+        public const int DefaultStartSize = 1500000;
+
+        /// <summary> Default cache size to use with eviction policy. </summary>
+        public const int DefaultCacheSize = 100000;
+
+        /// <summary> Default value for 'invalidate' flag that indicates if this is invalidation-based cache. </summary>
+        public const bool DefaultInvalidate = false;
+
+        /// <summary> Default rebalance mode for distributed cache. </summary>
+        public const CacheRebalanceMode DefaultRebalanceMode = CacheRebalanceMode.Async;
+
+        /// <summary> Default rebalance batch size in bytes. </summary>
+        public const int DefaultRebalanceBatchSize = 512*1024; // 512K
+
+        /// <summary> Default maximum eviction queue ratio. </summary>
+        public const float DefaultMaxEvictionOverflowRatio = 10;
+
+        /// <summary> Default eviction synchronized flag. </summary>
+        public const bool DefaultEvictSynchronized = false;
+
+        /// <summary> Default eviction key buffer size for batching synchronized evicts. </summary>
+        public const int DefaultEvictSynchronizedKeyBufferSize = 1024;
+
+        /// <summary> Default synchronous eviction timeout. </summary>
+        public static readonly TimeSpan DefaultEvictSynchronizedTimeout = TimeSpan.FromMilliseconds(10000);
+
+        /// <summary> Default synchronous eviction concurrency level. </summary>
+        public const int DefaultEvictSynchronizedConcurrencyLevel = 4;
+
+        /// <summary> Default value for eager ttl flag. </summary>
+        public const bool DefaultEagerTtl = true;
+
+        /// <summary> Default off-heap storage size is {@code -1} which means that off-heap storage is disabled. </summary>
+        public const long DefaultOffHeapMaxMemory = -1;
+
+        /// <summary> Default value for 'swapEnabled' flag. </summary>
+        public const bool DefaultEnableSwap = false;
+
+        /// <summary> Default value for 'maxConcurrentAsyncOps'. </summary>
+        public const int DefaultMaxConcurrentAsyncOperations = 500;
+
+        /// <summary> Default value for 'writeBehindEnabled' flag. </summary>
+        public const bool DefaultWriteBehindEnabled = false;
+
+        /// <summary> Default flush size for write-behind cache store. </summary>
+        public const int DefaultWriteBehindFlushSize = 10240; // 10K
+
+        /// <summary> Default flush frequency for write-behind cache store. </summary>
+        public static readonly TimeSpan DefaultWriteBehindFlushFrequency = TimeSpan.FromMilliseconds(5000);
+
+        /// <summary> Default count of flush threads for write-behind cache store. </summary>
+        public const int DefaultWriteBehindFlushThreadCount = 1;
+
+        /// <summary> Default batch size for write-behind cache store. </summary>
+        public const int DefaultWriteBehindBatchSize = 512;
+
+        /// <summary> Default value for load previous value flag. </summary>
+        public const bool DefaultLoadPreviousValue = false;
+
+        /// <summary> Default memory mode. </summary>
+        public const CacheMemoryMode DefaultMemoryMode = CacheMemoryMode.OnheapTiered;
+
+        /// <summary> Default value for 'readFromBackup' flag. </summary>
+        public const bool DefaultReadFromBackup = true;
+
+        /// <summary> Default timeout after which long query warning will be printed. </summary>
+        public static readonly TimeSpan DefaultLongQueryWarningTimeout = TimeSpan.FromMilliseconds(3000);
+
+        /// <summary> Default size for onheap SQL row cache size. </summary>
+        public const int DefaultSqlOnheapRowCacheSize = 10*1024;
+
+        /// <summary> Default value for keep portable in store behavior .</summary>
+        public const bool DefaultKeepVinaryInStore = true;
+
+        /// <summary> Default value for 'copyOnRead' flag. </summary>
+        public const bool DefaultCopyOnRead = true;
+
+        /// <summary>
+        /// Gets or sets the cache name.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        public CacheConfiguration() : this((string) null)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        public CacheConfiguration(string name)
+        {
+            Name = name;
+
+            Backups = DefaultBackups;
+            AtomicityMode = DefaultAtomicityMode;
+            CacheMode = DefaultCacheMode;
+            CopyOnRead = DefaultCopyOnRead;
+            EagerTtl = DefaultEagerTtl;
+            EvictSynchronizedKeyBufferSize = DefaultEvictSynchronizedKeyBufferSize;
+            EvictSynchronized = DefaultEvictSynchronized;
+            EvictSynchronizedConcurrencyLevel = DefaultEvictSynchronizedConcurrencyLevel;
+            EvictSynchronizedTimeout = DefaultEvictSynchronizedTimeout;
+            Invalidate = DefaultInvalidate;
+            KeepBinaryInStore = DefaultKeepVinaryInStore;
+            LoadPreviousValue = DefaultLoadPreviousValue;
+            LockTimeout = DefaultLockTimeout;
+            LongQueryWarningTimeout = DefaultLongQueryWarningTimeout;
+            MaxConcurrentAsyncOperations = DefaultMaxConcurrentAsyncOperations;
+            MaxEvictionOverflowRatio = DefaultMaxEvictionOverflowRatio;
+            MemoryMode = DefaultMemoryMode;
+            OffHeapMaxMemory = DefaultOffHeapMaxMemory;
+            ReadFromBackup = DefaultReadFromBackup;
+            RebalanceBatchSize = DefaultRebalanceBatchSize;
+            RebalanceMode = DefaultRebalanceMode;
+            RebalanceThrottle = DefaultRebalanceThrottle;
+            RebalanceTimeout = DefaultRebalanceTimeout;
+            SqlOnheapRowCacheSize = DefaultSqlOnheapRowCacheSize;
+            StartSize = DefaultStartSize;
+            EnableSwap = DefaultEnableSwap;
+            WriteBehindBatchSize = DefaultWriteBehindBatchSize;
+            WriteBehindEnabled = DefaultWriteBehindEnabled;
+            WriteBehindFlushFrequency = DefaultWriteBehindFlushFrequency;
+            WriteBehindFlushSize = DefaultWriteBehindFlushSize;
+            WriteBehindFlushThreadCount= DefaultWriteBehindFlushThreadCount;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class 
+        /// and populates <see cref="QueryEntities"/> according to provided query types.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        /// <param name="queryTypes">
+        /// Collection of types to be registered as query entities. These types should use 
+        /// <see cref="QuerySqlFieldAttribute"/> to configure query fields and properties.
+        /// </param>
+        public CacheConfiguration(string name, params Type[] queryTypes) : this(name)
+        {
+            QueryEntities = queryTypes.Select(type => new QueryEntity {ValueType = type}).ToArray();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        /// <param name="queryEntities">Query entities.</param>
+        public CacheConfiguration(string name, params QueryEntity[] queryEntities) : this(name)
+        {
+            QueryEntities = queryEntities;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        internal CacheConfiguration(IBinaryRawReader reader)
+        {
+            AtomicityMode = (CacheAtomicityMode) reader.ReadInt();
+            AtomicWriteOrderMode = (CacheAtomicWriteOrderMode) reader.ReadInt();
+            Backups = reader.ReadInt();
+            CacheMode = (CacheMode) reader.ReadInt();
+            CopyOnRead = reader.ReadBoolean();
+            EagerTtl = reader.ReadBoolean();
+            EnableSwap = reader.ReadBoolean();
+            EvictSynchronized = reader.ReadBoolean();
+            EvictSynchronizedConcurrencyLevel = reader.ReadInt();
+            EvictSynchronizedKeyBufferSize = reader.ReadInt();
+            EvictSynchronizedTimeout = reader.ReadLongAsTimespan();
+            Invalidate = reader.ReadBoolean();
+            KeepBinaryInStore = reader.ReadBoolean();
+            LoadPreviousValue = reader.ReadBoolean();
+            LockTimeout = reader.ReadLongAsTimespan();
+            LongQueryWarningTimeout = reader.ReadLongAsTimespan();
+            MaxConcurrentAsyncOperations = reader.ReadInt();
+            MaxEvictionOverflowRatio = reader.ReadFloat();
+            MemoryMode = (CacheMemoryMode) reader.ReadInt();
+            Name = reader.ReadString();
+            OffHeapMaxMemory = reader.ReadLong();
+            ReadFromBackup = reader.ReadBoolean();
+            RebalanceBatchSize = reader.ReadInt();
+            RebalanceDelay = reader.ReadLongAsTimespan();
+            RebalanceMode = (CacheRebalanceMode) reader.ReadInt();
+            RebalanceThrottle = reader.ReadLongAsTimespan();
+            RebalanceTimeout = reader.ReadLongAsTimespan();
+            SqlEscapeAll = reader.ReadBoolean();
+            SqlOnheapRowCacheSize = reader.ReadInt();
+            StartSize = reader.ReadInt();
+            WriteBehindBatchSize = reader.ReadInt();
+            WriteBehindEnabled = reader.ReadBoolean();
+            WriteBehindFlushFrequency = reader.ReadLongAsTimespan();
+            WriteBehindFlushSize = reader.ReadInt();
+            WriteBehindFlushThreadCount = reader.ReadInt();
+            WriteSynchronizationMode = (CacheWriteSynchronizationMode) reader.ReadInt();
+            CacheStoreFactory = reader.ReadObject<IFactory<ICacheStore>>();
+
+            var count = reader.ReadInt();
+            QueryEntities = count == 0 ? null : Enumerable.Range(0, count).Select(x => new QueryEntity(reader)).ToList();
+        }
+
+        /// <summary>
+        /// Writes this instane to the specified writer.
+        /// </summary>
+        /// <param name="writer">The writer.</param>
+        internal void Write(IBinaryRawWriter writer)
+        {
+            writer.WriteInt((int) AtomicityMode);
+            writer.WriteInt((int) AtomicWriteOrderMode);
+            writer.WriteInt(Backups);
+            writer.WriteInt((int) CacheMode);
+            writer.WriteBoolean(CopyOnRead);
+            writer.WriteBoolean(EagerTtl);
+            writer.WriteBoolean(EnableSwap);
+            writer.WriteBoolean(EvictSynchronized);
+            writer.WriteInt(EvictSynchronizedConcurrencyLevel);
+            writer.WriteInt(EvictSynchronizedKeyBufferSize);
+            writer.WriteLong((long) EvictSynchronizedTimeout.TotalMilliseconds);
+            writer.WriteBoolean(Invalidate);
+            writer.WriteBoolean(KeepBinaryInStore);
+            writer.WriteBoolean(LoadPreviousValue);
+            writer.WriteLong((long) LockTimeout.TotalMilliseconds);
+            writer.WriteLong((long) LongQueryWarningTimeout.TotalMilliseconds);
+            writer.WriteInt(MaxConcurrentAsyncOperations);
+            writer.WriteFloat(MaxEvictionOverflowRatio);
+            writer.WriteInt((int) MemoryMode);
+            writer.WriteString(Name);
+            writer.WriteLong(OffHeapMaxMemory);
+            writer.WriteBoolean(ReadFromBackup);
+            writer.WriteInt(RebalanceBatchSize);
+            writer.WriteLong((long) RebalanceDelay.TotalMilliseconds);
+            writer.WriteInt((int) RebalanceMode);
+            writer.WriteLong((long) RebalanceThrottle.TotalMilliseconds);
+            writer.WriteLong((long) RebalanceTimeout.TotalMilliseconds);
+            writer.WriteBoolean(SqlEscapeAll);
+            writer.WriteInt(SqlOnheapRowCacheSize);
+            writer.WriteInt(StartSize);
+            writer.WriteInt(WriteBehindBatchSize);
+            writer.WriteBoolean(WriteBehindEnabled);
+            writer.WriteLong((long) WriteBehindFlushFrequency.TotalMilliseconds);
+            writer.WriteInt(WriteBehindFlushSize);
+            writer.WriteInt(WriteBehindFlushThreadCount);
+            writer.WriteInt((int) WriteSynchronizationMode);
+            writer.WriteObject(CacheStoreFactory);
+
+            if (QueryEntities != null)
+            {
+                writer.WriteInt(QueryEntities.Count);
+
+                foreach (var entity in QueryEntities)
+                {
+                    if (entity == null)
+                        throw new InvalidOperationException("Invalid cache configuration: QueryEntity can't be null.");
+
+                    entity.Write(writer);
+                }
+            }
+            else
+                writer.WriteInt(0);
+        }
+
+        /// <summary>
+        /// Gets or sets write synchronization mode. This mode controls whether the main        
+        /// caller should wait for update on other nodes to complete or not.
+        /// </summary>
+        public CacheWriteSynchronizationMode WriteSynchronizationMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether eviction is synchronized between primary, backup and near nodes.        
+        /// If this parameter is true and swap is disabled then <see cref="ICache{TK,TV}.LocalEvict"/>
+        /// will involve all nodes where an entry is kept.  
+        /// If this property is set to false then eviction is done independently on different cache nodes.        
+        /// Note that it's not recommended to set this value to true if cache store is configured since it will allow 
+        /// to significantly improve cache performance.
+        /// </summary>
+        [DefaultValue(DefaultEvictSynchronized)]
+        public bool EvictSynchronized { get; set; }
+
+        /// <summary>
+        /// Gets or sets size of the key buffer for synchronized evictions.
+        /// </summary>
+        [DefaultValue(DefaultEvictSynchronizedKeyBufferSize)]
+        public int EvictSynchronizedKeyBufferSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets concurrency level for synchronized evictions. 
+        /// This flag only makes sense with <see cref="EvictSynchronized"/> set to true. 
+        /// When synchronized evictions are enabled, it is possible that local eviction policy will try 
+        /// to evict entries faster than evictions can be synchronized with backup or near nodes. 
+        /// This value specifies how many concurrent synchronous eviction sessions should be allowed 
+        /// before the system is forced to wait and let synchronous evictions catch up with the eviction policy.       
+        /// </summary>
+        [DefaultValue(DefaultEvictSynchronizedConcurrencyLevel)]
+        public int EvictSynchronizedConcurrencyLevel { get; set; }
+
+        /// <summary>
+        /// Gets or sets timeout for synchronized evictions
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:10")]
+        public TimeSpan EvictSynchronizedTimeout { get; set; }
+
+        /// <summary>
+        /// This value denotes the maximum size of eviction queue in percents of cache size 
+        /// in case of distributed cache (replicated and partitioned) and using synchronized eviction
+        /// <para/>        
+        /// That queue is used internally as a buffer to decrease network costs for synchronized eviction. 
+        /// Once queue size reaches specified value all required requests for all entries in the queue 
+        /// are sent to remote nodes and the queue is cleared.
+        /// </summary>
+        [DefaultValue(DefaultMaxEvictionOverflowRatio)]
+        public float MaxEvictionOverflowRatio { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether expired cache entries will be eagerly removed from cache. 
+        /// When set to false, expired entries will be removed on next entry access.        
+        /// </summary>
+        [DefaultValue(DefaultEagerTtl)]
+        public bool EagerTtl { get; set; }
+
+        /// <summary>
+        /// Gets or sets initial cache size which will be used to pre-create internal hash table after start.
+        /// </summary>
+        [DefaultValue(DefaultStartSize)]
+        public int StartSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether value should be loaded from store if it is not in the cache 
+        /// for the following cache operations:   
+        /// <list type="bullet">
+        /// <item><term><see cref="ICache{TK,TV}.PutIfAbsent"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.Replace(TK,TV)"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.Remove(TK)"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.GetAndPut"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.GetAndRemove"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.GetAndReplace"/></term></item>
+        /// <item><term><see cref="ICache{TK,TV}.GetAndPutIfAbsent"/></term></item>
+        /// </list>     
+        /// </summary>
+        [DefaultValue(DefaultLoadPreviousValue)]
+        public bool LoadPreviousValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the flag indicating whether <see cref="ICacheStore"/> is working with binary objects 
+        /// instead of deserialized objects.
+        /// </summary>
+        [DefaultValue(DefaultKeepVinaryInStore)]
+        public bool KeepBinaryInStore { get; set; }
+
+        /// <summary>
+        /// Gets or sets caching mode to use.
+        /// </summary>
+        [DefaultValue(DefaultCacheMode)]
+        public CacheMode CacheMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets cache atomicity mode.
+        /// </summary>
+        [DefaultValue(DefaultAtomicityMode)]
+        public CacheAtomicityMode AtomicityMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets cache write ordering mode.
+        /// </summary>
+        public CacheAtomicWriteOrderMode AtomicWriteOrderMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets number of nodes used to back up single partition for 
+        /// <see cref="Configuration.CacheMode.Partitioned"/> cache.
+        /// </summary>
+        [DefaultValue(DefaultBackups)]
+        public int Backups { get; set; }
+
+        /// <summary>
+        /// Gets or sets default lock acquisition timeout.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:00")]
+        public TimeSpan LockTimeout { get; set; }
+
+        /// <summary>
+        /// Invalidation flag. If true, values will be invalidated (nullified) upon commit in near cache.
+        /// </summary>
+        [DefaultValue(DefaultInvalidate)]
+        public bool Invalidate { get; set; }
+
+        /// <summary>
+        /// Gets or sets cache rebalance mode.
+        /// </summary>
+        [DefaultValue(DefaultRebalanceMode)]
+        public CacheRebalanceMode RebalanceMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets size (in number bytes) to be loaded within a single rebalance message.
+        /// Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data.
+        /// </summary>
+        [DefaultValue(DefaultRebalanceBatchSize)]
+        public int RebalanceBatchSize { get; set; }
+
+        /// <summary>
+        /// Flag indicating whether Ignite should use swap storage by default.
+        /// </summary>
+        [DefaultValue(DefaultEnableSwap)]
+        public bool EnableSwap { get; set; }
+
+        /// <summary>
+        /// Gets or sets maximum number of allowed concurrent asynchronous operations, 0 for unlimited.
+        /// </summary>
+        [DefaultValue(DefaultMaxConcurrentAsyncOperations)]
+        public int MaxConcurrentAsyncOperations { get; set; }
+
+        /// <summary>
+        /// Flag indicating whether Ignite should use write-behind behaviour for the cache store.
+        /// </summary>
+        [DefaultValue(DefaultWriteBehindEnabled)]
+        public bool WriteBehindEnabled { get; set; }
+
+        /// <summary>
+        /// Maximum size of the write-behind cache. If cache size exceeds this value, all cached items are flushed 
+        /// to the cache store and write cache is cleared.
+        /// </summary>
+        [DefaultValue(DefaultWriteBehindFlushSize)]
+        public int WriteBehindFlushSize { get; set; }
+
+        /// <summary>
+        /// Frequency with which write-behind cache is flushed to the cache store.
+        /// This value defines the maximum time interval between object insertion/deletion from the cache
+        /// at the moment when corresponding operation is applied to the cache store.
+        /// <para/> 
+        /// If this value is 0, then flush is performed according to the flush size.
+        /// <para/>
+        /// Note that you cannot set both
+        /// <see cref="WriteBehindFlushSize"/> and <see cref="WriteBehindFlushFrequency"/> to 0.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:05")]
+        public TimeSpan WriteBehindFlushFrequency { get; set; }
+
+        /// <summary>
+        /// Number of threads that will perform cache flushing. Cache flushing is performed when cache size exceeds 
+        /// value defined by <see cref="WriteBehindFlushSize"/>, or flush interval defined by 
+        /// <see cref="WriteBehindFlushFrequency"/> is elapsed.
+        /// </summary>
+        [DefaultValue(DefaultWriteBehindFlushThreadCount)]
+        public int WriteBehindFlushThreadCount { get; set; }
+
+        /// <summary>
+        /// Maximum batch size for write-behind cache store operations. 
+        /// Store operations (get or remove) are combined in a batch of this size to be passed to 
+        /// <see cref="ICacheStore.WriteAll"/> or <see cref="ICacheStore.DeleteAll"/> methods. 
+        /// </summary>
+        [DefaultValue(DefaultWriteBehindBatchSize)]
+        public int WriteBehindBatchSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets rebalance timeout.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:10")]
+        public TimeSpan RebalanceTimeout { get; set; }
+
+        /// <summary>
+        /// Gets or sets delay upon a node joining or leaving topology (or crash) 
+        /// after which rebalancing should be started automatically. 
+        /// Rebalancing should be delayed if you plan to restart nodes
+        /// after they leave topology, or if you plan to start multiple nodes at once or one after another
+        /// and don't want to repartition and rebalance until all nodes are started.
+        /// </summary>
+        public TimeSpan RebalanceDelay { get; set; }
+
+        /// <summary>
+        /// Time to wait between rebalance messages to avoid overloading of CPU or network.
+        /// When rebalancing large data sets, the CPU or network can get over-consumed with rebalancing messages,
+        /// which consecutively may slow down the application performance. This parameter helps tune 
+        /// the amount of time to wait between rebalance messages to make sure that rebalancing process
+        /// does not have any negative performance impact. Note that application will continue to work
+        /// properly while rebalancing is still in progress.
+        /// <para/>
+        /// Value of 0 means that throttling is disabled.
+        /// </summary>
+        public TimeSpan RebalanceThrottle { get; set; }
+
+        /// <summary>
+        /// Gets or sets maximum amount of memory available to off-heap storage. Possible values are
+        /// -1 means that off-heap storage is disabled. 0 means that Ignite will not limit off-heap storage 
+        /// (it's up to user to properly add and remove entries from cache to ensure that off-heap storage 
+        /// does not grow indefinitely.
+        /// Any positive value specifies the limit of off-heap storage in bytes.
+        /// </summary>
+        [DefaultValue(DefaultOffHeapMaxMemory)]
+        public long OffHeapMaxMemory { get; set; }
+
+        /// <summary>
+        /// Gets or sets memory mode for cache.
+        /// </summary>
+        [DefaultValue(DefaultMemoryMode)]
+        public CacheMemoryMode MemoryMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether data can be read from backup.
+        /// </summary>
+        [DefaultValue(DefaultReadFromBackup)]
+        public bool ReadFromBackup { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether copy of of the value stored in cache should be created
+        /// for cache operation implying return value. 
+        /// </summary>
+        [DefaultValue(DefaultCopyOnRead)]
+        public bool CopyOnRead { get; set; }
+
+        /// <summary>
+        /// Gets or sets the timeout after which long query warning will be printed.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:03")]
+        public TimeSpan LongQueryWarningTimeout { get; set; }
+
+        /// <summary>
+        /// If true all the SQL table and field names will be escaped with double quotes like 
+        /// ({ "tableName"."fieldsName"}). This enforces case sensitivity for field names and
+        /// also allows having special characters in table and field names.
+        /// </summary>
+        public bool SqlEscapeAll { get; set; }
+
+        /// <summary>
+        /// Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access.
+        /// This setting only makes sense when offheap is enabled for this cache.
+        /// </summary>
+        [DefaultValue(DefaultSqlOnheapRowCacheSize)]
+        public int SqlOnheapRowCacheSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the factory for underlying persistent storage for read-through and write-through operations.
+        /// </summary>
+        public IFactory<ICacheStore> CacheStoreFactory { get; set; }
+
+        /// <summary>
+        /// Gets or sets the query entity configuration.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<QueryEntity> QueryEntities { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMemoryMode.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMemoryMode.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMemoryMode.cs
new file mode 100644
index 0000000..a072302
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMemoryMode.cs
@@ -0,0 +1,60 @@
+/*
+ * 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.Cache.Configuration
+{
+    /// <summary>
+    /// Memory modes define whether cache entries are stored on heap memory, offheap memory, or in swap space.
+    /// </summary>
+    public enum CacheMemoryMode
+    {
+        /// <summary>
+        /// Entries will be stored on-heap first. The onheap tiered storage works as follows:
+        /// <list type="bullet">
+        /// <item><description>
+        /// Entries are cached on heap memory first.
+        /// </description></item>
+        /// <item><description>
+        /// If offheap memory is enabled and eviction policy evicts an entry from heap memory, 
+        /// entry will be moved to offheap memory. If offheap memory is disabled, then entry is simply discarded.
+        /// </description></item>
+        /// <item><description>
+        /// If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space. 
+        /// If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, 
+        /// then entry will be evicted directly from heap memory into swap.
+        /// </description></item>
+        /// </list>
+        /// <para />
+        /// Note that heap memory evictions are handled by configured EvictionPolicy implementation. By default, 
+        /// no eviction policy is enabled, so entries never leave heap memory space unless explicitly removed.
+        /// </summary>
+        OnheapTiered,
+
+        /// <summary>
+        /// Works the same as <see cref="OnheapTiered"/>, except that entries never end up in heap memory and get 
+        /// stored in offheap memory right away. Entries get cached in offheap memory first and then 
+        /// get evicted to swap, if one is configured.
+        /// </summary>
+        OffheapTiered,
+
+        /// <summary>
+        /// Entry keys will be stored on heap memory, and values will be stored in offheap memory.
+        /// Note that in this mode entries can be evicted only to swap.
+        /// </summary>
+        OffheapValues
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMode.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMode.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMode.cs
new file mode 100644
index 0000000..6608354
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheMode.cs
@@ -0,0 +1,52 @@
+/*
+ * 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.Cache.Configuration
+{
+    /// <summary>
+    /// Caching modes.
+    /// </summary>
+    public enum CacheMode
+    {
+        /// <summary>
+        /// Specifies local-only cache behaviour. In this mode caches residing on
+        /// different grid nodes will not know about each other.
+        /// <para />
+        /// Other than distribution, <see cref="Local"/> caches still have all
+        /// the caching features, such as eviction, expiration, swapping,
+        /// querying, etc... This mode is very useful when caching read-only data
+        /// or data that automatically expires at a certain interval and
+        /// then automatically reloaded from persistence store.
+        /// </summary>
+        Local,
+
+        /// <summary>
+        /// Specifies fully replicated cache behavior. In this mode all the keys are distributed
+        /// to all participating nodes. 
+        /// </summary>
+        Replicated,
+
+        /// <summary>
+        /// Specifies partitioned cache behaviour. In this mode the overall
+        /// key set will be divided into partitions and all partitions will be split
+        /// equally between participating nodes. 
+        /// <para />
+        /// Note that partitioned cache is always fronted by local 'near' cache which stores most recent data. 
+        /// </summary>
+        Partitioned
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheRebalanceMode.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheRebalanceMode.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheRebalanceMode.cs
new file mode 100644
index 0000000..2ef2115
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheRebalanceMode.cs
@@ -0,0 +1,51 @@
+/*
+ * 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.Cache.Configuration
+{
+    /// <summary>
+    /// Cache rebalance mode. When rebalancing is enabled (i.e. has value other than <see cref="None"/>), 
+    /// distributed caches will attempt to rebalance all necessary values from other grid nodes. 
+    /// <para />
+    /// Replicated caches will try to load the full set of cache entries from other nodes, 
+    /// while partitioned caches will only load the entries for which current node is primary or backup.
+    /// <para />
+    /// Note that rebalance mode only makes sense for <see cref="CacheMode.Replicated"/> 
+    /// and <see cref="CacheMode.Partitioned"/> caches. Caches with <see cref="CacheMode.Local"/> 
+    /// mode are local by definition and therefore cannot rebalance any values from neighboring nodes.
+    /// </summary>
+    public enum CacheRebalanceMode
+    {
+        /// <summary>
+        /// Synchronous rebalance mode. Distributed caches will not start until all necessary data
+        /// is loaded from other available grid nodes.
+        /// </summary>
+        Sync,
+
+        /// <summary>
+        /// Asynchronous rebalance mode. Distributed caches will start immediately and will load all necessary
+        /// data from other available grid nodes in the background.
+        /// </summary>
+        Async,
+
+        /// <summary>
+        /// In this mode no rebalancing will take place which means that caches will be either loaded on
+        /// demand from persistent store whenever data is accessed, or will be populated explicitly.
+        /// </summary>
+        None
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheWriteSynchronizationMode.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheWriteSynchronizationMode.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheWriteSynchronizationMode.cs
new file mode 100644
index 0000000..3257f15
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheWriteSynchronizationMode.cs
@@ -0,0 +1,45 @@
+/*
+ * 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.Cache.Configuration
+{
+    /// <summary>
+    /// Mode indicating how Ignite should wait for write replies from other nodes.
+    /// </summary>
+    public enum CacheWriteSynchronizationMode
+    {
+        /// <summary>
+        /// Mode indicating that Ignite should wait for write or commit replies from all nodes.
+        /// This behavior guarantees that whenever any of the atomic or transactional writes
+        /// complete, all other participating nodes which cache the written data have been updated.
+        /// </summary>
+        FullSync,
+
+        /// <summary>
+        /// Flag indicating that Ignite will not wait for write or commit responses from participating nodes,
+        /// which means that remote nodes may get their state updated a bit after any of the cache write methods
+        /// complete, or after {@link Transaction#commit()} method completes.
+        /// </summary>
+        FullAsync,
+
+        /// <summary>
+        /// This flag only makes sense for {@link CacheMode#PARTITIONED} mode. When enabled, Ignite will wait 
+        /// for write or commit to complete on primary node, but will not wait for backups to be updated.
+        /// </summary>
+        PrimarySync
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryAlias.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryAlias.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryAlias.cs
new file mode 100644
index 0000000..33849c7
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryAlias.cs
@@ -0,0 +1,59 @@
+/*
+ * 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.Cache.Configuration
+{
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Represents cache query configuration alias.
+    /// </summary>
+    public class QueryAlias
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryAlias"/> class.
+        /// </summary>
+        public QueryAlias()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryAlias"/> class.
+        /// </summary>
+        /// <param name="fullName">The full name.</param>
+        /// <param name="alias">The alias.</param>
+        public QueryAlias(string fullName, string alias)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(fullName, "fullName");
+            IgniteArgumentCheck.NotNullOrEmpty(alias, "alias");
+
+            FullName = fullName;
+            Alias = alias;
+        }
+
+        /// <summary>
+        /// Gets or sets the full name of the query field.
+        /// </summary>
+        public string FullName { get; set; }
+        
+        /// <summary>
+        /// Gets or sets the alias for the full name.
+        /// </summary>
+        public string Alias { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
new file mode 100644
index 0000000..4151540
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
@@ -0,0 +1,401 @@
+/*
+ * 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.Global
+// ReSharper disable MemberCanBePrivate.Global
+namespace Apache.Ignite.Core.Cache.Configuration
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
+    using System.Reflection;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary;
+
+    /// <summary>
+    /// Query entity is a description of cache entry (composed of key and value) 
+    /// in a way of how it must be indexed and can be queried.
+    /// </summary>
+    public class QueryEntity
+    {
+        /** */
+        private Type _keyType;
+
+        /** */
+        private Type _valueType;
+
+        /** */
+        private string _valueTypeName;
+
+        /** */
+        private string _keyTypeName;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryEntity"/> class.
+        /// </summary>
+        public QueryEntity()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryEntity"/> class.
+        /// </summary>
+        /// <param name="valueType">Type of the cache entry value.</param>
+        public QueryEntity(Type valueType)
+        {
+            ValueType = valueType;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryEntity"/> class.
+        /// </summary>
+        /// <param name="keyType">Type of the key.</param>
+        /// <param name="valueType">Type of the value.</param>
+        public QueryEntity(Type keyType, Type valueType)
+        {
+            KeyType = keyType;
+            ValueType = valueType;
+        }
+
+        /// <summary>
+        /// Gets or sets key Java type name.
+        /// </summary>
+        public string KeyTypeName
+        {
+            get { return _keyTypeName; }
+            set
+            {
+                _keyTypeName = value;
+                _keyType = null;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the type of the key.
+        /// <para />
+        /// This is a shortcut for <see cref="KeyTypeName"/>. Getter will return null for non-primitive types.
+        /// <para />
+        /// Setting this property will overwrite <see cref="Fields"/> and <see cref="Indexes"/> according to
+        /// <see cref="QuerySqlFieldAttribute"/>, if any.
+        /// </summary>
+        public Type KeyType
+        {
+            get { return _keyType ?? JavaTypes.GetDotNetType(KeyTypeName); }
+            set
+            {
+                RescanAttributes(value, _valueType);  // Do this first because it can throw
+
+                KeyTypeName = value == null
+                    ? null
+                    : (JavaTypes.GetJavaTypeName(value) ?? BinaryUtils.GetTypeName(value));
+
+                _keyType = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets value Java type name.
+        /// </summary>
+        public string ValueTypeName
+        {
+            get { return _valueTypeName; }
+            set
+            {
+                _valueTypeName = value;
+                _valueType = null;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the type of the value.
+        /// <para />
+        /// This is a shortcut for <see cref="ValueTypeName"/>. Getter will return null for non-primitive types.
+        /// <para />
+        /// Setting this property will overwrite <see cref="Fields"/> and <see cref="Indexes"/> according to
+        /// <see cref="QuerySqlFieldAttribute"/>, if any.
+        /// </summary>
+        public Type ValueType
+        {
+            get { return _valueType ?? JavaTypes.GetDotNetType(ValueTypeName); }
+            set
+            {
+                RescanAttributes(_keyType, value);  // Do this first because it can throw
+
+                ValueTypeName = value == null
+                    ? null
+                    : (JavaTypes.GetJavaTypeName(value) ?? BinaryUtils.GetTypeName(value));
+
+                _valueType = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets query fields, a map from field name to Java type name. 
+        /// The order of fields defines the order of columns returned by the 'select *' queries.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<QueryField> Fields { get; set; }
+
+        /// <summary>
+        /// Gets or sets field name aliases: mapping from full name in dot notation to an alias 
+        /// that will be used as SQL column name.
+        /// Example: {"parent.name" -> "parentName"}.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<QueryAlias> Aliases { get; set; }
+
+        /// <summary>
+        /// Gets or sets the query indexes.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<QueryIndex> Indexes { get; set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryEntity"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        internal QueryEntity(IBinaryRawReader reader)
+        {
+            KeyTypeName = reader.ReadString();
+            ValueTypeName = reader.ReadString();
+
+            var count = reader.ReadInt();
+            Fields = count == 0 ? null : Enumerable.Range(0, count).Select(x =>
+                    new QueryField(reader.ReadString(), reader.ReadString())).ToList();
+
+            count = reader.ReadInt();
+            Aliases = count == 0 ? null : Enumerable.Range(0, count)
+                .Select(x=> new QueryAlias(reader.ReadString(), reader.ReadString())).ToList();
+
+            count = reader.ReadInt();
+            Indexes = count == 0 ? null : Enumerable.Range(0, count).Select(x => new QueryIndex(reader)).ToList();
+        }
+
+        /// <summary>
+        /// Writes this instance.
+        /// </summary>
+        internal void Write(IBinaryRawWriter writer)
+        {
+            writer.WriteString(KeyTypeName);
+            writer.WriteString(ValueTypeName);
+
+            if (Fields != null)
+            {
+                writer.WriteInt(Fields.Count);
+
+                foreach (var field in Fields)
+                {
+                    writer.WriteString(field.Name);
+                    writer.WriteString(field.FieldTypeName);
+                }
+            }
+            else
+                writer.WriteInt(0);
+
+
+            if (Aliases != null)
+            {
+                writer.WriteInt(Aliases.Count);
+
+                foreach (var queryAlias in Aliases)
+                {
+                    writer.WriteString(queryAlias.FullName);
+                    writer.WriteString(queryAlias.Alias);
+                }
+            }
+            else
+                writer.WriteInt(0);
+
+            if (Indexes != null)
+            {
+                writer.WriteInt(Indexes.Count);
+
+                foreach (var index in Indexes)
+                {
+                    if (index == null)
+                        throw new InvalidOperationException("Invalid cache configuration: QueryIndex can't be null.");
+
+                    index.Write(writer);
+                }
+            }
+            else
+                writer.WriteInt(0);
+        }
+
+
+        /// <summary>
+        /// Rescans the attributes in <see cref="KeyType"/> and <see cref="ValueType"/>.
+        /// </summary>
+        private void RescanAttributes(params Type[] types)
+        {
+            if (types.Length == 0 || types.All(t => t == null))
+                return;
+
+            var fields = new List<QueryField>();
+            var indexes = new List<QueryIndexEx>();
+
+            foreach (var type in types.Where(t => t != null))
+                ScanAttributes(type, fields, indexes, null, new HashSet<Type>());
+
+            if (fields.Any())
+                Fields = fields;
+
+            if (indexes.Any())
+                Indexes = GetGroupIndexes(indexes).ToArray();
+        }
+
+        /// <summary>
+        /// Gets the group indexes.
+        /// </summary>
+        /// <param name="indexes">Ungrouped indexes with their group names.</param>
+        /// <returns></returns>
+        private static IEnumerable<QueryIndex> GetGroupIndexes(List<QueryIndexEx> indexes)
+        {
+            return indexes.Where(idx => idx.IndexGroups != null)
+                .SelectMany(idx => idx.IndexGroups.Select(g => new {Index = idx, GroupName = g}))
+                .GroupBy(x => x.GroupName)
+                .Select(g =>
+                {
+                    var idxs = g.Select(pair => pair.Index).ToArray();
+
+                    var first = idxs.First();
+
+                    return new QueryIndex(idxs.SelectMany(i => i.Fields).ToArray())
+                    {
+                        IndexType = first.IndexType,
+                        Name = first.Name
+                    };
+                })
+                .Concat(indexes.Where(idx => idx.IndexGroups == null));
+        }
+
+        /// <summary>
+        /// Scans specified type for occurences of <see cref="QuerySqlFieldAttribute"/>.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="fields">The fields.</param>
+        /// <param name="indexes">The indexes.</param>
+        /// <param name="parentPropName">Name of the parent property.</param>
+        /// <param name="visitedTypes">The visited types.</param>
+        private static void ScanAttributes(Type type, List<QueryField> fields, List<QueryIndexEx> indexes, 
+            string parentPropName, ISet<Type> visitedTypes)
+        {
+            Debug.Assert(type != null);
+            Debug.Assert(fields != null);
+            Debug.Assert(indexes != null);
+
+            if (visitedTypes.Contains(type))
+                throw new InvalidOperationException("Recursive Query Field definition detected: " + type);
+
+            visitedTypes.Add(type);
+
+            foreach (var memberInfo in GetFieldsAndProperties(type))
+            {
+                var customAttributes = memberInfo.Key.GetCustomAttributes(true);
+
+                foreach (var attr in customAttributes.OfType<QuerySqlFieldAttribute>())
+                {
+                    var columnName = attr.Name ?? memberInfo.Key.Name;
+
+                    // Dot notation is required for nested SQL fields
+                    if (parentPropName != null)
+                        columnName = parentPropName + "." + columnName;
+
+                    fields.Add(new QueryField(columnName, memberInfo.Value));
+
+                    if (attr.IsIndexed)
+                        indexes.Add(new QueryIndexEx(columnName, attr.IsDescending, QueryIndexType.Sorted,
+                            attr.IndexGroups));
+
+                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes);
+                }
+
+                foreach (var attr in customAttributes.OfType<QueryTextFieldAttribute>())
+                {
+                    var columnName = attr.Name ?? memberInfo.Key.Name;
+
+                    // No dot notation for FullText index names
+                    indexes.Add(new QueryIndexEx(columnName, false, QueryIndexType.FullText, null));
+
+                    if (parentPropName != null)
+                        columnName = parentPropName + "." + columnName;
+
+                    fields.Add(new QueryField(columnName, memberInfo.Value));
+
+                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes);
+                }
+            }
+
+            visitedTypes.Remove(type);
+        }
+
+        /// <summary>
+        /// Gets the fields and properties.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns></returns>
+        private static IEnumerable<KeyValuePair<MemberInfo, Type>> GetFieldsAndProperties(Type type)
+        {
+            Debug.Assert(type != null);
+
+            if (type.IsPrimitive)
+                yield break;
+
+            var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
+                               BindingFlags.DeclaredOnly;
+
+            while (type != typeof (object) && type != null)
+            {
+                foreach (var fieldInfo in type.GetFields(bindingFlags))
+                    yield return new KeyValuePair<MemberInfo, Type>(fieldInfo, fieldInfo.FieldType);
+
+                foreach (var propertyInfo in type.GetProperties(bindingFlags))
+                    yield return new KeyValuePair<MemberInfo, Type>(propertyInfo, propertyInfo.PropertyType);
+
+                type = type.BaseType;
+            }
+        }
+
+        /// <summary>
+        /// Extended index with group names.
+        /// </summary>
+        private class QueryIndexEx : QueryIndex
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see cref="QueryIndexEx"/> class.
+            /// </summary>
+            /// <param name="fieldName">Name of the field.</param>
+            /// <param name="isDescending">if set to <c>true</c> [is descending].</param>
+            /// <param name="indexType">Type of the index.</param>
+            /// <param name="groups">The groups.</param>
+            public QueryIndexEx(string fieldName, bool isDescending, QueryIndexType indexType, 
+                ICollection<string> groups) 
+                : base(isDescending, indexType, fieldName)
+            {
+                IndexGroups = groups;
+            }
+
+            /// <summary>
+            /// Gets or sets the index groups.
+            /// </summary>
+            public ICollection<string> IndexGroups { get; set; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs
new file mode 100644
index 0000000..8c70a29
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs
@@ -0,0 +1,109 @@
+/*
+ * 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.Global
+// ReSharper disable MemberCanBePrivate.Global
+namespace Apache.Ignite.Core.Cache.Configuration
+{
+    using System;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Represents a queryable field.
+    /// </summary>
+    public class QueryField
+    {
+        /** */
+        private Type _type;
+
+        /** */
+        private string _fieldTypeName;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryField"/> class.
+        /// </summary>
+        public QueryField()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryField"/> class.
+        /// </summary>
+        /// <param name="name">Name.</param>
+        /// <param name="javaFieldTypeName">Java type name.</param>
+        public QueryField(string name, string javaFieldTypeName)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+            IgniteArgumentCheck.NotNullOrEmpty(javaFieldTypeName, "typeName");
+
+            Name = name;
+            FieldTypeName = javaFieldTypeName;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryField" /> class.
+        /// </summary>
+        /// <param name="name">Name.</param>
+        /// <param name="fieldType">Type.</param>
+        public QueryField(string name, Type fieldType)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+            IgniteArgumentCheck.NotNull(fieldType, "type");
+
+            Name = name;
+            FieldType = fieldType;
+        }
+
+        /// <summary>
+        /// Gets the field name.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the value.
+        /// <para />
+        /// This is a shortcut for <see cref="FieldTypeName"/>. Getter will return null for non-primitive types.
+        /// </summary>
+        public Type FieldType
+        {
+            get { return _type ?? JavaTypes.GetDotNetType(FieldTypeName); }
+            set
+            {
+                FieldTypeName = value == null
+                    ? null
+                    : (JavaTypes.GetJavaTypeName(value) ?? BinaryUtils.GetTypeName(value));
+
+                _type = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the Java type name.
+        /// </summary>
+        public string FieldTypeName
+        {
+            get { return _fieldTypeName; }
+            set
+            {
+                _fieldTypeName = value;
+                _type = null;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndex.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndex.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndex.cs
new file mode 100644
index 0000000..7079606
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndex.cs
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable UnusedMember.Global
+namespace Apache.Ignite.Core.Cache.Configuration
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Represents cache query index configuration.
+    /// </summary>
+    public class QueryIndex
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex"/> class.
+        /// </summary>
+        public QueryIndex()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex" /> class.
+        /// </summary>
+        /// <param name="fieldNames">Names of the fields to index.</param>
+        public QueryIndex(params string[] fieldNames) : this(false, fieldNames)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex" /> class.
+        /// </summary>
+        /// <param name="isDescending">Sort direction.</param>
+        /// <param name="fieldNames">Names of the fields to index.</param>
+        public QueryIndex(bool isDescending, params string[] fieldNames)
+        {
+            Fields = fieldNames.Select(f => new QueryIndexField(f, isDescending)).ToArray();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex" /> class.
+        /// </summary>
+        /// <param name="isDescending">Sort direction.</param>
+        /// <param name="indexType">Type of the index.</param>
+        /// <param name="fieldNames">Names of the fields to index.</param>
+        public QueryIndex(bool isDescending, QueryIndexType indexType, params string[] fieldNames) 
+            : this(isDescending, fieldNames)
+        {
+            IndexType = indexType;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex"/> class.
+        /// </summary>
+        /// <param name="fields">The fields.</param>
+        public QueryIndex(params QueryIndexField[] fields)
+        {
+            if (fields == null || fields.Length == 0)
+                throw new ArgumentException("Query index must have at least one field");
+
+            if (fields.Any(f => f == null))
+                throw new ArgumentException("IndexField cannot be null.");
+
+            Fields = fields;
+        }
+
+        /// <summary>
+        /// Gets or sets the index name.
+        /// Will be set automatically if not specified.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the index.
+        /// </summary>
+        public QueryIndexType IndexType { get; set; }
+
+        /// <summary>
+        /// Gets or sets a collection of fields to be indexed.
+        /// </summary>
+        public ICollection<QueryIndexField> Fields { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndex"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        internal QueryIndex(IBinaryRawReader reader)
+        {
+            Name = reader.ReadString();
+            IndexType = (QueryIndexType) reader.ReadByte();
+
+            var count = reader.ReadInt();
+            Fields = count == 0 ? null : Enumerable.Range(0, count).Select(x =>
+                new QueryIndexField(reader.ReadString(), reader.ReadBoolean())).ToList();
+        }
+
+        /// <summary>
+        /// Writes this instance.
+        /// </summary>
+        internal void Write(IBinaryRawWriter writer)
+        {
+            writer.WriteString(Name);
+            writer.WriteByte((byte) IndexType);
+
+            if (Fields != null)
+            {
+                writer.WriteInt(Fields.Count);
+
+                foreach (var field in Fields)
+                {
+                    writer.WriteString(field.Name);
+                    writer.WriteBoolean(field.IsDescending);
+                }
+            }
+            else
+                writer.WriteInt(0);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexField.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexField.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexField.cs
new file mode 100644
index 0000000..0b11e9c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexField.cs
@@ -0,0 +1,66 @@
+/*
+ * 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.Cache.Configuration
+{
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Represents an indexed field.
+    /// </summary>
+    public class QueryIndexField
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndexField"/> class.
+        /// </summary>
+        public QueryIndexField()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndexField"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        public QueryIndexField(string name)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+
+            Name = name;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryIndexField"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="isDescending">Sort direction.</param>
+        public QueryIndexField(string name, bool isDescending) : this (name)
+        {
+            IsDescending = isDescending;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets a value indicating whether this index is descending. Default is false.
+        /// </summary>
+        public bool IsDescending { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexType.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexType.cs
new file mode 100644
index 0000000..25fed62
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryIndexType.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.Cache.Configuration
+{
+    /// <summary>
+    /// Query index type.
+    /// </summary>
+    public enum QueryIndexType
+    {
+        /// <summary>
+        /// Sorted index.
+        /// </summary>
+        Sorted,
+
+        /// <summary>
+        /// Fulltext index.
+        /// </summary>
+        FullText,
+
+        /// <summary>
+        /// Geo-spatial index.
+        /// </summary>
+        Geospatial
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs
new file mode 100644
index 0000000..a522115
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs
@@ -0,0 +1,60 @@
+/*
+ * 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.Cache.Configuration
+{
+    using System;
+    using System.Diagnostics.CodeAnalysis;
+
+    /// <summary>
+    /// Marks field or property for SQL queries.
+    /// <para />
+    /// Using this attribute is an alternative to <see cref="QueryEntity.Fields"/> in <see cref="CacheConfiguration"/>.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+    public sealed class QuerySqlFieldAttribute : Attribute
+    {
+        /// <summary>
+        /// Gets or sets the sql field name.
+        /// If not provided, property or field name will be used.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether corresponding field should be indexed.
+        /// Just like with databases, field indexing may require additional overhead during updates, 
+        /// but makes select operations faster.
+        /// </summary>
+        public bool IsIndexed { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether index for this field should be descending.
+        /// Ignored when <see cref="IsIndexed"/> is <c>false</c>.
+        /// </summary>
+        public bool IsDescending { get; set; }
+
+        /// <summary>
+        /// Gets or sets the collection of index groups this field belongs to. 
+        /// Groups are used for compound indexes, 
+        /// whenever index should be created on more than one field.
+        /// All fields within the same group will belong to the same index.
+        /// </summary>
+        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", 
+            Justification = "Attribute initializers do not allow collections")]
+        public string[] IndexGroups { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryTextFieldAttribute.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryTextFieldAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryTextFieldAttribute.cs
new file mode 100644
index 0000000..6386496
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryTextFieldAttribute.cs
@@ -0,0 +1,36 @@
+/*
+ * 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.Cache.Configuration
+{
+    using System;
+
+    /// <summary>
+    /// Marks field or property for Text queries.
+    /// <para />
+    /// Using this attribute is an alternative to <see cref="QueryEntity.Fields"/> in <see cref="CacheConfiguration"/>.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+    public sealed class QueryTextFieldAttribute : Attribute
+    {
+        /// <summary>
+        /// Gets or sets the text field name.
+        /// If not provided, property or field name will be used.
+        /// </summary>
+        public string Name { get; set; }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
index 192dabf..f5e7cd2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Cache
     using System.Collections.Generic;
     using System.Diagnostics.CodeAnalysis;
     using System.Threading.Tasks;
+    using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Expiry;
     using Apache.Ignite.Core.Cache.Query;
     using Apache.Ignite.Core.Cache.Query.Continuous;
@@ -66,6 +67,11 @@ namespace Apache.Ignite.Core.Cache
         IIgnite Ignite { get; }
 
         /// <summary>
+        /// Gets the cache configuration.
+        /// </summary>
+        CacheConfiguration GetConfiguration();
+
+        /// <summary>
         /// Checks whether this cache contains no key-value mappings.
         /// <para />
         /// Semantically equals to <c>ICache.Size(CachePeekMode.PRIMARY) == 0</c>.

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Common/IFactory.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Common/IFactory.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Common/IFactory.cs
new file mode 100644
index 0000000..67c2683
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Common/IFactory.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.Common
+{
+    using System;
+
+    /// <summary>
+    /// Factory that produces instances of a specific type.
+    /// Implementation can be passed over the wire and thus should be marked with <see cref="SerializableAttribute"/>.
+    /// </summary>
+    public interface IFactory<out T>
+    {
+        /// <summary>
+        /// Creates an instance of the cache store.
+        /// </summary>
+        /// <returns>New instance of the cache store.</returns>
+        T CreateInstance();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/IDiscoverySpi.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/IDiscoverySpi.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/IDiscoverySpi.cs
new file mode 100644
index 0000000..2fcafbf
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/IDiscoverySpi.cs
@@ -0,0 +1,32 @@
+/*
+ * 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.Discovery
+{
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Discovery.Tcp;
+
+    /// <summary>
+    /// Represents a discovery service provider interface.
+    /// Only predefined implementation is supported now: <see cref="TcpDiscoverySpi"/>.
+    /// </summary>
+    [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")]
+    public interface IDiscoverySpi
+    {
+        // No-op.
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ee20f1d9/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/Tcp/ITcpDiscoveryIpFinder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/Tcp/ITcpDiscoveryIpFinder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/Tcp/ITcpDiscoveryIpFinder.cs
new file mode 100644
index 0000000..c2f4329
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Discovery/Tcp/ITcpDiscoveryIpFinder.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.Discovery.Tcp
+{
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Discovery.Tcp.Multicast;
+    using Apache.Ignite.Core.Discovery.Tcp.Static;
+
+    /// <summary>
+    /// Represents an IP finder for <see cref="TcpDiscoverySpi"/>.
+    /// Only predefined implementations are supported now: 
+    /// <see cref="TcpDiscoveryStaticIpFinder"/>, <see cref="TcpDiscoveryMulticastIpFinder"/>.
+    /// </summary>
+    [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")]
+    public interface ITcpDiscoveryIpFinder
+    {
+        // No-op.
+    }
+}
\ No newline at end of file