Repository: ignite
Updated Branches:
  refs/heads/master dddf6ba0f -> 77a9aaca1


http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs
 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs
new file mode 100644
index 0000000..d1ba5da
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs
@@ -0,0 +1,534 @@
+/*
+ * 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.AspNet.Impl
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Collections.Specialized;
+    using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
+    using System.Linq;
+    using System.Runtime.Serialization.Formatters.Binary;
+    using System.Web.SessionState;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Binarizable key-value collection with dirty item tracking.
+    /// </summary>
+    internal class IgniteSessionStateItemCollection : 
ISessionStateItemCollection
+    {
+        /** */
+        private readonly Dictionary<string, int> _dict;
+
+        /** */
+        private readonly List<Entry> _list;
+
+        /** Indicates where this is a new collection, not a deserialized old 
one. */
+        private readonly bool _isNew;
+
+        /** Removed keys. Hash set because keys can be removed multiple times. 
*/
+        private HashSet<string> _removedKeys;
+
+        /** Indicates that entire collection is dirty and can't be written as 
a diff. */
+        private bool _dirtyAll;
+
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="IgniteSessionStateItemCollection"/> class.
+        /// </summary>
+        /// <param name="reader">The binary reader.</param>
+        internal IgniteSessionStateItemCollection(IBinaryRawReader reader)
+        {
+            Debug.Assert(reader != null);
+
+            var count = reader.ReadInt();
+
+            _dict = new Dictionary<string, int>(count);
+            _list = new List<Entry>(count);
+
+            for (var i = 0; i < count; i++)
+            {
+                var key = reader.ReadString();
+
+                var valBytes = reader.ReadByteArray();
+
+                if (valBytes != null)
+                {
+                    var entry = new Entry(key, true, valBytes);
+
+                    _dict[key] = _list.Count;
+
+                    _list.Add(entry);
+                }
+                else
+                    AddRemovedKey(key);
+            }
+
+            _isNew = false;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="IgniteSessionStateItemCollection"/> class.
+        /// </summary>
+        public IgniteSessionStateItemCollection()
+        {
+            _dict = new Dictionary<string, int>();
+            _list = new List<Entry>();
+            _isNew = true;
+        }
+
+        /** <inheritdoc /> */
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of 
public methods", MessageId = "0", 
+            Justification = "Validation is present.")]
+        public void CopyTo(Array array, int index)
+        {
+            IgniteArgumentCheck.NotNull(array, "array");
+            IgniteArgumentCheck.Ensure(Count + index < array.Length, "array",
+                "The number of elements in the source collection is greater 
than the available space " +
+                "from specified index to the end of the array.");
+
+            // This should return only keys.
+            foreach (var entry in _list)
+                array.SetValue(entry.Key, index++);
+        }
+
+        /** <inheritdoc /> */
+        public IEnumerator GetEnumerator()
+        {
+            // This should return only keys.
+            return _list.Select(x => x.Key).GetEnumerator();
+        }
+
+        /** <inheritdoc /> */
+        public int Count
+        {
+            get { return _dict.Count; }
+        }
+
+        /** <inheritdoc /> */
+        public object SyncRoot
+        {
+            get { return _list; }
+        }
+
+        /** <inheritdoc /> */
+        public bool IsSynchronized
+        {
+            get { return false; }
+        }
+
+        /** <inheritdoc /> */
+        public object this[string key]
+        {
+            get
+            {
+                var entry = GetEntry(key);
+
+                if (entry == null)
+                    return null;
+
+                SetDirtyOnRead(entry);
+
+                return entry.Value;
+            }
+            set
+            {
+                var entry = GetOrCreateDirtyEntry(key);
+
+                entry.Value = value;
+            }
+        }
+
+        /** <inheritdoc /> */
+        public object this[int index]
+        {
+            get
+            {
+                var entry = _list[index];
+
+                SetDirtyOnRead(entry);
+
+                return entry.Value;
+            }
+            set
+            {
+                var entry = _list[index];
+
+                entry.IsDirty = true;
+
+                entry.Value = value;
+            }
+        }
+
+        /** <inheritdoc /> */
+        public NameObjectCollectionBase.KeysCollection Keys
+        {
+            get { return new NameObjectCollection(this).Keys; }
+        }
+
+
+        /** <inheritdoc /> */
+        public bool Dirty
+        {
+            get { return _dirtyAll || _list.Any(x => x.IsDirty); }
+            set { _dirtyAll = value; }
+        }
+
+        /// <summary>
+        /// Writes this object to the given writer.
+        /// </summary>
+        public void WriteBinary(IBinaryRawWriter writer, bool changesOnly)
+        {
+            IgniteArgumentCheck.NotNull(writer, "writer");
+
+            if (_isNew || _dirtyAll || !changesOnly || (_removedKeys == null 
&& _list.All(x => x.IsDirty)))
+            {
+                // Write in full mode.
+                writer.WriteInt(_list.Count);
+
+                foreach (var entry in _list)
+                {
+                    writer.WriteString(entry.Key);
+
+                    // Write as byte array to enable partial deserialization.
+                    writer.WriteByteArray(entry.GetBytes());
+                }
+            }
+            else
+            {
+                // Write in diff mode.
+                var removed = GetRemovedKeys();
+
+                var count = _list.Count(x => x.IsDirty) + (removed == null ? 0 
: removed.Count);
+
+                writer.WriteInt(count);  // reserve count
+
+                // Write removed keys as [key + null].
+                if (removed != null)
+                {
+                    foreach (var removedKey in removed)
+                    {
+                        writer.WriteString(removedKey);
+                        writer.WriteByteArray(null);
+                    }
+                }
+
+                // Write dirty items.
+                foreach (var entry in _list)
+                {
+                    if (!entry.IsDirty)
+                        continue;
+
+                    writer.WriteString(entry.Key);
+
+                    // Write as byte array to enable partial deserialization.
+                    writer.WriteByteArray(entry.GetBytes());
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the removed keys.
+        /// </summary>
+        private ICollection<string> GetRemovedKeys()
+        {
+            if (_removedKeys == null)
+                return null;
+
+            // Filter out existing keys.
+            var removed = new HashSet<string>(_removedKeys);
+
+            foreach (var entry in _list)
+                removed.Remove(entry.Key);
+
+            return removed;
+        }
+
+        /// <summary>
+        /// Removes the specified key.
+        /// </summary>
+        public void Remove(string key)
+        {
+            var index = GetIndex(key);
+
+            if (index < 0)
+                return;
+
+            var entry = _list[index];
+            Debug.Assert(key == entry.Key);
+
+            _list.RemoveAt(index);
+            _dict.Remove(key);
+
+            // Update all indexes.
+            for (var i = 0; i < _list.Count; i++)
+                _dict[_list[i].Key] = i;
+
+            if (entry.IsInitial)
+                AddRemovedKey(key);
+        }
+
+        /// <summary>
+        /// Removes at specified index.
+        /// </summary>
+        public void RemoveAt(int index)
+        {
+            var entry = _list[index];
+
+            _list.RemoveAt(index);
+            _dict.Remove(entry.Key);
+
+            if (entry.IsInitial)
+                AddRemovedKey(entry.Key);
+        }
+
+        /// <summary>
+        /// Clears this instance.
+        /// </summary>
+        public void Clear()
+        {
+            foreach (var entry in _list)
+            {
+                if (entry.IsInitial)
+                    AddRemovedKey(entry.Key);
+            }
+
+            _list.Clear();
+            _dict.Clear();
+
+            _dirtyAll = true;
+        }
+
+        /// <summary>
+        /// Applies the changes.
+        /// </summary>
+        public void ApplyChanges(IgniteSessionStateItemCollection changes)
+        {
+            var removed = changes._removedKeys;
+
+            if (removed != null)
+            {
+                foreach (var key in removed)
+                    Remove(key);
+            }
+            else
+            {
+                // Not a diff: replace all.
+                Clear();
+            }
+
+            foreach (var changedEntry in changes._list)
+            {
+                var entry = GetOrCreateDirtyEntry(changedEntry.Key);
+
+                // Copy without deserialization.
+                changedEntry.CopyTo(entry);
+            }
+        }
+
+        /// <summary>
+        /// Adds the removed key.
+        /// </summary>
+        private void AddRemovedKey(string key)
+        {
+            Debug.Assert(!_isNew);
+
+            if (_removedKeys == null)
+                _removedKeys = new HashSet<string>();
+
+            _removedKeys.Add(key);
+        }
+
+        /// <summary>
+        /// Gets or creates an entry.
+        /// </summary>
+        private Entry GetOrCreateDirtyEntry(string key)
+        {
+            var entry = GetEntry(key);
+
+            if (entry == null)
+            {
+                entry = new Entry(key, false, null);
+
+                _dict[key] = _list.Count;
+                _list.Add(entry);
+            }
+
+            entry.IsDirty = true;
+
+            return entry;
+        }
+
+        /// <summary>
+        /// Gets the entry.
+        /// </summary>
+        private Entry GetEntry(string key)
+        {
+            IgniteArgumentCheck.NotNull(key, "key");
+
+            int index;
+
+            return !_dict.TryGetValue(key, out index) ? null : _list[index];
+        }
+
+        /// <summary>
+        /// Gets the index.
+        /// </summary>
+        private int GetIndex(string key)
+        {
+            int index;
+
+            return !_dict.TryGetValue(key, out index) ? -1 : index;
+        }
+
+        /// <summary>
+        /// Sets the dirty on read.
+        /// </summary>
+        private static void SetDirtyOnRead(Entry entry)
+        {
+            var type = entry.Value.GetType();
+
+            if (IsImmutable(type))
+                return;
+
+            entry.IsDirty = true;
+        }
+
+        /// <summary>
+        /// Determines whether the specified type is immutable.
+        /// </summary>
+        private static bool IsImmutable(Type type)
+        {
+            type = Nullable.GetUnderlyingType(type) ?? type;  // Unwrap 
nullable.
+
+            if (type.IsPrimitive)
+                return true;
+
+            if (type == typeof(string) || type == typeof(DateTime) || type == 
typeof(Guid) || type == typeof(decimal))
+                return true;
+
+            return false;
+        }
+
+        /// <summary>
+        /// Inner entry.
+        /// </summary>
+        private class Entry
+        {
+            /** */
+            public readonly bool IsInitial;
+
+            /** */
+            public readonly string Key;
+
+            /** */
+            public bool IsDirty;
+
+            /** */
+            private object _value;
+
+            /** */
+            private bool _isDeserialized;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="Entry"/> class.
+            /// </summary>
+            public Entry(string key, bool isInitial, object value)
+            {
+                Debug.Assert(key != null);
+
+                Key = key;
+                IsInitial = isInitial;
+                _isDeserialized = !isInitial;
+                _value = value;
+            }
+
+            /// <summary>
+            /// Gets or sets the value.
+            /// </summary>
+            public object Value
+            {
+                get
+                {
+                    if (!_isDeserialized)
+                    {
+                        using (var stream = new MemoryStream((byte[])_value))
+                        {
+                            _value = new BinaryFormatter().Deserialize(stream);
+                        }
+
+                        _isDeserialized = true;
+                    }
+
+                    return _value;
+                }
+                set
+                {
+                    _value = value;
+                    _isDeserialized = true;
+                }
+            }
+
+            /// <summary>
+            /// Copies contents to another entry.
+            /// </summary>
+            public void CopyTo(Entry entry)
+            {
+                Debug.Assert(entry != null);
+
+                entry._isDeserialized = _isDeserialized;
+                entry._value = _value;
+            }
+
+            /// <summary>
+            /// Gets the bytes.
+            /// </summary>
+            public byte[] GetBytes()
+            {
+                if (!_isDeserialized)
+                    return (byte[]) _value;
+
+                using (var stream = new MemoryStream())
+                {
+                    new BinaryFormatter().Serialize(stream, _value);
+
+                    return stream.ToArray();
+                }
+            }
+        }
+
+        /// <summary>
+        /// NameObjectCollectionBase.KeysCollection has internal constructor.
+        /// The only way to implement ISessionStateItemCollection.Keys 
property 
+        /// is to have a NameObjectCollectionBase in hand.
+        /// </summary>
+        private class NameObjectCollection : NameObjectCollectionBase
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see 
cref="NameObjectCollection"/> class.
+            /// </summary>
+            public NameObjectCollection(IEnumerable keys)
+            {
+                foreach (string key in keys)
+                    BaseAdd(key, null);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs
 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs
new file mode 100644
index 0000000..32c36b5
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs
@@ -0,0 +1,116 @@
+/*
+ * 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.AspNet.Impl
+{
+    using System;
+    using System.IO;
+    using System.Web;
+    using System.Web.SessionState;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Ignite <see cref="SessionStateStoreData"/> implementation.
+    /// </summary>
+    internal class IgniteSessionStateStoreData : SessionStateStoreData
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="IgniteSessionStateStoreData"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        public IgniteSessionStateStoreData(IBinaryRawReader reader) : base(
+            new IgniteSessionStateItemCollection(reader),
+            DeserializeStaticObjects(reader.ReadByteArray()), reader.ReadInt())
+        {
+            LockNodeId = reader.ReadGuid();
+            LockId = reader.ReadLong();
+            LockTime = reader.ReadTimestamp();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="IgniteSessionStateStoreData"/> class.
+        /// </summary>
+        /// <param name="staticObjects">The static objects.</param>
+        /// <param name="timeout">The timeout.</param>
+        public IgniteSessionStateStoreData(HttpStaticObjectsCollection 
staticObjects, int timeout)
+            : base(new IgniteSessionStateItemCollection(), staticObjects, 
timeout)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Writes this object to the given writer.
+        /// </summary>
+        public void WriteBinary(IBinaryRawWriter writer, bool changesOnly)
+        {
+            ((IgniteSessionStateItemCollection)Items).WriteBinary(writer, 
changesOnly);
+            writer.WriteByteArray(SerializeStaticObjects());
+            writer.WriteInt(Timeout);
+
+            writer.WriteGuid(LockNodeId);
+            writer.WriteLong(LockId);
+            writer.WriteTimestamp(LockTime);
+        }
+
+        /// <summary>
+        /// Gets or sets the lock node id. Null means not locked.
+        /// </summary>
+        public Guid? LockNodeId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the lock id.
+        /// </summary>
+        public long LockId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the lock time.
+        /// </summary>
+        public DateTime? LockTime { get; set; }
+
+        /// <summary>
+        /// Deserializes the static objects.
+        /// </summary>
+        private static HttpStaticObjectsCollection 
DeserializeStaticObjects(byte[] bytes)
+        {
+            if (bytes == null)
+                return new HttpStaticObjectsCollection();
+
+            using (var stream = new MemoryStream(bytes))
+            using (var reader = new BinaryReader(stream))
+            {
+                return HttpStaticObjectsCollection.Deserialize(reader);
+            }
+        }
+
+        /// <summary>
+        /// Serializes the static objects.
+        /// </summary>
+        private byte[] SerializeStaticObjects()
+        {
+            if (StaticObjects == null || StaticObjects.Count == 0)
+                return null;
+
+            using (var stream = new MemoryStream())
+            using (var writer = new BinaryWriter(stream))
+            {
+                StaticObjects.Serialize(writer);
+
+                return stream.ToArray();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs
new file mode 100644
index 0000000..ebca8e0
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs
@@ -0,0 +1,91 @@
+/*
+ * 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.AspNet.Impl
+{
+    using System;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Result of the session state lock processor.
+    /// </summary>
+    internal class SessionStateLockResult
+    {
+        /** Success flag. */
+        private readonly bool _success;
+
+        /** Session state data. */
+        private readonly IgniteSessionStateStoreData _data;
+
+        /** Lock time. */
+        private readonly DateTime? _lockTime;
+
+        /** Lock id. */
+        private readonly long _lockId;
+
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="SessionStateLockResult"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        public SessionStateLockResult(IBinaryRawReader reader)
+        {
+            _success = reader.ReadBoolean();
+
+            if (_success)
+                _data = new IgniteSessionStateStoreData(reader);
+
+            _lockTime = reader.ReadTimestamp();
+            _lockId = reader.ReadLong();
+
+            Debug.Assert(_success ^ (_data == null));
+            Debug.Assert(_success ^ (_lockTime != null));
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether lock succeeded.
+        /// </summary>
+        public bool Success
+        {
+            get { return _success; }
+        }
+
+        /// <summary>
+        /// Gets the data. Null when <see cref="Success"/> is <c>false</c>.
+        /// </summary>
+        public IgniteSessionStateStoreData Data
+        {
+            get { return _data; }
+        }
+
+        /// <summary>
+        /// Gets the lock time. Null when <see cref="Success"/> is <c>true</c>.
+        /// </summary>
+        public DateTime? LockTime
+        {
+            get { return _lockTime; }
+        }
+
+        /// <summary>
+        /// Gets the lock identifier.
+        /// </summary>
+        public long LockId
+        {
+            get { return _lockId; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs 
b/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs
index ad61ecd..2a7da67 100644
--- a/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs
@@ -17,6 +17,7 @@
 
 using System;
 using System.Reflection;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 [assembly: AssemblyTitle("Apache.Ignite.AspNet")]
@@ -36,4 +37,6 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyFileVersion("1.8.0.14218")]
 [assembly: AssemblyInformationalVersion("1.8.0")]
 
-[assembly: CLSCompliant(true)]
\ No newline at end of file
+[assembly: CLSCompliant(true)]
+
+[assembly: InternalsVisibleTo("Apache.Ignite.AspNet.Tests, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9380ce05eb74bd7c531f72e9ea615c59d7eceb09bd9795cb3dff1fcf638fd799c2a58a9be42fff156efe1c8cdebb751e27763f6c9a7c80cdc1dc1bbf44283608ef18ccd5017fd57b2b026503637c89c2537f361807f3bdd49265f4d444716159d989342561d324b1a0961640338bb32eaf67f4ae0c95f1b210f65404b0909c6")]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/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 95fea8f..b1e0dbe 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
@@ -49,13 +49,11 @@
     <Reference Include="System.configuration" />
     <Reference Include="System.Core" />
     <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Web" />
     <Reference Include="System.ServiceProcess" />
     <Reference Include="System.XML" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="TestAppConfig.cs" />
-    <Compile Include="AspNet\IgniteOutputCacheProviderTest.cs" />
     <Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" />
     <Compile Include="Binary\BinaryCompactFooterInteropTest.cs" />
     <Compile Include="Binary\BinarySelfTestFullFooter.cs" />
@@ -167,10 +165,6 @@
     <Compile Include="WindowsServiceTest.cs" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference 
Include="..\Apache.Ignite.AspNet\Apache.Ignite.AspNet.csproj">
-      <Project>{13EA96FC-CC83-4164-A7C0-4F30ED797460}</Project>
-      <Name>Apache.Ignite.AspNet</Name>
-    </ProjectReference>
     <ProjectReference 
Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj">
       <Project>{4CD2F726-7E2B-46C4-A5BA-057BB82EECB6}</Project>
       <Name>Apache.Ignite.Core</Name>

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs
deleted file mode 100644
index 51bfdc1..0000000
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Tests.AspNet
-{
-    using System;
-    using System.Collections.Specialized;
-    using System.Threading;
-    using Apache.Ignite.AspNet;
-    using Apache.Ignite.Core.Common;
-    using NUnit.Framework;
-
-    /// <summary>
-    /// Tests for <see cref="IgniteOutputCacheProvider"/>
-    /// </summary>
-    public class IgniteOutputCacheProviderTest
-    {
-        /** Grid name XML config attribute. */
-        private const string GridNameAttr = "gridName";
-
-        /** Cache name XML config attribute. */
-        private const string CacheNameAttr = "cacheName";
-
-        /** Cache name XML config attribute. */
-        private const string SectionNameAttr = 
"igniteConfigurationSectionName";
-
-        /** Grid name. */
-        private const string GridName = "grid1";
-
-        /** Cache name. */
-        private const string CacheName = "myCache";
-
-        /// <summary>
-        /// Fixture setup.
-        /// </summary>
-        [TestFixtureSetUp]
-        public void TestFixtureSetUp()
-        {
-            Ignition.Start(new 
IgniteConfiguration(TestUtils.GetTestConfiguration()) {GridName = GridName});
-        }
-
-        /// <summary>
-        /// Fixture teardown.
-        /// </summary>
-        [TestFixtureTearDown]
-        public void TestFixtureTearDown()
-        {
-            Ignition.StopAll(true);
-        }
-
-        /// <summary>
-        /// Tests provider initialization.
-        /// </summary>
-        [Test]
-        public void TestInitialization()
-        {
-            var cacheProvider = new IgniteOutputCacheProvider();
-
-            // Not initialized
-            Assert.Throws<InvalidOperationException>(() => 
cacheProvider.Get("1"));
-
-            // Grid not started
-            Assert.Throws<IgniteException>(() =>
-                cacheProvider.Initialize("testName", new NameValueCollection
-                {
-                    {GridNameAttr, "invalidGridName"},
-                    {CacheNameAttr, CacheName}
-                }));
-
-            // Valid grid
-            cacheProvider = GetProvider();
-
-            cacheProvider.Set("1", 1, DateTime.MaxValue);
-            Assert.AreEqual(1, cacheProvider.Get("1"));
-        }
-
-        /// <summary>
-        /// Tests autostart from web configuration section.
-        /// </summary>
-        [Test]
-        public void TestStartFromWebConfigSection()
-        {
-            var cacheProvider = new IgniteOutputCacheProvider();
-
-            cacheProvider.Initialize("testName2", new NameValueCollection
-            {
-                {SectionNameAttr, "igniteConfiguration2"},
-                {CacheNameAttr, "cacheName2"}
-            });
-
-            cacheProvider.Set("1", 3, DateTime.MaxValue);
-            Assert.AreEqual(3, cacheProvider.Get("1"));
-        }
-
-        /// <summary>
-        /// Tests provider caching.
-        /// </summary>
-        [Test]
-        public void TestCaching()
-        {
-            var cacheProvider = GetProvider();
-
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-            cacheProvider.Set("1", 1, DateTime.MaxValue);
-            Assert.AreEqual(1, cacheProvider.Get("1"));
-
-            cacheProvider.Remove("1");
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-
-            Assert.AreEqual(null, cacheProvider.Add("2", 2, 
DateTime.MaxValue));
-            Assert.AreEqual(2, cacheProvider.Add("2", 5, DateTime.MaxValue));
-        }
-
-        /// <summary>
-        /// Tests cache expiration.
-        /// </summary>
-        [Test]
-        public void TestExpiry()
-        {
-            var cacheProvider = GetProvider();
-            cacheProvider.Remove("1");
-
-            // Set
-            cacheProvider.Set("1", 1, DateTime.UtcNow.AddSeconds(1.3));
-            Assert.AreEqual(1, cacheProvider.Get("1"));
-            Thread.Sleep(2000);
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-
-            cacheProvider.Set("1", 1, DateTime.UtcNow);
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-
-            // Add
-            cacheProvider.Add("1", 1, DateTime.UtcNow.AddSeconds(0.7));
-            Assert.AreEqual(1, cacheProvider.Get("1"));
-            Thread.Sleep(2000);
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-
-            cacheProvider.Add("1", 1, DateTime.UtcNow);
-            Assert.AreEqual(null, cacheProvider.Get("1"));
-        }
-
-        /// <summary>
-        /// Gets the initialized provider.
-        /// </summary>
-        private static IgniteOutputCacheProvider GetProvider()
-        {
-            var cacheProvider = new IgniteOutputCacheProvider();
-
-            cacheProvider.Initialize("testName", new NameValueCollection
-            {
-                {GridNameAttr, GridName},
-                {CacheNameAttr, CacheName}
-            });
-
-            return cacheProvider;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
index c0b8599..6ca2f9d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs
@@ -23,7 +23,6 @@ namespace Apache.Ignite.Core.Tests
     using System.Collections.Generic;
     using System.Linq;
     using System.Threading;
-    using Apache.Ignite.Core.Discovery;
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Static;
     using Apache.Ignite.Core.Impl;

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
index 8ba3e29..fb47f29 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
@@ -872,6 +872,21 @@ namespace Apache.Ignite.Core.Impl.Cache
             return AsyncInstance.GetTask(CacheOp.InvokeAll, reader => 
ReadInvokeAllResults<TRes>(reader.Stream));
         }
 
+        /** <inheritDoc /> */
+        public T DoOutInOpExtension<T>(int extensionId, int opCode, 
Action<IBinaryRawWriter> writeAction, 
+            Func<IBinaryRawReader, T> readFunc)
+        {
+            return DoOutInOpX((int) CacheOp.Extension, writer =>
+                {
+                    writer.WriteInt(extensionId);
+                    writer.WriteInt(opCode);
+                    writeAction(writer);
+                },
+                (input, res) => res == True
+                    ? readFunc(Marshaller.StartUnmarshal(input))
+                    : default(T), ReadException);
+        }
+
         /** <inheritdoc /> */
         public ICacheLock Lock(TK key)
         {

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs
index 4c42bf3..e6ca938 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs
@@ -61,6 +61,7 @@ namespace Apache.Ignite.Core.Impl.Cache
         Replace2 = 37,
         Replace3 = 38,
         GetConfig = 39,
-        LoadAll = 40
+        LoadAll = 40,
+        Extension = 41
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
index a23cf08..0349db8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
@@ -36,5 +36,19 @@ namespace Apache.Ignite.Core.Impl.Cache
         /// Cursor.
         /// </returns>
         IQueryCursor<T> QueryFields<T>(SqlFieldsQuery qry, 
Func<IBinaryRawReader, int, T> readerFunc);
+
+        /// <summary>
+        /// Invokes a cache extension.
+        /// </summary>
+        /// <typeparam name="T">The type of the result.</typeparam>
+        /// <param name="extensionId">The extension identifier.</param>
+        /// <param name="opCode">The extension op code.</param>
+        /// <param name="writeAction">The write action.</param>
+        /// <param name="readFunc">The read action.</param>
+        /// <returns>
+        /// Result of the processing.
+        /// </returns>
+        T DoOutInOpExtension<T>(int extensionId, int opCode, 
Action<IBinaryRawWriter> writeAction, 
+            Func<IBinaryRawReader, T> readFunc);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/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 fd52c8a..4ee67dd 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -21,7 +21,6 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
-    using System.Globalization;
     using System.IO;
     using System.Runtime.InteropServices;
     using System.Threading;

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
index 008ba5c..9fcbeb0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
@@ -43,5 +43,6 @@ using System.Runtime.InteropServices;
 
 [assembly: InternalsVisibleTo("Apache.Ignite.Core.Tests, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100a5bf8e0062a26bde53ccf0f8c42ef5b122a22052f99aecacb7028adcc163050324ee3c75ff40eb0cbe2d0426fa20eca03726cad90d7eb882ff47f5361567a82b676a27565f88b2479d7b9354ae0a1e526ee781b6e11de943d8f4a49efb53765f8c954022bede0fca86c133fab038af8dc88b67d6b6e5b9796d6ca490e699efab")]
 [assembly: InternalsVisibleTo("Apache.Ignite.Benchmarks, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100a3e0c1df4cbedbd4ed0e88808401c69b69ec12575ed1c056ac9f448e018fb29af19d236b7b03563aad66c48ab2045e72971ed098d4f65d4cdd38d65abcb39b4f84c626b22ccab2754375f0e8c97dc304fa146f0eddad5cc40a71803a8f15b0b0bb0bff0d4bf0ff6a64bb1044e0d71e6e2405b83fd4c1f7b3e2cfc2e9d50823d4")]
+[assembly: InternalsVisibleTo("Apache.Ignite.AspNet.Tests, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9380ce05eb74bd7c531f72e9ea615c59d7eceb09bd9795cb3dff1fcf638fd799c2a58a9be42fff156efe1c8cdebb751e27763f6c9a7c80cdc1dc1bbf44283608ef18ccd5017fd57b2b026503637c89c2537f361807f3bdd49265f4d444716159d989342561d324b1a0961640338bb32eaf67f4ae0c95f1b210f65404b0909c6")]
 
 #endif

http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.sln
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.sln 
b/modules/platforms/dotnet/Apache.Ignite.sln
index 2362ce2..8a3bf04 100644
--- a/modules/platforms/dotnet/Apache.Ignite.sln
+++ b/modules/platforms/dotnet/Apache.Ignite.sln
@@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.Ignite.Linq", "Apach
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.AspNet", 
"Apache.Ignite.AspNet\Apache.Ignite.AspNet.csproj", 
"{13EA96FC-CC83-4164-A7C0-4F30ED797460}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.Ignite.AspNet.Tests", 
"Apache.Ignite.AspNet.Tests\Apache.Ignite.AspNet.Tests.csproj", 
"{18EA4C71-A11D-4AB1-8042-418F7559D84F}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -174,6 +176,18 @@ Global
                {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x64.Build.0 = 
Release|Any CPU
                {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x86.ActiveCfg = 
Release|Any CPU
                {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x86.Build.0 = 
Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x64.ActiveCfg = 
Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x64.Build.0 = 
Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x86.ActiveCfg = 
Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x86.Build.0 = 
Debug|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x64.ActiveCfg = 
Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x64.Build.0 = 
Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x86.ActiveCfg = 
Release|Any CPU
+               {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x86.Build.0 = 
Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE

Reply via email to