ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ptupit...@apache.org
Subject ignite git commit: IGNITE-2379 .NET: ASP.NET Output Cache provider
Date Fri, 17 Jun 2016 15:10:47 GMT
Repository: ignite
Updated Branches:
  refs/heads/master c61c0cb15 -> 00a60b951


IGNITE-2379 .NET: ASP.NET Output Cache provider

This closes #406


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

Branch: refs/heads/master
Commit: 00a60b9515ccc50fdfdcbf85e27060aaba0bc49a
Parents: c61c0cb
Author: Pavel Tupitsyn <ptupitsyn@apache.org>
Authored: Fri Jun 17 18:10:32 2016 +0300
Committer: Pavel Tupitsyn <ptupitsyn@apache.org>
Committed: Fri Jun 17 18:10:32 2016 +0300

----------------------------------------------------------------------
 .gitignore                                      |   1 +
 .../Apache.Ignite.AspNet.csproj                 |  72 ++++++
 .../Apache.Ignite.AspNet.nuspec                 |  57 +++++
 .../Apache.Ignite.AspNet.ruleset                |   9 +
 .../Apache.Ignite.AspNet.snk                    | Bin 0 -> 596 bytes
 .../IgniteOutputCacheProvider.cs                | 221 +++++++++++++++++++
 .../Apache.Ignite.AspNet/IgniteWebUtils.cs      |  45 ++++
 .../Properties/AssemblyInfo.cs                  |  39 ++++
 .../Apache.Ignite.Core.Tests.NuGet.csproj       |   8 +
 .../AspNetTest.cs                               |  73 ++++++
 .../packages.config                             |   1 +
 .../Apache.Ignite.Core.Tests.csproj             |   6 +
 .../AspNet/IgniteOutputCacheProviderTest.cs     | 172 +++++++++++++++
 .../dotnet/Apache.Ignite.Core.Tests/app.config  |   2 +-
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |   2 +
 .../Properties/AssemblyInfo.cs                  |   2 +-
 .../Apache.Ignite.Linq.nuspec                   |   4 +-
 modules/platforms/dotnet/Apache.Ignite.sln      |  16 +-
 18 files changed, 725 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 665770d..b534eb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,4 @@ ipch/
 [Rr]elease*/
 packages
 *.classname
+*.nupkg
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.csproj b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.csproj
new file mode 100644
index 0000000..3474584
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.csproj
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"
/>
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x64</Platform>
+    <ProjectGuid>{13EA96FC-CC83-4164-A7C0-4F30ED797460}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Apache.Ignite.AspNet</RootNamespace>
+    <AssemblyName>Apache.Ignite.AspNet</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>Apache.Ignite.AspNet.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;CODE_ANALYSIS</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>Apache.Ignite.AspNet.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>Apache.Ignite.AspNet.ruleset</CodeAnalysisRuleSet>
+    <DocumentationFile>bin\Release\Apache.Ignite.AspNet.XML</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="IgniteOutputCacheProvider.cs" />
+    <Compile Include="IgniteWebUtils.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj">
+      <Project>{4cd2f726-7e2b-46c4-a5ba-057bb82eecb6}</Project>
+      <Name>Apache.Ignite.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Apache.Ignite.AspNet.nuspec" />
+    <None Include="Apache.Ignite.AspNet.ruleset" />
+    <None Include="Apache.Ignite.AspNet.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and
uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.nuspec
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.nuspec b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.nuspec
new file mode 100644
index 0000000..2324faa
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.nuspec
@@ -0,0 +1,57 @@
+<?xml version="1.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.
+-->
+
+<!-- 
+
+Creating NuGet package:
+1) Build Apache.Ignite.sln (AnyCPU configuration)
+2) Create package (use csproj instead of nuspec so that template substitution works): 
+   nuget pack Apache.Ignite.AspNet.csproj -Prop Configuration=Release -Prop Platform=AnyCPU
+
+-->
+
+<package >
+    <metadata>
+        <id>Apache.Ignite.AspNet</id>
+        <title>Apache Ignite ASP.NET Integration</title>
+        <!-- -->
+        <version>$version$</version>
+        <authors>Apache Ignite</authors>
+        <owners>Apache Software Foundation</owners>
+        <licenseUrl>http://www.apache.org/licenses/LICENSE-2.0</licenseUrl>
+        <projectUrl>https://ignite.apache.org/</projectUrl>
+        <iconUrl>https://ignite.apache.org/images/logo_ignite_32_32.png</iconUrl>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>
+Apache Ignite ASP.NET Output Cache Provider: caches page output in a distributed in-memory
cache.
+Ideal for web farms: share cached data between servers effortlessly.
+            
+More info: https://apacheignite-net.readme.io/
+        </description>
+        <summary>
+            Apache Ignite ASP.NET Integration
+        </summary>
+        <releaseNotes></releaseNotes>
+        <copyright>Copyright 2016</copyright>
+        <tags>OutputCacheProvider Apache Ignite In-Memory Distributed Computing SQL
NoSQL Grid Map Reduce Cache</tags>
+        <dependencies>
+            <dependency id="Apache.Ignite" version="[$version$]" />
+        </dependencies>    
+    </metadata>
+</package>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.ruleset
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.ruleset b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.ruleset
new file mode 100644
index 0000000..bc7683a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.ruleset
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RuleSet Name="Rules for Apache.Ignite.AspNet" Description="Code analysis rules for Apache.Ignite.AspNet.csproj."
ToolsVersion="14.0">
+  <IncludeAll Action="Error" />
+  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
+    <Rule Id="CA1704" Action="None" />
+    <Rule Id="CA2204" Action="None" />
+    <Rule Id="CA2243" Action="None" />
+  </Rules>
+</RuleSet>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.snk
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.snk b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.snk
new file mode 100644
index 0000000..799e742
Binary files /dev/null and b/modules/platforms/dotnet/Apache.Ignite.AspNet/Apache.Ignite.AspNet.snk
differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteOutputCacheProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteOutputCacheProvider.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteOutputCacheProvider.cs
new file mode 100644
index 0000000..d6006e5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteOutputCacheProvider.cs
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+using System.Web.Caching;
+
+namespace Apache.Ignite.AspNet
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Collections.Specialized;
+    using System.Configuration;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Globalization;
+    using Apache.Ignite.Core;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Expiry;
+    using Apache.Ignite.Core.Common;
+
+    /// <summary>
+    /// ASP.NET output cache provider that uses Ignite cache as a storage.
+    /// <para />
+    /// You can either start Ignite yourself, and provide <c>gridName</c> attribute,

+    /// or provide <c>igniteConfigurationSectionName</c> attribute to start Ignite
automatically from specified
+    /// configuration section (see <see cref="IgniteConfigurationSection"/>).
+    /// <para />
+    /// <c>cacheName</c> attribute specifies Ignite cache name to use for data
storage. This attribute can be omitted 
+    /// if cache name is null.
+    /// </summary>
+    public class IgniteOutputCacheProvider : OutputCacheProvider
+    {
+        /** */
+        private const string GridName = "gridName";
+        
+        /** */
+        private const string CacheName = "cacheName";
+
+        /** */
+        private const string IgniteConfigurationSectionName = "igniteConfigurationSectionName";
+
+        /** Max number of cached expiry caches. */
+        private const int MaxExpiryCaches = 1000;
+
+        /** */
+        private volatile ICache<string, object> _cache;
+
+        /** Cached caches per expiry seconds. */
+        private volatile Dictionary<long, ICache<string, object>> _expiryCaches
= 
+            new Dictionary<long, ICache<string, object>>();
+
+        /** Sync object. */ 
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Returns a reference to the specified entry in the output cache.
+        /// </summary>
+        /// <param name="key">A unique identifier for a cached entry in the output
cache.</param>
+        /// <returns>
+        /// The <paramref name="key" /> value that identifies the specified entry in
the cache, or null if the specified entry is not in the cache.
+        /// </returns>
+        public override object Get(string key)
+        {
+            object res;
+
+            return Cache.TryGet(key, out res) ? res : null;
+        }
+
+        /// <summary>
+        /// Inserts the specified entry into the output cache.
+        /// </summary>
+        /// <param name="key">A unique identifier for <paramref name="entry" />.</param>
+        /// <param name="entry">The content to add to the output cache.</param>
+        /// <param name="utcExpiry">The time and date on which the cached entry expires.</param>
+        /// <returns>
+        /// A reference to the specified provider.
+        /// </returns>
+        public override object Add(string key, object entry, DateTime utcExpiry)
+        {
+            return GetCacheWithExpiry(utcExpiry).GetAndPutIfAbsent(key, entry).Value;
+        }
+
+        /// <summary>
+        /// Inserts the specified entry into the output cache, overwriting the entry if it
is already cached.
+        /// </summary>
+        /// <param name="key">A unique identifier for <paramref name="entry" />.</param>
+        /// <param name="entry">The content to add to the output cache.</param>
+        /// <param name="utcExpiry">The time and date on which the cached <paramref
name="entry" /> expires.</param>
+        public override void Set(string key, object entry, DateTime utcExpiry)
+        {
+            GetCacheWithExpiry(utcExpiry)[key] = entry;
+        }
+
+        /// <summary>
+        /// Removes the specified entry from the output cache.
+        /// </summary>
+        /// <param name="key">The unique identifier for the entry to remove from the
output cache.</param>
+        public override void Remove(string key)
+        {
+            Cache.Remove(key);
+        }
+
+        /// <summary>
+        /// Initializes the provider.
+        /// </summary>
+        /// <param name="name">The friendly name of the provider.</param>
+        /// <param name="config">A collection of the name/value pairs representing
the provider-specific attributes specified in the configuration for this provider.</param>
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods")]
+        public override void Initialize(string name, NameValueCollection config)
+        {
+            base.Initialize(name, config);
+
+            var gridName = config[GridName];
+            var cacheName = config[CacheName];
+            var cfgSection = config[IgniteConfigurationSectionName];
+
+            try
+            {
+                var grid = cfgSection != null
+                    ? StartFromApplicationConfiguration(cfgSection)
+                    : Ignition.GetIgnite(gridName);
+
+                _cache = grid.GetOrCreateCache<string, object>(cacheName);
+            }
+            catch (Exception ex)
+            {
+                throw new IgniteException(string.Format(CultureInfo.InvariantCulture,
+                    "Failed to initialize {0}: {1}", GetType(), ex), ex);
+            }
+        }
+
+        /// <summary>
+        /// Starts Ignite from application configuration.
+        /// </summary>
+        private static IIgnite StartFromApplicationConfiguration(string sectionName)
+        {
+            var section = ConfigurationManager.GetSection(sectionName) as IgniteConfigurationSection;
+
+            if (section == null)
+                throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture,

+                    "Could not find {0} with name '{1}'", typeof(IgniteConfigurationSection).Name,
sectionName));
+
+            var config = section.IgniteConfiguration;
+
+            if (string.IsNullOrWhiteSpace(config.IgniteHome))
+            {
+                // IgniteHome not set by user: populate from default directory
+                config = new IgniteConfiguration(config) {IgniteHome = IgniteWebUtils.GetWebIgniteHome()};
+            }
+
+            return Ignition.Start(config);
+        }
+
+        /// <summary>
+        /// Gets the cache.
+        /// </summary>
+        private ICache<string, object> Cache
+        {
+            get
+            {
+                var cache = _cache;
+
+                if (cache == null)
+                    throw new InvalidOperationException("IgniteOutputCacheProvider has not
been initialized.");
+
+                return cache;
+            }
+        }
+
+        /// <summary>
+        /// Gets the cache with expiry policy according to provided expiration date.
+        /// </summary>
+        /// <param name="utcExpiry">The UTC expiry.</param>
+        /// <returns>Cache with expiry policy.</returns>
+        private ICache<string, object> GetCacheWithExpiry(DateTime utcExpiry)
+        {
+            if (utcExpiry == DateTime.MaxValue)
+                return Cache;
+
+            // Round up to seconds ([OutputCache] duration is in seconds).
+            var expirySeconds = (long) (utcExpiry - DateTime.UtcNow).TotalSeconds;
+
+            if (expirySeconds < 1)
+                expirySeconds = 1;
+
+            ICache<string, object> expiryCache;
+
+            if (_expiryCaches.TryGetValue(expirySeconds, out expiryCache))
+                return expiryCache;
+
+            lock (_syncRoot)
+            {
+                if (_expiryCaches.TryGetValue(expirySeconds, out expiryCache))
+                    return expiryCache;
+
+                // Copy on write with size limit
+                _expiryCaches = _expiryCaches.Count > MaxExpiryCaches
+                    ? new Dictionary<long, ICache<string, object>>()
+                    : new Dictionary<long, ICache<string, object>>(_expiryCaches);
+
+                expiryCache = Cache.WithExpiryPolicy(new ExpiryPolicy(TimeSpan.FromSeconds(expirySeconds),
null, null));
+
+                _expiryCaches[expirySeconds] = expiryCache;
+
+                return expiryCache;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteWebUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteWebUtils.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteWebUtils.cs
new file mode 100644
index 0000000..8a6ab5a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/IgniteWebUtils.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.AspNet
+{
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
+    using System.Web;
+
+    /// <summary>
+    /// Ignite web utilities.
+    /// </summary>
+    public static class IgniteWebUtils
+    {
+        /// <summary>
+        /// Gets the Ignite home directory from default location in web deployment (application_root\bin).
+        /// Ignite can not detect home directory in a standard way because IIS uses temporary
folders for dlls.
+        /// </summary>
+        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", 
+            Justification = "Not appropriate: uses IO")]
+        public static string GetWebIgniteHome()
+        {
+            var ctx = HttpContext.Current;
+
+            if (ctx == null)
+                return null;
+
+            return ctx.Server.MapPath(@"~\bin");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/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
new file mode 100644
index 0000000..0b502fd
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs
@@ -0,0 +1,39 @@
+/*
+* 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.
+*/
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Apache.Ignite.AspNet")]
+[assembly: AssemblyDescription("Apache Ignite.NET ASP.NET integration")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache Ignite.NET")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("13ea96fc-cc83-4164-a7c0-4f30ed797460")]
+
+[assembly: AssemblyVersion("1.7.0.11707")]
+[assembly: AssemblyFileVersion("1.7.0.11707")]
+[assembly: AssemblyInformationalVersion("1.7.0")]
+
+[assembly: CLSCompliant(true)]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj
index 22a203e..8c4c46b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj
@@ -80,6 +80,11 @@
       <HintPath>packages\Apache.Ignite.Linq.1.6.0\lib\net40\Apache.Ignite.Linq.dll</HintPath>
       <Private>True</Private>
     </Reference>
+    <Reference Include="Apache.Ignite.AspNet">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>packages\Apache.Ignite.AspNet.1.6.0\lib\net40\Apache.Ignite.AspNet.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="nunit-console-runner">
       <HintPath>..\libs\nunit-console-runner.dll</HintPath>
     </Reference>
@@ -92,10 +97,13 @@
       <Private>True</Private>
     </Reference>
     <Reference Include="System" />
+    <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Web" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AspNetTest.cs" />
     <Compile Include="ComputeTest.cs" />
     <Compile Include="SchemaTest.cs" />
     <Compile Include="StartupTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/AspNetTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/AspNetTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/AspNetTest.cs
new file mode 100644
index 0000000..91711e5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/AspNetTest.cs
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable UnusedAutoPropertyAccessor.Local
+namespace Apache.Ignite.Core.Tests.NuGet
+{
+    using System;
+    using System.Collections.Specialized;
+    using Apache.Ignite.AspNet;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// ASP.NET test.
+    /// </summary>
+    public class AspNetTest
+    {
+        /// <summary>
+        /// Fixture set up.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            var cfg = new IgniteConfiguration
+            {
+                DiscoverySpi = TestUtil.GetLocalDiscoverySpi(),
+                CacheConfiguration = new [] {new CacheConfiguration("aspNetCache") }
+            };
+
+            Ignition.Start(cfg);
+        }
+
+        /// <summary>
+        /// Fixture tear down.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests cache put/get.
+        /// </summary>
+        [Test]
+        public void TestSetGet()
+        {
+            var cacheProvider = new IgniteOutputCacheProvider();
+
+            cacheProvider.Initialize("myProvider", new NameValueCollection
+            {
+                {"cacheName", "aspNetCache"}
+            });
+
+            cacheProvider.Set("1", 3, DateTime.MaxValue);
+            Assert.AreEqual(3, cacheProvider.Get("1"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config
index edf80de..88d9cc2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config
@@ -20,6 +20,7 @@
 <packages>
   <package id="Apache.Ignite" version="1.6.0" targetFramework="net40" />
   <package id="Apache.Ignite.Linq" version="1.6.0" targetFramework="net40" />
+  <package id="Apache.Ignite.AspNet" version="1.6.0" targetFramework="net40" />
   <package id="Apache.Ignite.Schema" version="1.6.0" targetFramework="net40" />
   <package id="Remotion.Linq" version="2.0.1" targetFramework="net40" />
 </packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/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 fdb3645..1a367d4 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,10 +49,12 @@
     <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="AspNet\IgniteOutputCacheProviderTest.cs" />
     <Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" />
     <Compile Include="Binary\BinaryCompactFooterInteropTest.cs" />
     <Compile Include="Binary\BinarySelfTestFullFooter.cs" />
@@ -161,6 +163,10 @@
     <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/00a60b95/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
new file mode 100644
index 0000000..8d0f546
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs
@@ -0,0 +1,172 @@
+/*
+ * 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.5));
+            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(1.5));
+            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/00a60b95/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config
index 1df48bf..d22bea4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config
@@ -41,7 +41,7 @@
         </cacheConfiguration>
     </igniteConfiguration>
 
-    <igniteConfiguration2 gridName="myGrid2">
+    <igniteConfiguration2 gridName="myGrid2" localhost="127.0.0.1">
         <discoverySpi type="TcpDiscoverySpi">
             <ipFinder type="TcpDiscoveryStaticIpFinder">
                 <endpoints>

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index a505cca..6bdf1ab 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -398,6 +398,8 @@
             Assemblies = cfg.Assemblies;
             SuppressWarnings = cfg.SuppressWarnings;
             LifecycleBeans = cfg.LifecycleBeans;
+            JvmInitialMemoryMb = cfg.JvmInitialMemoryMb;
+            JvmMaxMemoryMb = cfg.JvmMaxMemoryMb;
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/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 955f205..5c5dfe5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs
@@ -25,7 +25,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("Apache Software Foundation")]
 [assembly: AssemblyProduct("Apache Ignite.NET")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.nuspec
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.nuspec b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.nuspec
index 21206be..088ca13 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.nuspec
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.nuspec
@@ -20,9 +20,9 @@
 <!-- 
 
 Creating NuGet package:
-1) Build Apache.Ignite.sln (x64 configuration)
+1) Build Apache.Ignite.sln (AnyCPU configuration)
 2) Create package (use csproj instead of nuspec so that template substitution works): 
-   nuget pack Apache.Ignite.Linq.csproj -Prop Configuration=Release -Prop Platform=x64
+   nuget pack Apache.Ignite.Linq.csproj -Prop Configuration=Release -Prop Platform=AnyCPU
 
 -->
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/00a60b95/modules/platforms/dotnet/Apache.Ignite.sln
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.sln b/modules/platforms/dotnet/Apache.Ignite.sln
index ba1b6ce..96cb996 100644
--- a/modules/platforms/dotnet/Apache.Ignite.sln
+++ b/modules/platforms/dotnet/Apache.Ignite.sln
@@ -1,4 +1,4 @@
-
+
 Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.Core", "Apache.Ignite.Core\Apache.Ignite.Core.csproj",
"{4CD2F726-7E2B-46C4-A5BA-057BB82EECB6}"
@@ -35,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jni", "..\cpp\jni\project\v
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.Linq", "Apache.Ignite.Linq\Apache.Ignite.Linq.csproj",
"{5B571661-17F4-4F29-8C7D-0EDB38CA9B55}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.AspNet", "Apache.Ignite.AspNet\Apache.Ignite.AspNet.csproj",
"{13EA96FC-CC83-4164-A7C0-4F30ED797460}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -161,6 +163,18 @@ Global
 		{5B571661-17F4-4F29-8C7D-0EDB38CA9B55}.Release|x64.Build.0 = Release|Any CPU
 		{5B571661-17F4-4F29-8C7D-0EDB38CA9B55}.Release|x86.ActiveCfg = Release|Any CPU
 		{5B571661-17F4-4F29-8C7D-0EDB38CA9B55}.Release|x86.Build.0 = Release|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|x64.Build.0 = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Debug|x86.Build.0 = Debug|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|Any CPU.Build.0 = Release|Any CPU
+		{13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x64.ActiveCfg = Release|Any CPU
+		{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
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE


Mime
View raw message