Skip to content

Commit 28cd8c7

Browse files
committed
Refactor, add tests
1 parent 6d04502 commit 28cd8c7

File tree

10 files changed

+291
-43
lines changed

10 files changed

+291
-43
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" />
4+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
5+
<PropertyGroup>
6+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
7+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
8+
<ProjectGuid>{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}</ProjectGuid>
9+
<OutputType>Library</OutputType>
10+
<AppDesignerFolder>Properties</AppDesignerFolder>
11+
<RootNamespace>AspNet.MVC5.AssetVersioning.Tests</RootNamespace>
12+
<AssemblyName>AspNet.MVC5.AssetVersioning.Tests</AssemblyName>
13+
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
14+
<FileAlignment>512</FileAlignment>
15+
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
17+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
18+
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
19+
<IsCodedUITest>False</IsCodedUITest>
20+
<TestProjectType>UnitTest</TestProjectType>
21+
<NuGetPackageImportStamp>
22+
</NuGetPackageImportStamp>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
25+
<DebugSymbols>true</DebugSymbols>
26+
<DebugType>full</DebugType>
27+
<Optimize>false</Optimize>
28+
<OutputPath>bin\Debug\</OutputPath>
29+
<DefineConstants>DEBUG;TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
34+
<DebugType>pdbonly</DebugType>
35+
<Optimize>true</Optimize>
36+
<OutputPath>bin\Release\</OutputPath>
37+
<DefineConstants>TRACE</DefineConstants>
38+
<ErrorReport>prompt</ErrorReport>
39+
<WarningLevel>4</WarningLevel>
40+
</PropertyGroup>
41+
<ItemGroup>
42+
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
43+
<HintPath>..\src\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath>
44+
</Reference>
45+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
46+
<HintPath>..\src\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
47+
</Reference>
48+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
49+
<HintPath>..\src\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
50+
</Reference>
51+
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
52+
<HintPath>..\src\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
53+
</Reference>
54+
<Reference Include="Moq, Version=4.12.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
55+
<HintPath>..\src\packages\Moq.4.12.0\lib\net45\Moq.dll</HintPath>
56+
</Reference>
57+
<Reference Include="System" />
58+
<Reference Include="System.Configuration" />
59+
<Reference Include="System.Core" />
60+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
61+
<HintPath>..\src\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
62+
</Reference>
63+
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
64+
<HintPath>..\src\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
65+
</Reference>
66+
<Reference Include="System.Web" />
67+
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
68+
<HintPath>..\src\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll</HintPath>
69+
</Reference>
70+
<Reference Include="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
71+
<HintPath>..\src\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll</HintPath>
72+
</Reference>
73+
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
74+
<HintPath>..\src\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll</HintPath>
75+
</Reference>
76+
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
77+
<HintPath>..\src\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll</HintPath>
78+
</Reference>
79+
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
80+
<HintPath>..\src\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
81+
</Reference>
82+
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
83+
<HintPath>..\src\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
84+
</Reference>
85+
</ItemGroup>
86+
<ItemGroup>
87+
<Compile Include="ExtensionsTests.cs" />
88+
<Compile Include="Properties\AssemblyInfo.cs" />
89+
</ItemGroup>
90+
<ItemGroup>
91+
<None Include="packages.config" />
92+
</ItemGroup>
93+
<ItemGroup>
94+
<ProjectReference Include="..\src\AspNet.MVC5.AssetVersioning.csproj">
95+
<Project>{ed5f5dc4-dbb1-4444-a0df-8392ed3936bd}</Project>
96+
<Name>AspNet.MVC5.AssetVersioning</Name>
97+
</ProjectReference>
98+
</ItemGroup>
99+
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
100+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
101+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
102+
<PropertyGroup>
103+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
104+
</PropertyGroup>
105+
<Error Condition="!Exists('..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props'))" />
106+
<Error Condition="!Exists('..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets'))" />
107+
</Target>
108+
<Import Project="..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\src\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" />
109+
</Project>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Web;
4+
using System.Web.Mvc;
5+
using System.Web.Mvc.AssetVersioning;
6+
using System.Web.Routing;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
using Moq;
9+
10+
namespace AspNet.MVC5.AssetVersioning.Tests
11+
{
12+
[TestClass]
13+
public class ExtensionsTests
14+
{
15+
[TestMethod]
16+
public void AppendVersion_Should_Append_To_Empty_Url()
17+
{
18+
19+
var path = Extensions.AppendVersion("https://foo.com/test.js", "123");
20+
21+
Assert.AreEqual("https://foo.com/test.js?123", path);
22+
}
23+
24+
[TestMethod]
25+
public void AppendVersion_Should_Append_To_Existing_Url()
26+
{
27+
28+
var path = Extensions.AppendVersion("https://foo.com/test.js?h=foo", "123");
29+
30+
Assert.AreEqual("https://foo.com/test.js?h=foo&123", path);
31+
}
32+
33+
[TestMethod]
34+
public void ComputeHash_Returns_Sha256_Hash_of_File_Contents()
35+
{
36+
var hash = AssetVersionCache.ComputeHash("test.txt");
37+
38+
Assert.AreEqual("5b9VrKRrgLl2zwVdUOwhwihZ2cwlYdjQTqgEVV+G624=", hash);
39+
}
40+
41+
[TestMethod]
42+
public void GetOrAddCachedVersion_Caches_File_Hash()
43+
{
44+
var cache = new System.Web.Caching.Cache();
45+
var hash = AssetVersionCache.GetOrAddCachedVersion("test.txt", cache);
46+
47+
var assetCache = cache.Get("__AssetVersions__") as ConcurrentDictionary<string, string>;
48+
49+
Assert.AreEqual(1, cache.Count);
50+
Assert.AreEqual(1, assetCache.Count);
51+
Assert.AreEqual("5b9VrKRrgLl2zwVdUOwhwihZ2cwlYdjQTqgEVV+G624=", assetCache["test.txt"]);
52+
Assert.AreEqual(hash, assetCache["test.txt"]);
53+
54+
var cachedHash = AssetVersionCache.GetOrAddCachedVersion("test.txt", cache);
55+
56+
Assert.AreEqual(1, assetCache.Count);
57+
Assert.AreEqual(hash, cachedHash);
58+
}
59+
}
60+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
[assembly: AssemblyTitle("AspNet.MVC5.AssetVersioning.Tests")]
6+
[assembly: AssemblyDescription("")]
7+
[assembly: AssemblyConfiguration("")]
8+
[assembly: AssemblyCompany("")]
9+
[assembly: AssemblyProduct("AspNet.MVC5.AssetVersioning.Tests")]
10+
[assembly: AssemblyCopyright("Copyright © 2019")]
11+
[assembly: AssemblyTrademark("")]
12+
[assembly: AssemblyCulture("")]
13+
14+
[assembly: ComVisible(false)]
15+
16+
[assembly: Guid("fa45de7e-f4ba-426e-b3ea-010f7553ce8f")]
17+
18+
// [assembly: AssemblyVersion("1.0.*")]
19+
[assembly: AssemblyVersion("1.0.0.0")]
20+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Castle.Core" version="4.4.0" targetFramework="net472" />
4+
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net472" />
5+
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net472" />
6+
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net472" />
7+
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net472" />
8+
<package id="Moq" version="4.12.0" targetFramework="net472" />
9+
<package id="MSTest.TestAdapter" version="1.3.2" targetFramework="net472" />
10+
<package id="MSTest.TestFramework" version="1.3.2" targetFramework="net472" />
11+
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net472" />
12+
<package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net472" />
13+
</packages>

src/AspNet.MVC5.AssetVersioning.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<Reference Include="System.Xml" />
6464
</ItemGroup>
6565
<ItemGroup>
66+
<Compile Include="AssetVersionCache.cs" />
6667
<Compile Include="Extensions.cs" />
6768
<Compile Include="Properties\AssemblyInfo.cs" />
6869
</ItemGroup>
@@ -71,6 +72,11 @@
7172
<None Include="Build.ps1" />
7273
<None Include="packages.config" />
7374
</ItemGroup>
75+
<ItemGroup>
76+
<Content Include="test.txt">
77+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
78+
</Content>
79+
</ItemGroup>
7480
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
7581
<PropertyGroup>
7682
<PostBuildEvent>powershell $(ProjectDir)Build.ps1</PostBuildEvent>

src/AspNet.MVC5.AssetVersioning.csproj.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<version>1.0.527</version>
66
<authors>kayub</authors>
77
<owners>kayub</owners>
8-
<licenseUrl>http://https://github.com/kamranayub/aspnetmvc5-asset-versioning</licenseUrl>
8+
<licenseUrl>https://github.com/kamranayub/aspnetmvc5-asset-versioning</licenseUrl>
99
<projectUrl>https://github.com/kamranayub/aspnetmvc5-asset-versioning</projectUrl>
1010
<requireLicenseAcceptance>false</requireLicenseAcceptance>
1111
<description>Url Helper extension to get versioned content asset URLs</description>

src/AspNet.MVC5.AssetVersioning.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1010
..\README.md = ..\README.md
1111
EndProjectSection
1212
EndProject
13+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.MVC5.AssetVersioning.Tests", "..\AspNet.MVC5.AssetVersioning.Tests\AspNet.MVC5.AssetVersioning.Tests.csproj", "{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}"
14+
EndProject
1315
Global
1416
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1517
Debug|Any CPU = Debug|Any CPU
@@ -20,6 +22,10 @@ Global
2022
{ED5F5DC4-DBB1-4444-A0DF-8392ED3936BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
2123
{ED5F5DC4-DBB1-4444-A0DF-8392ED3936BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
2224
{ED5F5DC4-DBB1-4444-A0DF-8392ED3936BD}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{FA45DE7E-F4BA-426E-B3EA-010F7553CE8F}.Release|Any CPU.Build.0 = Release|Any CPU
2329
EndGlobalSection
2430
GlobalSection(SolutionProperties) = preSolution
2531
HideSolutionNode = FALSE

src/AssetVersionCache.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Security.Cryptography;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using System.Web;
10+
using System.Web.Caching;
11+
12+
namespace System.Web.Mvc.AssetVersioning
13+
{
14+
public static class AssetVersionCache
15+
{
16+
private const string CACHE_KEY = "__AssetVersions__";
17+
18+
private static ConcurrentDictionary<string, string> GetOrCreateAssetCache(Cache cache)
19+
{
20+
var assetCache = cache[CACHE_KEY] as ConcurrentDictionary<string, string>;
21+
22+
if (assetCache == null)
23+
{
24+
assetCache = new ConcurrentDictionary<string, string>();
25+
cache[CACHE_KEY] = assetCache;
26+
}
27+
28+
return assetCache;
29+
}
30+
31+
public static string ComputeHash(string filePath)
32+
{
33+
using (var stream = File.OpenRead(filePath))
34+
{
35+
using (var sha256 = SHA256.Create())
36+
{
37+
return Convert.ToBase64String(sha256.ComputeHash(stream));
38+
}
39+
}
40+
}
41+
42+
public static string GetOrAddCachedVersion(string filePath, Cache cache)
43+
{
44+
if (!File.Exists(filePath))
45+
{
46+
return null;
47+
}
48+
var assetCache = GetOrCreateAssetCache(cache);
49+
var version = string.Empty;
50+
51+
if (assetCache.ContainsKey(filePath))
52+
{
53+
version = assetCache[filePath];
54+
}
55+
else
56+
{
57+
version = AssetVersionCache.ComputeHash(filePath);
58+
version = assetCache.GetOrAdd(filePath, version);
59+
}
60+
61+
return version;
62+
}
63+
}
64+
}

src/Extensions.cs

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,27 @@
66

77
namespace System.Web.Mvc.AssetVersioning
88
{
9-
public static class UrlHelpers
9+
public static class Extensions
1010
{
11-
private const string CACHE_KEY = "__AssetVersions__";
12-
13-
private static ConcurrentDictionary<string, string> GetOrCreateAssetCache(HttpContextBase context)
11+
public static string AppendVersion(string contentUrl, string version)
1412
{
15-
var cache = context.Cache[CACHE_KEY] as ConcurrentDictionary<string, string>;
16-
17-
if (cache == null)
18-
{
19-
cache = new ConcurrentDictionary<string, string>();
20-
context.Cache[CACHE_KEY] = cache;
21-
}
13+
var url = new UriBuilder(contentUrl);
14+
if (url.Query != null && url.Query.Length > 1)
15+
url.Query = url.Query.Substring(1) + "&" + version;
16+
else
17+
url.Query = version;
2218

23-
return cache;
19+
return url.Uri.GetComponents(UriComponents.Scheme | UriComponents.Host | UriComponents.PathAndQuery, UriFormat.Unescaped);
2420
}
2521

2622
public static string VersionedContent(this UrlHelper helper, string assetPath)
2723
{
28-
// resolve file
2924
var fullPath = helper.RequestContext.HttpContext.Server.MapPath(assetPath);
25+
var version = AssetVersionCache.GetOrAddCachedVersion(fullPath, helper.RequestContext.HttpContext.Cache);
3026

31-
if (File.Exists(fullPath))
32-
{
33-
var cache = GetOrCreateAssetCache(helper.RequestContext.HttpContext);
34-
var version = string.Empty;
35-
36-
if (cache.ContainsKey(fullPath))
37-
{
38-
version = cache[fullPath];
39-
}
40-
else
41-
{
42-
using (var stream = File.OpenRead(fullPath))
43-
{
44-
using (var sha256 = SHA256.Create())
45-
{
46-
version = Convert.ToBase64String(sha256.ComputeHash(stream));
47-
}
48-
}
49-
50-
version = cache.GetOrAdd(fullPath, version);
51-
}
52-
27+
if (version != null) {
5328
// append hash to query string
54-
var url = new UriBuilder(helper.Content(assetPath));
55-
if (url.Query != null && url.Query.Length > 1)
56-
url.Query = url.Query.Substring(1) + "&" + version;
57-
else
58-
url.Query = version;
59-
60-
return url.ToString();
29+
return Extensions.AppendVersion(helper.Content(assetPath), version);
6130
}
6231

6332
return helper.Content(assetPath);

src/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1234

0 commit comments

Comments
 (0)