├── .gitignore ├── DynamicBundles ├── DynamicBundles.Test │ ├── AssetsInLayoutOnly │ │ ├── AssetsInLayoutOnly.cs │ │ └── Views │ │ │ ├── Account │ │ │ ├── Details.cshtml │ │ │ ├── EditDetails.cshtml │ │ │ └── Login.cshtml │ │ │ ├── Home │ │ │ └── Index.cshtml │ │ │ ├── Product │ │ │ └── Details.cshtml │ │ │ ├── Shared │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ └── _Layout.css │ │ │ └── _LayoutContainer │ │ │ │ ├── Reset.css │ │ │ │ ├── SharedCode.js │ │ │ │ ├── Site.css │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ └── jquery-1.8.2.js │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ ├── DependenciesInController │ │ ├── Tests.cs │ │ └── Views │ │ │ ├── Account │ │ │ ├── AccountDetailsAssets.css │ │ │ ├── AccountDetailsAssets.js │ │ │ ├── Details │ │ │ │ └── Details.cshtml │ │ │ ├── EditDetails │ │ │ │ └── EditDetails.cshtml │ │ │ └── Login.cshtml │ │ │ ├── Home │ │ │ └── Index.cshtml │ │ │ ├── Product │ │ │ └── Details.cshtml │ │ │ ├── Shared │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ └── _Layout.css │ │ │ └── _LayoutContainer │ │ │ │ ├── Site.css │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ └── jquery-1.8.2.js │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ ├── DynamicBundles.Test.csproj │ ├── Helpers │ │ ├── ArrayEqualityTesters.cs │ │ ├── TestCacheHelper.cs │ │ ├── TestDynamicBundleCollection.cs │ │ ├── TestPathHelper.cs │ │ └── Tester.cs │ ├── MultipleFileDependencies │ │ ├── Tests.cs │ │ └── Views │ │ │ ├── Account │ │ │ ├── AccountDetailsAssets │ │ │ │ ├── AccountDetailsAssets.css │ │ │ │ └── AccountDetailsAssets.js │ │ │ ├── Details │ │ │ │ ├── Details.cshtml │ │ │ │ └── Details.nuspec │ │ │ ├── EditDetails │ │ │ │ └── EditDetails.cshtml │ │ │ └── Login.cshtml │ │ │ ├── Home │ │ │ └── Index.cshtml │ │ │ ├── Product │ │ │ └── Details.cshtml │ │ │ ├── Shared │ │ │ ├── DetailsAssets │ │ │ │ └── DetailsAssets.css │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ └── _Layout.css │ │ │ └── _LayoutContainer │ │ │ │ ├── Site.css │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ └── jquery-1.8.2.js │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ ├── NuspecTests │ │ ├── NuspecFiles │ │ │ ├── empty.nuspec │ │ │ ├── multipledependencies.nuspec │ │ │ ├── nuget.nuspec │ │ │ └── onedependency.nuspec │ │ └── NuspecTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RelativeFileDependencies │ │ ├── Tests.cs │ │ └── Views │ │ │ ├── Account │ │ │ ├── AccountDetailsAssets │ │ │ │ ├── AccountDetailsAssets.css │ │ │ │ └── AccountDetailsAssets.js │ │ │ ├── Details │ │ │ │ ├── Details.cshtml │ │ │ │ └── Details.nuspec │ │ │ ├── EditDetails │ │ │ │ ├── EditDetails.cshtml │ │ │ │ └── EditDetails.nuspec │ │ │ └── Login.cshtml │ │ │ ├── Home │ │ │ └── Index.cshtml │ │ │ ├── Product │ │ │ └── Details.cshtml │ │ │ ├── Shared │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ └── _Layout.css │ │ │ └── _LayoutContainer │ │ │ │ ├── Site.css │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ └── jquery-1.8.2.js │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ ├── RootRelativeFileDependencies │ │ ├── Tests.cs │ │ └── Views │ │ │ ├── Account │ │ │ ├── AccountDetailsAssets │ │ │ │ ├── AccountDetailsAssets.css │ │ │ │ └── AccountDetailsAssets.js │ │ │ ├── Details │ │ │ │ ├── Details.cshtml │ │ │ │ └── Details.nuspec │ │ │ ├── EditDetails │ │ │ │ ├── EditDetails.cshtml │ │ │ │ └── EditDetails.nuspec │ │ │ └── Login.cshtml │ │ │ ├── Home │ │ │ └── Index.cshtml │ │ │ ├── Product │ │ │ └── Details.cshtml │ │ │ ├── Shared │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ └── _Layout.css │ │ │ └── _LayoutContainer │ │ │ │ ├── Site.css │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ └── jquery-1.8.2.js │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ ├── app.config │ └── packages.config ├── DynamicBundles.TestWeb │ ├── App_Start │ │ ├── BundleConfig.cs │ │ ├── FilterConfig.cs │ │ ├── RouteConfig.cs │ │ └── WebApiConfig.cs │ ├── Areas │ │ └── TestArea │ │ │ ├── Controllers │ │ │ └── HomeController.cs │ │ │ ├── TestAreaAreaRegistration.cs │ │ │ └── Views │ │ │ ├── Home │ │ │ ├── Index.cshtml │ │ │ ├── Index.css │ │ │ ├── Index.js │ │ │ └── MyPerson.cshtml │ │ │ ├── Shared │ │ │ ├── _Layout.cshtml │ │ │ ├── _Layout.css │ │ │ ├── _Layout.js │ │ │ └── _SharedBox3 │ │ │ │ ├── _SharedBox3.cshtml │ │ │ │ ├── _SharedBox3.css │ │ │ │ └── _SharedBox3.js │ │ │ └── Web.config │ ├── Content │ │ └── Site.css │ ├── Controllers │ │ ├── DefaultController.cs │ │ └── HomeController.cs │ ├── DynamicBundles.TestWeb.csproj │ ├── Global.asax │ ├── Global.asax.cs │ ├── Helpers.cs │ ├── Models │ │ ├── HomeAddress.cs │ │ └── Person.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Views │ │ ├── Default │ │ │ └── Index.cshtml │ │ ├── Home │ │ │ ├── About.cshtml │ │ │ ├── Home.css │ │ │ ├── Home.js │ │ │ ├── Index │ │ │ │ ├── Index.cshtml │ │ │ │ ├── Index.css │ │ │ │ └── Index.js │ │ │ ├── MyChild.cshtml │ │ │ ├── MyPerson.cshtml │ │ │ └── Product │ │ │ │ ├── Product.cshtml │ │ │ │ ├── Product.css │ │ │ │ └── Product.js │ │ ├── Shared │ │ │ ├── EditorTemplates │ │ │ │ ├── HomeAddress.cshtml │ │ │ │ ├── HomeAddress.css │ │ │ │ └── HomeAddress.js │ │ │ ├── _Layout │ │ │ │ ├── _Layout.cshtml │ │ │ │ ├── _Layout.css │ │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ │ └── jquery.validate.unobtrusive.min.js │ │ │ ├── _LayoutContainer │ │ │ │ ├── _LayoutContainer.cshtml │ │ │ │ ├── jquery-1.8.2.js │ │ │ │ └── jquery-1.8.2.min.js │ │ │ ├── _SharedBox │ │ │ │ ├── _SharedBox.cshtml │ │ │ │ ├── _SharedBox.css │ │ │ │ └── _SharedBox.js │ │ │ └── _SharedBox2 │ │ │ │ ├── _SharedBox2.cshtml │ │ │ │ ├── _SharedBox2.css │ │ │ │ └── _SharedBox2.js │ │ ├── Web.config │ │ └── _ViewStart.cshtml │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ └── packages.config ├── DynamicBundles.sln └── DynamicBundles │ ├── AssetPath.cs │ ├── BundleFactories.cs │ ├── BundleHelper.cs │ ├── BundleTransformer.Configuration.xsd │ ├── CacheHelper.cs │ ├── DependencyResolver.cs │ ├── DynamicBundleCollection.cs │ ├── DynamicBundles.csproj │ ├── DynamicBundles.nuspec │ ├── DynamicBundlesBuilder.cs │ ├── DynamicBundlesViewEngine.cs │ ├── HttpContextStore.cs │ ├── Models │ ├── AssetType.cs │ ├── FileListsByAssetType.cs │ └── ListsByKey.cs │ ├── NuGet │ └── readme.txt │ ├── NuspecFile.cs │ ├── Properties │ ├── AssemblyInfo.cs │ └── AssemblyInfo.cs.template │ ├── RouteHelper.cs │ ├── StringListHelper.cs │ ├── WebViewPage.cs │ ├── app.config │ └── packages.config ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/AssetsInLayoutOnly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using DynamicBundles.Models; 4 | using DynamicBundles; 5 | using System.Collections.Generic; 6 | using System.Web.Optimization; 7 | using System.Linq; 8 | 9 | namespace DynamicBundles.Test 10 | { 11 | [TestClass] 12 | public class UnitTest1 13 | { 14 | [TestMethod] 15 | public void CheckBundle() 16 | { 17 | string[] assetDirs = 18 | new [] { 19 | "~/Views/Account", 20 | "~/Views/Shared/_Layout", 21 | "~/Views/Shared/_LayoutContainer" 22 | }; 23 | 24 | string[][] expectedScriptFiles = 25 | { 26 | new [] { 27 | "~/Views/Shared/_LayoutContainer/SharedCode.js", 28 | "~/Views/Shared/_LayoutContainer/jquery-1.8.2.js" 29 | } 30 | }; 31 | 32 | string[][] expectedStyleFiles = 33 | { 34 | new [] { 35 | "~/Views/Shared/_LayoutContainer/Site.css", 36 | "~/Views/Shared/_LayoutContainer/Reset.css", 37 | "~/Views/Shared/_Layout/_Layout.css" 38 | } 39 | }; 40 | 41 | Tester.Test("AssetsInLayoutOnly", 42 | assetDirs, 43 | expectedScriptFiles, 44 | expectedStyleFiles); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Account/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Account/EditDetails.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "EditDetails"; 3 | } 4 | 5 |

EditDetails

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login"; 3 | } 4 | 5 |

Login

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Product/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Shared/_LayoutContainer/Reset.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Shared/_LayoutContainer/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/AssetsInLayoutOnly/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using DynamicBundles.Models; 4 | using DynamicBundles; 5 | using System.Collections.Generic; 6 | using System.Web.Optimization; 7 | using System.Linq; 8 | 9 | namespace DynamicBundles.Test.DependenciesInController 10 | { 11 | [TestClass] 12 | public class UnitTest1 13 | { 14 | [TestMethod] 15 | public void DependenciesInController() 16 | { 17 | string[] assetDirs = 18 | new [] { 19 | "~/Views/Account/Details", 20 | "~/Views/Shared/_Layout", 21 | "~/Views/Shared/_LayoutContainer" 22 | }; 23 | 24 | string[][] expectedScriptFiles = 25 | { 26 | new string[] { 27 | "~/Views/Shared/_LayoutContainer/jquery-1.8.2.js" 28 | }, 29 | new string[] { 30 | "~/Views/Account/AccountDetailsAssets.js" 31 | } 32 | }; 33 | 34 | string[][] expectedStyleFiles = 35 | { 36 | new [] { 37 | "~/Views/Shared/_LayoutContainer/Site.css", 38 | "~/Views/Shared/_Layout/_Layout.css" 39 | }, 40 | new string[] { 41 | "~/Views/Account/AccountDetailsAssets.css" 42 | } 43 | }; 44 | 45 | Tester.Test("DependenciesInController", 46 | assetDirs, 47 | expectedScriptFiles, 48 | expectedStyleFiles); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Account/AccountDetailsAssets.css: -------------------------------------------------------------------------------- 1 | .account-dependencies { 2 | border: 2px pink solid; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Account/AccountDetailsAssets.js: -------------------------------------------------------------------------------- 1 | alert("AccountDetailsAssets"); 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Account/Details/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Account/EditDetails/EditDetails.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "EditDetails"; 3 | } 4 | 5 |

EditDetails

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login"; 3 | } 4 | 5 |

Login

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Product/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Shared/_LayoutContainer/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/DependenciesInController/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Helpers/ArrayEqualityTesters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | 8 | namespace DynamicBundles.Test 9 | { 10 | public class ArrayEqualityTesters 11 | { 12 | public static void AssertOneDimStringArraysEqual(string[] saa1, string[] saa2) 13 | { 14 | int saaLength = saa1.Length; 15 | Assert.AreEqual(saaLength, saa2.Length); 16 | 17 | for (int i = 0; i < saaLength; i++) 18 | { 19 | Assert.AreEqual(saa1[i], saa2[i]); 20 | } 21 | } 22 | 23 | public static void AssertTwoDimStringArraysEqual(string[][] saa1, string[][] saa2) 24 | { 25 | int saaLength = saa1.Length; 26 | Assert.AreEqual(saaLength, saa2.Length); 27 | 28 | for (int i = 0; i < saaLength; i++) 29 | { 30 | int saaLength2 = saa1[i].Length; 31 | Assert.AreEqual(saaLength2, saa2[i].Length); 32 | 33 | for (int i2 = 0; i2 < saaLength2; i2++) 34 | { 35 | Assert.AreEqual(saa1[i][i2], saa2[i][i2]); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Helpers/TestCacheHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | using DynamicBundles; 8 | 9 | namespace DynamicBundles.Test 10 | { 11 | public class TestCacheHelper : ICacheHelper 12 | { 13 | public T Get(string cacheKey, Func createItem, IEnumerable directories) 14 | { 15 | T item = createItem(); 16 | return item; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Helpers/TestDynamicBundleCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Optimization; 7 | using DynamicBundles; 8 | 9 | namespace DynamicBundles.Test 10 | { 11 | /// 12 | /// Encapsulates the MVC BundleCollection. The difference is that this class 13 | /// implements IBundleCollection, so it can be replaced by a mock 14 | /// during unit testing. 15 | /// 16 | internal class TestDynamicBundleCollection : IDynamicBundleCollection 17 | { 18 | private Dictionary _bundles = null; 19 | 20 | public TestDynamicBundleCollection(Dictionary bundles) 21 | { 22 | _bundles = bundles; 23 | } 24 | 25 | /// 26 | /// Returns true if a bundle with the passed in name exists. 27 | /// 28 | public bool Exists(string bundleName) 29 | { 30 | return (_bundles.ContainsKey(bundleName)); 31 | } 32 | 33 | /// 34 | /// Adds the given Bundle to the bundle collection 35 | /// 36 | public void Add(Bundle bundle) 37 | { 38 | _bundles[bundle.Path] = bundle; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Helpers/TestPathHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Reflection; 7 | using System.IO; 8 | 9 | namespace DynamicBundles.Test 10 | { 11 | public class TestPathHelper 12 | { 13 | private string _testDirectory; 14 | 15 | public TestPathHelper(string testDirectory) 16 | { 17 | _testDirectory = testDirectory; 18 | } 19 | 20 | /// 21 | /// Converts a root relative path to an absolute path 22 | /// 23 | /// 24 | /// 25 | public string rootToAbsolutePath(string rootRelativePath) 26 | { 27 | // Note that this will end in \bin\Debug 28 | string absoluteAssemblyDir = Path.GetDirectoryName(typeof(TestPathHelper).Assembly.Location); 29 | 30 | string absoluteProjectDir = Path.GetDirectoryName(Path.GetDirectoryName(absoluteAssemblyDir)); 31 | 32 | string absoluteTestDir = Path.Combine(absoluteProjectDir, _testDirectory); 33 | 34 | // rootRelativePath must start with ~/. The tilde will be replaced by the test dir. 35 | string absolutePath = Path.Combine(absoluteTestDir, rootRelativePath.Substring(2).Replace('/', '\\')); 36 | 37 | return absolutePath; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Helpers/Tester.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using System.Web.Optimization; 8 | 9 | namespace DynamicBundles.Test 10 | { 11 | internal class Tester 12 | { 13 | public static void Test(string testRootDir, string[] assetDirs, string[][] expectedScriptFiles, string[][] expectedStyleFiles) 14 | { 15 | var log = new Dictionary(); 16 | 17 | Dictionary bundles = new Dictionary(); 18 | 19 | var _dynamicBundlesBuilder = 20 | new DynamicBundlesBuilder(new TestDynamicBundleCollection(bundles), 21 | new TestCacheHelper(), 22 | new BundleFactories(log)); 23 | 24 | var pathHelper = new TestPathHelper(testRootDir); 25 | Func rootToAbsolutePathFunc = (rootRelativePath) => pathHelper.rootToAbsolutePath(rootRelativePath); 26 | 27 | List assetDirectoryList = 28 | assetDirs.Select(a => new AssetPath(a, rootToAbsolutePathFunc)).ToList(); 29 | 30 | List scriptBundleVirtualPaths; 31 | List styleBundleVirtualPaths; 32 | 33 | _dynamicBundlesBuilder.Builder(assetDirectoryList, out scriptBundleVirtualPaths, out styleBundleVirtualPaths); 34 | 35 | string[][] actualScriptFiles = scriptBundleVirtualPaths.Select(n => log[n]).ToArray(); 36 | string[][] actualStyleFiles = styleBundleVirtualPaths.Select(n => log[n]).ToArray(); 37 | 38 | ArrayEqualityTesters.AssertTwoDimStringArraysEqual(actualScriptFiles, expectedScriptFiles); 39 | ArrayEqualityTesters.AssertTwoDimStringArraysEqual(actualStyleFiles, expectedStyleFiles); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using DynamicBundles.Models; 4 | using DynamicBundles; 5 | using System.Collections.Generic; 6 | using System.Web.Optimization; 7 | using System.Linq; 8 | 9 | namespace DynamicBundles.Test.MultipleFileDependencies 10 | { 11 | [TestClass] 12 | public class UnitTest1 13 | { 14 | [TestMethod] 15 | public void MultipleFileDependencies() 16 | { 17 | string[] assetDirs = 18 | new [] { 19 | "~/Views/Account/Details", 20 | "~/Views/Shared/_Layout", 21 | "~/Views/Shared/_LayoutContainer" 22 | }; 23 | 24 | string[][] expectedScriptFiles = 25 | { 26 | new string[] { 27 | "~/Views/Shared/_LayoutContainer/jquery-1.8.2.js" 28 | }, 29 | new string[] { 30 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js" 31 | } 32 | }; 33 | 34 | string[][] expectedStyleFiles = 35 | { 36 | new [] { 37 | "~/Views/Shared/_LayoutContainer/Site.css", 38 | "~/Views/Shared/_Layout/_Layout.css" 39 | }, 40 | new string[] { 41 | "~/Views/Shared/DetailsAssets/DetailsAssets.css" 42 | }, 43 | new string[] { 44 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css" 45 | } 46 | }; 47 | 48 | Tester.Test("MultipleFileDependencies", 49 | assetDirs, 50 | expectedScriptFiles, 51 | expectedStyleFiles); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css: -------------------------------------------------------------------------------- 1 | .account-dependencies { 2 | border: 2px pink solid; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js: -------------------------------------------------------------------------------- 1 | alert("AccountDetailsAssets"); 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/Details/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/Details/Details.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/EditDetails/EditDetails.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "EditDetails"; 3 | } 4 | 5 |

EditDetails

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login"; 3 | } 4 | 5 |

Login

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Product/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Shared/DetailsAssets/DetailsAssets.css: -------------------------------------------------------------------------------- 1 | .account-dependencies { 2 | border: 2px pink solid; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Shared/_LayoutContainer/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/MultipleFileDependencies/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/NuspecTests/NuspecFiles/empty.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/NuspecTests/NuspecFiles/multipledependencies.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/NuspecTests/NuspecFiles/nuget.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | http://jsnlog.com 10 | http://jsnlog.com/Nuget/icon.png 11 | false 12 | $description$ 13 | Copyright 2014 14 | JavaScript logging exceptions log4net nlog elmah 15 | 16 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/NuspecTests/NuspecFiles/onedependency.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/NuspecTests/NuspecTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using DynamicBundles; 8 | 9 | namespace DynamicBundles.Test.NuspecTests 10 | { 11 | [TestClass] 12 | public class NuspecTests 13 | { 14 | [TestMethod] 15 | public void PathIsNuspec() 16 | { 17 | Assert.IsTrue(NuspecFile.IsNuspecFile("~/Views/blah.nuspec")); 18 | } 19 | 20 | [TestMethod] 21 | public void PathIsNotNuspec() 22 | { 23 | Assert.IsFalse(NuspecFile.IsNuspecFile("~/Views/blah.xml")); 24 | } 25 | 26 | [TestMethod] 27 | public void EmptyNuspec() 28 | { 29 | TestNuspecFileDepencyIds("empty.nuspec", new string[] {}); 30 | } 31 | 32 | [TestMethod] 33 | public void OneDependencyNuspec() 34 | { 35 | TestNuspecFileDepencyIds("onedependency.nuspec", new string[] { "~/View/Library" }); 36 | } 37 | 38 | [TestMethod] 39 | public void MultipleDependenciesNuspec() 40 | { 41 | TestNuspecFileDepencyIds("multipledependencies.nuspec", 42 | new string[] { "~/Views/Library", "~/Packages" }); 43 | } 44 | 45 | [TestMethod] 46 | public void NugetNuspec() 47 | { 48 | TestNuspecFileDepencyIds("nuget.nuspec", 49 | new string[] { "Common.Logging", "WebActivatorEx" }); 50 | } 51 | 52 | /// 53 | /// Ensures that after a nuspec file is loaded in memory, it has the expected dependency ids. 54 | /// 55 | /// 56 | /// Nuspec file to test 57 | /// 58 | /// 59 | /// Expected dependency ids. 60 | /// 61 | private void TestNuspecFileDepencyIds(string nuspecfileName, IEnumerable expectedIds) 62 | { 63 | ArrayEqualityTesters.AssertOneDimStringArraysEqual(NuspecFileDepencyIds(nuspecfileName).ToArray(), expectedIds.ToArray()); 64 | } 65 | 66 | private IEnumerable NuspecFileDepencyIds(string nuspecfileName) 67 | { 68 | var pathHelper = new TestPathHelper("NuspecTests/NuspecFiles"); 69 | string nuspecAbsolutePath = pathHelper.rootToAbsolutePath("~/" + nuspecfileName); 70 | 71 | var nuspecFile = new NuspecFile(nuspecAbsolutePath); 72 | return nuspecFile.DependencyIds; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DynamicBundles.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DynamicBundles.Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6b32a272-a076-468e-8571-5ee6c5ec0764")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using DynamicBundles.Models; 4 | using DynamicBundles; 5 | using System.Collections.Generic; 6 | using System.Web.Optimization; 7 | using System.Linq; 8 | 9 | namespace DynamicBundles.Test.RelativeFileDependencies 10 | { 11 | [TestClass] 12 | public class UnitTest1 13 | { 14 | [TestMethod] 15 | public void RelativeFileDependencies() 16 | { 17 | string[] assetDirs = 18 | new [] { 19 | "~/Views/Account/Details", 20 | "~/Views/Shared/_Layout", 21 | "~/Views/Shared/_LayoutContainer" 22 | }; 23 | 24 | string[][] expectedScriptFiles = 25 | { 26 | new string[] { 27 | "~/Views/Shared/_LayoutContainer/jquery-1.8.2.js" 28 | }, 29 | new string[] { 30 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js" 31 | } 32 | }; 33 | 34 | string[][] expectedStyleFiles = 35 | { 36 | new [] { 37 | "~/Views/Shared/_LayoutContainer/Site.css", 38 | "~/Views/Shared/_Layout/_Layout.css" 39 | }, 40 | new string[] { 41 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css" 42 | } 43 | }; 44 | 45 | Tester.Test("RelativeFileDependencies", 46 | assetDirs, 47 | expectedScriptFiles, 48 | expectedStyleFiles); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css: -------------------------------------------------------------------------------- 1 | .account-dependencies { 2 | border: 2px pink solid; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js: -------------------------------------------------------------------------------- 1 | alert("AccountDetailsAssets"); 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/Details/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/Details/Details.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/EditDetails/EditDetails.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "EditDetails"; 3 | } 4 | 5 |

EditDetails

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/EditDetails/EditDetails.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login"; 3 | } 4 | 5 |

Login

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Product/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Shared/_LayoutContainer/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RelativeFileDependencies/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using DynamicBundles.Models; 4 | using DynamicBundles; 5 | using System.Collections.Generic; 6 | using System.Web.Optimization; 7 | using System.Linq; 8 | 9 | namespace DynamicBundles.Test.RootRelativeFileDependencies 10 | { 11 | [TestClass] 12 | public class UnitTest1 13 | { 14 | [TestMethod] 15 | public void RootRelativeFileDependencies() 16 | { 17 | string[] assetDirs = 18 | new [] { 19 | "~/Views/Account/Details", 20 | "~/Views/Shared/_Layout", 21 | "~/Views/Shared/_LayoutContainer" 22 | }; 23 | 24 | string[][] expectedScriptFiles = 25 | { 26 | new string[] { 27 | "~/Views/Shared/_LayoutContainer/jquery-1.8.2.js" 28 | }, 29 | new string[] { 30 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js" 31 | } 32 | }; 33 | 34 | string[][] expectedStyleFiles = 35 | { 36 | new [] { 37 | "~/Views/Shared/_LayoutContainer/Site.css", 38 | "~/Views/Shared/_Layout/_Layout.css" 39 | }, 40 | new string[] { 41 | "~/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css" 42 | } 43 | }; 44 | 45 | Tester.Test("RootRelativeFileDependencies", 46 | assetDirs, 47 | expectedScriptFiles, 48 | expectedStyleFiles); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.css: -------------------------------------------------------------------------------- 1 | .account-dependencies { 2 | border: 2px pink solid; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/AccountDetailsAssets/AccountDetailsAssets.js: -------------------------------------------------------------------------------- 1 | alert("AccountDetailsAssets"); 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/Details/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/Details/Details.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/EditDetails/EditDetails.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "EditDetails"; 3 | } 4 | 5 |

EditDetails

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/EditDetails/EditDetails.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login"; 3 | } 4 | 5 |

Login

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Product/Details.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Details"; 3 | } 4 | 5 |

Details

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Shared/_LayoutContainer/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | @RenderBody() 12 | 13 | @Scripts.Render("~/bundles/jquery") 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/RootRelativeFileDependencies/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace DynamicBundles.TestWeb 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | //bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | // "~/Scripts/jquery-{version}.js")); 13 | 14 | //bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include( 15 | // "~/Scripts/jquery-ui-{version}.js")); 16 | 17 | //bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 18 | // "~/Scripts/jquery.unobtrusive*", 19 | // "~/Scripts/jquery.validate*")); 20 | 21 | //// Use the development version of Modernizr to develop with and learn from. Then, when you're 22 | //// ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 23 | //bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 24 | // "~/Scripts/modernizr-*")); 25 | 26 | // bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css")); 27 | 28 | //bundles.Add(new StyleBundle("~/Content/themes/base/css").Include( 29 | // "~/Content/themes/base/jquery.ui.core.css", 30 | // "~/Content/themes/base/jquery.ui.resizable.css", 31 | // "~/Content/themes/base/jquery.ui.selectable.css", 32 | // "~/Content/themes/base/jquery.ui.accordion.css", 33 | // "~/Content/themes/base/jquery.ui.autocomplete.css", 34 | // "~/Content/themes/base/jquery.ui.button.css", 35 | // "~/Content/themes/base/jquery.ui.dialog.css", 36 | // "~/Content/themes/base/jquery.ui.slider.css", 37 | // "~/Content/themes/base/jquery.ui.tabs.css", 38 | // "~/Content/themes/base/jquery.ui.datepicker.css", 39 | // "~/Content/themes/base/jquery.ui.progressbar.css", 40 | // "~/Content/themes/base/jquery.ui.theme.css")); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace DynamicBundles.TestWeb 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace DynamicBundles.TestWeb 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 20 | namespaces: new string[] { "DynamicBundles.TestWeb.Controllers" } 21 | ); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace DynamicBundles.TestWeb 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | config.Routes.MapHttpRoute( 13 | name: "DefaultApi", 14 | routeTemplate: "api/{controller}/{id}", 15 | defaults: new { id = RouteParameter.Optional } 16 | ); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace DynamicBundles.TestWeb.Areas.TestArea.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | 12 | [ChildActionOnly] 13 | public ActionResult MyPerson() 14 | { 15 | Person s = new Person 16 | { 17 | FirstName = "Joe Area", 18 | LastName = "Smith", 19 | HomeAddress = new HomeAddress 20 | { 21 | Street = "Area Country Lane", 22 | HouseNumber = 1145, 23 | City = "Rochester" 24 | } 25 | }; 26 | 27 | return PartialView(s); 28 | } 29 | 30 | // 31 | // GET: /TestArea/Home/ 32 | 33 | public ActionResult Index() 34 | { 35 | return View(); 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/TestAreaAreaRegistration.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace DynamicBundles.TestWeb.Areas.TestArea 4 | { 5 | public class TestAreaAreaRegistration : AreaRegistration 6 | { 7 | public override string AreaName 8 | { 9 | get 10 | { 11 | return "TestArea"; 12 | } 13 | } 14 | 15 | public override void RegisterArea(AreaRegistrationContext context) 16 | { 17 | context.MapRoute( 18 | "TestArea_default", 19 | "TestArea/{controller}/{action}/{id}", 20 | new { action = "Index", id = UrlParameter.Optional }, 21 | new string[] { "DynamicBundles.TestWeb.Areas.TestArea.Controllers" } 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | Layout = "~/Areas/TestArea/Views/Shared/_Layout.cshtml"; 4 | } 5 |

TestArea - Index

6 |

7 | @Html.Action("MyPerson") 8 |

9 | 10 | 11 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Home/Index.css: -------------------------------------------------------------------------------- 1 | .Index { color: blue; border: 1px red solid; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Home/Index.js: -------------------------------------------------------------------------------- 1 | // comment Area index 2 | alert("Area index"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Home/MyPerson.cshtml: -------------------------------------------------------------------------------- 1 | @model DynamicBundles.TestWeb.Person 2 | 3 | 4 |

Area My person

5 | 6 |

7 | First Name: 8 | @Html.EditorFor(m=>m.FirstName) 9 |

10 |

11 | Last Name: 12 | @Html.EditorFor(m=>m.LastName) 13 |

14 |

15 | Address: 16 | @Html.EditorFor(m=>m.HomeAddress) 17 |

18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout/_Layout.cshtml"; 3 | } 4 | 5 |

TestArea _Layout

6 | 7 | 8 | @Html.Partial("_SharedBox3") 9 | 10 | @Html.Partial("_SharedBox2") 11 | 12 | 13 | @RenderBody() 14 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_Layout.css: -------------------------------------------------------------------------------- 1 | .L_ayout { color: orange; border: 1px red solid; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_Layout.js: -------------------------------------------------------------------------------- 1 | // comment _Layout 2 | alert("_Layout"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_SharedBox3/_SharedBox3.cshtml: -------------------------------------------------------------------------------- 1 | 

2 | Shared box3 3 |

4 | 5 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_SharedBox3/_SharedBox3.css: -------------------------------------------------------------------------------- 1 | .SharedBox3 { color: green; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Shared/_SharedBox3/_SharedBox3.js: -------------------------------------------------------------------------------- 1 | // comment _SharedBox3 2 | alert("_SharedBox3"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Areas/TestArea/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: .85em; 3 | font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif; 4 | color: #232323; 5 | background-color: #fff; 6 | } 7 | 8 | header, footer, nav, section { 9 | display: block; 10 | } 11 | 12 | 13 | /* Styles for basic forms 14 | -----------------------------------------------------------*/ 15 | fieldset { 16 | border: 1px solid #ddd; 17 | padding: 0 1.4em 1.4em 1.4em; 18 | margin: 0 0 1.5em 0; 19 | } 20 | 21 | legend { 22 | font-size: 1.2em; 23 | font-weight: bold; 24 | } 25 | 26 | textarea { 27 | min-height: 75px; 28 | } 29 | 30 | .editor-label { 31 | margin: 1em 0 0 0; 32 | } 33 | 34 | .editor-field { 35 | margin: 0.5em 0 0 0; 36 | } 37 | 38 | 39 | /* Styles for validation helpers 40 | -----------------------------------------------------------*/ 41 | .field-validation-error { 42 | color: #f00; 43 | } 44 | 45 | .field-validation-valid { 46 | display: none; 47 | } 48 | 49 | .input-validation-error { 50 | border: 1px solid #f00; 51 | background-color: #fee; 52 | } 53 | 54 | .validation-summary-errors { 55 | font-weight: bold; 56 | color: #f00; 57 | } 58 | 59 | .validation-summary-valid { 60 | display: none; 61 | } 62 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Controllers/DefaultController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace DynamicBundles.TestWeb.Controllers 8 | { 9 | public class DefaultController : Controller 10 | { 11 | // 12 | // GET: /Default/ 13 | 14 | public ActionResult Index() 15 | { 16 | return View(); 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace DynamicBundles.TestWeb.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | // 12 | // GET: /Home/ 13 | 14 | public ActionResult Index() 15 | { 16 | return View("Index/Index"); 17 | } 18 | 19 | public ActionResult Product() 20 | { 21 | return View("Product"); 22 | } 23 | 24 | public ActionResult About() 25 | { 26 | return View(); 27 | } 28 | 29 | [ChildActionOnly] 30 | public ActionResult MyChild() 31 | { 32 | string s = "xyz"; 33 | return PartialView("MyChild", s); 34 | } 35 | 36 | [ChildActionOnly] 37 | public ActionResult MyPerson() 38 | { 39 | Person s = new Person { 40 | FirstName = "Joe", 41 | LastName = "Smith", 42 | HomeAddress = new HomeAddress { 43 | Street = "Country Lane", 44 | HouseNumber = 45, 45 | City = "Rochester" 46 | } 47 | }; 48 | 49 | return PartialView(s); 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="DynamicBundles.TestWeb.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Mvc; 7 | using System.Web.Optimization; 8 | using System.Web.Routing; 9 | 10 | namespace DynamicBundles.TestWeb 11 | { 12 | // Note: For instructions on enabling IIS6 or IIS7 classic mode, 13 | // visit http://go.microsoft.com/?LinkId=9394801 14 | 15 | public class MvcApplication : System.Web.HttpApplication 16 | { 17 | protected void Application_Start() 18 | { 19 | AreaRegistration.RegisterAllAreas(); 20 | 21 | //@@@@@@@@@@@@@@@@@@@@@ 22 | //leave the normal razor engine ViewEngines.Engines.Clear(); 23 | 24 | 25 | 26 | // Add DynamicBundles view engine. This functions the same as the Razor view engine, 27 | // but can find views sitting in their own directories, such as ~/Views/Home/Index/Index.cshtml 28 | // Note: this leaves the other view engines in place, so they can still be used. 29 | ViewEngines.Engines.Add(new DynamicBundles.DynamicBundlesViewEngine()); 30 | //@@@@@@@@@@@@@@@@@@@@@ 31 | 32 | WebApiConfig.Register(GlobalConfiguration.Configuration); 33 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 34 | RouteConfig.RegisterRoutes(RouteTable.Routes); 35 | 36 | 37 | // BundleConfig.RegisterBundles(BundleTable.Bundles); 38 | } 39 | 40 | 41 | 42 | 43 | 44 | 45 | protected void Application_EndRequest() 46 | { 47 | } 48 | 49 | 50 | } 51 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace DynamicBundles.TestWeb.Helpers 8 | { 9 | public static class Helpers 10 | { 11 | public static MvcHtmlString MyHelper(this HtmlHelper html, string x) 12 | { 13 | return new MvcHtmlString(x + "x"); 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Models/HomeAddress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace DynamicBundles.TestWeb 7 | { 8 | public class HomeAddress 9 | { 10 | public string Street { get; set; } 11 | public int HouseNumber { get; set; } 12 | public string City { get; set; } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Models/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace DynamicBundles.TestWeb 7 | { 8 | public class Person 9 | { 10 | public string FirstName { get; set; } 11 | public string LastName { get; set; } 12 | public HomeAddress HomeAddress { get; set; } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DynamicBundles.TestWeb")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DynamicBundles.TestWeb")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3a12d5cc-ffb8-43ec-b61b-9376e654e294")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Default/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

Default Index

6 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @using DynamicBundles.TestWeb.Helpers 2 | 3 | @{ 4 | ViewBag.Title = "About"; 5 | } 6 | 7 |

Home About

8 | 9 | @Html.Partial("_SharedBox") 10 | @Html.Partial("_SharedBox2") 11 | 12 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Home.css: -------------------------------------------------------------------------------- 1 | .HomeAddress { color: yellow; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Home.js: -------------------------------------------------------------------------------- 1 | // comment Home 2 | alert("Home"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Index/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using DynamicBundles.TestWeb.Helpers 2 | 3 | @{ 4 | ViewBag.Title = "Index"; 5 | } 6 | 7 |

Home Index

8 | 9 | @Html.Partial("_SharedBox") 10 | 11 |

12 | abcde 13 |

14 | 15 | @Html.Action("MyChild") 16 | 17 |

18 | After child 19 |

20 |

21 | @Html.MyHelper("hello helper") 22 |

23 |

24 | @Html.Action("MyPerson") 25 |

26 | 27 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Index/Index.css: -------------------------------------------------------------------------------- 1 | .Index { color: orange; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Index/Index.js: -------------------------------------------------------------------------------- 1 | // comment Index 2 | alert("Index"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/MyChild.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 |

4 | child: 5 | @Model 6 |

7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/MyPerson.cshtml: -------------------------------------------------------------------------------- 1 | @model DynamicBundles.TestWeb.Person 2 | 3 |

4 | First Name: 5 | @Html.EditorFor(m=>m.FirstName) 6 |

7 |

8 | Last Name: 9 | @Html.EditorFor(m=>m.LastName) 10 |

11 |

12 | Address: 13 | @Html.EditorFor(m=>m.HomeAddress) 14 |

15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Product/Product.cshtml: -------------------------------------------------------------------------------- 1 | @using DynamicBundles.TestWeb.Helpers 2 | 3 | @{ 4 | ViewBag.Title = "Product"; 5 | } 6 | 7 |

Home Product

8 | 9 | 10 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Product/Product.css: -------------------------------------------------------------------------------- 1 | .Product { color: orange; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Home/Product/Product.js: -------------------------------------------------------------------------------- 1 | // comment Index 2 | alert("Product"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/EditorTemplates/HomeAddress.cshtml: -------------------------------------------------------------------------------- 1 | @model DynamicBundles.TestWeb.HomeAddress 2 | 3 |

4 | @Html.TextAreaFor(m => m.Street, new { @class = "street"}) - @Html.TextBoxFor(m=>m.HouseNumber) 5 |

6 |

7 | @Html.TextBoxFor(m=>m.City) 8 |

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/EditorTemplates/HomeAddress.css: -------------------------------------------------------------------------------- 1 | .HomeAddress { 2 | color: yellow; 3 | } 4 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/EditorTemplates/HomeAddress.js: -------------------------------------------------------------------------------- 1 | // comment HomeAddress 2 | alert("HomeAddress"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_Layout/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | //@@@@@@@@@@@@@@@@@@@@@@@@@ 3 | // Add _LayoutContainer as the container for the _Layout.cshtml file itself. 4 | Layout = "../_LayoutContainer/_LayoutContainer.cshtml"; 5 | } 6 | 7 | 8 | 9 | 10 | @ViewBag.Title 11 | @* @Styles.Render("~/Content/css")*@ 12 | @* @Styles.Render(bundlePath)*@ 13 | 14 | @*@@@@@@@@@@@@@@@@@*@ 15 | @* @DynamicBundlesTopRender()*@ 16 | 17 | 18 | @* @Scripts.Render("~/bundles/modernizr")*@ 19 | 20 | 21 |

Main _Layout

22 | 23 | 24 | 25 | @Html.Partial("_SharedBox2") 26 | 27 | 28 |
29 | @RenderBody() 30 | 31 | @* @Scripts.Render("~/bundles/jquery")*@ 32 | @RenderSection("scripts", required: false) 33 | @* @Styles.Render("~/Content/css")*@ 34 | @* @Styles.Render(bundlePath)*@ 35 | 36 | 37 | 38 | @* @DynamicBundlesBottomRender()*@ 39 | 40 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_Layout/_Layout.css: -------------------------------------------------------------------------------- 1 | .L_ayout { color: pink; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_Layout/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});b.addSingleVal("accept","exts").addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_LayoutContainer/_LayoutContainer.cshtml: -------------------------------------------------------------------------------- 1 |  2 | @*@@@@@@@@@@@@@@@@@@@@@@@@*@ 3 | @*Nominate where to load the bundles. The bundles themselves are automatically generated.*@ 4 | @DynamicBundlesTopRender() 5 | 6 | @RenderBody() 7 | 8 | @DynamicBundlesBottomRender() 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox/_SharedBox.cshtml: -------------------------------------------------------------------------------- 1 | 

    2 | Shared box 3 |

    4 | 5 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox/_SharedBox.css: -------------------------------------------------------------------------------- 1 | .SharedBox { color: red; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox/_SharedBox.js: -------------------------------------------------------------------------------- 1 | // comment _SharedBox 2 | alert("_SharedBox"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox2/_SharedBox2.cshtml: -------------------------------------------------------------------------------- 1 | 

    2 | Shared box2 3 |

    4 | 5 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox2/_SharedBox2.css: -------------------------------------------------------------------------------- 1 | .SharedBox2 { color: green; } 2 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Shared/_SharedBox2/_SharedBox2.js: -------------------------------------------------------------------------------- 1 | // comment _SharedBox2 2 | alert("_SharedBox2"); 3 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
    10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.TestWeb/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Web 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicBundles", "DynamicBundles\DynamicBundles.csproj", "{37C5ED5D-3951-4325-9191-BCD55DDDD3FE}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicBundles.TestWeb", "DynamicBundles.TestWeb\DynamicBundles.TestWeb.csproj", "{4A836FF7-DAB1-498B-A698-C4B99BCC6B20}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicBundles.Test", "DynamicBundles.Test\DynamicBundles.Test.csproj", "{DECBC746-AEF8-4425-B7DF-92ACD738F7D0}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {37C5ED5D-3951-4325-9191-BCD55DDDD3FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {37C5ED5D-3951-4325-9191-BCD55DDDD3FE}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {37C5ED5D-3951-4325-9191-BCD55DDDD3FE}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {37C5ED5D-3951-4325-9191-BCD55DDDD3FE}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {4A836FF7-DAB1-498B-A698-C4B99BCC6B20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {4A836FF7-DAB1-498B-A698-C4B99BCC6B20}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {4A836FF7-DAB1-498B-A698-C4B99BCC6B20}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {4A836FF7-DAB1-498B-A698-C4B99BCC6B20}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {DECBC746-AEF8-4425-B7DF-92ACD738F7D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {DECBC746-AEF8-4425-B7DF-92ACD738F7D0}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {DECBC746-AEF8-4425-B7DF-92ACD738F7D0}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {DECBC746-AEF8-4425-B7DF-92ACD738F7D0}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/AssetPath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.IO; 8 | 9 | namespace DynamicBundles 10 | { 11 | /// 12 | /// Represents a path to a file or directory. 13 | /// That file or directory must live within the current project. 14 | /// 15 | /// This is called "AssetPath" rather than "Path" to not clash with the .Net Path class. 16 | /// 17 | public class AssetPath 18 | { 19 | public string RootRelativePath { get; private set; } 20 | 21 | private Func _rootToAbsolutePathFunc = null; 22 | 23 | /// 24 | /// Constructor. 25 | /// 26 | /// 27 | /// Path to the file or directory. Must be relative to the root of the project (start with a ~). 28 | /// 29 | /// 30 | /// Lambda that takes a root relative path and returns an absolute path. 31 | /// Does the same as HttpContext.Current.Server.MapPath 32 | /// 33 | public AssetPath(string rootRelativePath, Func rootToAbsolutePathFunc) 34 | { 35 | RootRelativePath = rootRelativePath; 36 | _rootToAbsolutePathFunc = rootToAbsolutePathFunc; 37 | } 38 | 39 | private string _absolutePath = null; 40 | public string AbsolutePath 41 | { 42 | get 43 | { 44 | if (_absolutePath == null) 45 | { 46 | _absolutePath = _rootToAbsolutePathFunc(RootRelativePath); 47 | } 48 | 49 | return _absolutePath; 50 | } 51 | } 52 | 53 | /// 54 | /// The absolute counterpart of say "~/Views/Home" might be something like 55 | /// "d:\dev\Views\Home". In that case, the "absolute prefix" (the stuff that replaces the ~) is "d:\dev", 56 | /// which is 6 chars long. /// 57 | /// 58 | private int? _absolutePathPrefixLength = null; 59 | private int AbsolutePathPrefixLength 60 | { 61 | get 62 | { 63 | if (_absolutePathPrefixLength == null) 64 | { 65 | const int lengthTilde = 1; 66 | 67 | _absolutePathPrefixLength = 68 | AbsolutePath.Length - RootRelativePath.Length + lengthTilde; 69 | } 70 | 71 | return _absolutePathPrefixLength.Value; 72 | } 73 | } 74 | 75 | /// 76 | /// Converts a absolute file name or directory name (c:\...) to an AssetPath containing an application relative url (~/....). 77 | /// The file or directory must sit in the same project as the file or directory represented by this AssetPath object. 78 | /// Returns a new AssetPath representing the file or directory. 79 | /// 80 | /// 81 | /// 82 | /// 83 | public AssetPath AbsolutePathToAssetPath(string absolutePath) 84 | { 85 | string rootRelativePath = "~" + absolutePath.Substring(AbsolutePathPrefixLength).Replace('\\', '/'); 86 | return new AssetPath(rootRelativePath, _rootToAbsolutePathFunc); 87 | } 88 | 89 | /// 90 | /// Create a new AssetPath with the same rootToAbsolutePathFunc as this AssetPath. 91 | /// 92 | /// If the given path is not root relative, it is assumed to be relative to this AssetPath. 93 | /// 94 | public AssetPath Create(string path) 95 | { 96 | if (!path.StartsWith("~")) 97 | { 98 | return RootRelativeCombine(RootRelativePath, path); 99 | } 100 | 101 | return new AssetPath(path, _rootToAbsolutePathFunc); 102 | } 103 | 104 | private AssetPath RootRelativeCombine(string rootRelativePath, string relativePath) 105 | { 106 | // If relativePath contains .. (such as ..\dir), then rootRelativePathWithDots also has .. 107 | // This somehow leads to an endless loop. 108 | string rootRelativePathWithDots = Path.Combine(RootRelativePath, relativePath); 109 | 110 | string absolutePath = Path.GetFullPath(_rootToAbsolutePathFunc(rootRelativePathWithDots)); 111 | AssetPath assetPath = AbsolutePathToAssetPath(absolutePath); 112 | return assetPath; 113 | } 114 | 115 | /// 116 | /// Returns a list with parent dirs of this file or directory, and the file or directory itself. 117 | /// If stopDirectory is given, it will stop when it hits that directory. Otherwise, it stops at ~ 118 | /// 119 | /// For example, suppose this object represents 120 | /// ~/Views/Shared/EditorTemplates/HomeAddress 121 | /// and the stopDirectory is 122 | /// Views 123 | /// 124 | /// Then this method returns 125 | /// ~/Views/Shared/EditorTemplates/HomeAddress 126 | /// ~/Views/Shared/EditorTemplates 127 | /// ~/Views/Shared 128 | /// 129 | /// 130 | public IEnumerable ParentDirs(string stopDirectory = "~") 131 | { 132 | List parentDirs = new List(); 133 | string currentRootRelativePath = RootRelativePath; 134 | 135 | while (!currentRootRelativePath.EndsWith(stopDirectory)) 136 | { 137 | parentDirs.Add(new AssetPath(currentRootRelativePath, _rootToAbsolutePathFunc)); 138 | currentRootRelativePath = Path.GetDirectoryName(currentRootRelativePath); 139 | } 140 | 141 | return parentDirs; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/BundleFactories.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Optimization; 7 | 8 | namespace DynamicBundles 9 | { 10 | public class BundleFactories 11 | { 12 | private Dictionary _log = null; 13 | 14 | public BundleFactories() 15 | { 16 | } 17 | 18 | /// 19 | /// Constructor 20 | /// 21 | /// 22 | /// A record of all bundle paths and the files in each bundle will be kept here. 23 | /// 24 | public BundleFactories(Dictionary log) 25 | { 26 | _log = log; 27 | } 28 | 29 | /// 30 | /// Creates a script bundle with the given path (= name) and files 31 | /// 32 | public ScriptBundle ScriptBundleFactory(string bundleVirtualPath, string[] fileRootRelativePaths) 33 | { 34 | return BundleWithPaths(new ScriptBundle(bundleVirtualPath), fileRootRelativePaths); 35 | } 36 | 37 | /// 38 | /// Creates a style bundle with the given path (= name) and files 39 | /// 40 | public StyleBundle StyleBundleFactory(string bundleVirtualPath, string[] fileRootRelativePaths) 41 | { 42 | return BundleWithPaths(new StyleBundle(bundleVirtualPath), fileRootRelativePaths); 43 | } 44 | 45 | private T BundleWithPaths(T bundle, string[] fileRootRelativePaths) where T: Bundle 46 | { 47 | bundle.Include(fileRootRelativePaths); 48 | 49 | if (_log != null) 50 | { 51 | _log[bundle.Path] = fileRootRelativePaths; 52 | } 53 | 54 | return bundle; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/BundleHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Optimization; 7 | using BundleTransformer.Core.Transformers; 8 | 9 | namespace DynamicBundles 10 | { 11 | internal class BundleHelper 12 | { 13 | /// 14 | /// Takes a list of lists of file paths. Each file path is root relative (starts with ~). 15 | /// Turns these lists of paths into bundles. Ensures each file path is added only once. 16 | /// 17 | /// Adds the bundles to the given bundle collection, but only if there is no bundle yet with the same files, 18 | /// regardless of the order of the files or casing. That is, (a.css, b.css) is regarded as the same as (B.css, a.css). 19 | /// Returns a list with the bundle paths, in the same order as the originating lists 20 | /// in the input list of lists. 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// Used to create a new bundle object. 26 | /// 27 | /// 28 | public static List AddFileListsAsBundles(IDynamicBundleCollection bundles, 29 | List> fileLists, 30 | Func bundleFactory) 31 | { 32 | var bundleNames = new List(); 33 | foreach (List fileList in fileLists) 34 | { 35 | if (fileList.Count > 0) 36 | { 37 | 38 | // You can optimise things by doing the deduping inside HashCodeForList, because that 39 | // represents the strings as integers (hash codes), which are faster to dedupe. 40 | 41 | IEnumerable filePathsList = fileList.Select(f => f.RootRelativePath); 42 | 43 | // Reverse the order of the files. Files that have been added later tend to be more generic 44 | // (such as files in _Layout are added before those in _LayoutContainer). This way, files that depend on the 45 | // more generic files are loaded later. 46 | string[] dedupedFileRootRelativePaths = filePathsList.Distinct().Reverse().ToArray(); 47 | 48 | string listHashCode = StringListHelper.HashCodeForList(dedupedFileRootRelativePaths); 49 | string bundleName = "~/" + listHashCode; 50 | 51 | if (!bundles.Exists(bundleName)) 52 | { 53 | Bundle newBundle = bundleFactory(bundleName, dedupedFileRootRelativePaths); 54 | bundles.Add(newBundle); 55 | } 56 | 57 | bundleNames.Add(bundleName); 58 | } 59 | } 60 | 61 | return bundleNames; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/CacheHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | using System.Web.Caching; 8 | 9 | namespace DynamicBundles 10 | { 11 | public interface ICacheHelper 12 | { 13 | T Get(string cacheKey, Func createItem, IEnumerable directories); 14 | } 15 | 16 | public class CacheHelper : ICacheHelper 17 | { 18 | private static object lockThis = new Object(); 19 | 20 | /// 21 | /// Gets an item from cache. 22 | /// If the item is not in cache, creates it and stores it, with a dependency on a collection of directories - 23 | /// so if a file is added/deleted or changed, the cache item is removed from cache. 24 | /// 25 | /// 26 | /// Type of the item. 27 | /// 28 | /// 29 | /// Cache key. 30 | /// 31 | /// 32 | /// Lambda that creates the item. 33 | /// 34 | /// 35 | /// New cache item is dependend on these directories. 36 | /// 37 | /// 38 | public T Get(string cacheKey, Func createItem, IEnumerable directories) 39 | { 40 | T item = (T)HttpContext.Current.Cache[cacheKey]; 41 | 42 | if (item == null) 43 | { 44 | lock(lockThis) 45 | { 46 | item = (T)HttpContext.Current.Cache[cacheKey]; 47 | if (item == null) 48 | { 49 | item = createItem(); 50 | HttpContext.Current.Cache.Insert(cacheKey, item, new CacheDependency(directories.ToArray())); 51 | } 52 | } 53 | } 54 | 55 | return item; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using DynamicBundles.Models; 7 | using System.IO; 8 | using System.Web; 9 | 10 | namespace DynamicBundles 11 | { 12 | public interface IDependencyResolver 13 | { 14 | FileListsByAssetType GetRequiredFilesForDirectory(AssetPath dirPath); 15 | } 16 | 17 | public class DependencyResolver : IDependencyResolver 18 | { 19 | ICacheHelper _cacheHelper = null; 20 | 21 | public DependencyResolver(ICacheHelper cacheHelper) 22 | { 23 | _cacheHelper = cacheHelper; 24 | } 25 | 26 | /// 27 | /// Takes the path to a directory and returns the files in that directory, the files in the parent directories (down to the Views or ~ dir), 28 | /// and all the files 29 | /// that that directory depends on (via .nuspec files). 30 | /// 31 | /// It does not go into sub directories. 32 | /// 33 | /// Uses caching to reduce trips to the file system. 34 | /// 35 | /// 36 | /// Path to the directory. 37 | /// 38 | /// 39 | /// The required files, split by asset type. 40 | /// 41 | public FileListsByAssetType GetRequiredFilesForDirectory(AssetPath dirPath) 42 | { 43 | string absolutePath = dirPath.AbsolutePath; 44 | var fileListsByAssetType = _cacheHelper.Get(absolutePath, () => GetRequiredFilesForDirectoryUnchached(dirPath), new[] { absolutePath }); 45 | return fileListsByAssetType; 46 | } 47 | 48 | /// 49 | /// Same as GetRequiredFilesForDirectory, but uncached. 50 | /// 51 | /// 52 | /// Path to the directory. 53 | /// 54 | /// 55 | private FileListsByAssetType GetRequiredFilesForDirectoryUnchached(AssetPath dirPath) 56 | { 57 | FileListsByAssetType fileListsByAssetType = new FileListsByAssetType(); 58 | 59 | // Note: parentDirs will contain dirPath itself. 60 | // 61 | // dirPath.ParentDirs will give you something like 62 | /// ~/Views/Shared/EditorTemplates/HomeAddress 63 | /// ~/Views/Shared/EditorTemplates 64 | /// ~/Views/Shared 65 | // However, the longer directory tends to have the more specific files. If there is a dependency between files in these 66 | // directories, it would be from more specific to less specific, not the other way around. So process the directories in 67 | // reverse order, so CSS and JS files in more common directories are loaded first. 68 | 69 | IEnumerable parentDirs = dirPath.ParentDirs("Views").Reverse(); 70 | foreach (AssetPath parentDir in parentDirs) 71 | { 72 | AddRequiredFilesSingleDirectory(fileListsByAssetType, parentDir); 73 | } 74 | 75 | return fileListsByAssetType; 76 | } 77 | 78 | /// 79 | /// Adds all files in a single directory to a fileListsByAssetType 80 | /// 81 | /// 82 | /// 83 | private void AddRequiredFilesSingleDirectory(FileListsByAssetType fileListsByAssetType, AssetPath dirPath) 84 | { 85 | string absolutePath = dirPath.AbsolutePath; 86 | IEnumerable filePaths = Directory.EnumerateFiles(absolutePath); 87 | 88 | // Need to first process the nuspec files, and then the asset files. 89 | // This because the asset files may depend on the files pointed at by the nuspec files. 90 | for (int i = 0; i < 2; i++) 91 | { 92 | foreach (string filePath in filePaths) 93 | { 94 | if (i == 0) 95 | { 96 | if (NuspecFile.IsNuspecFile(filePath)) 97 | { 98 | fileListsByAssetType.Append(GetDependencies(filePath, dirPath)); 99 | } 100 | } 101 | else 102 | { 103 | AssetType? assetType = AssetTypeOfFile(filePath); 104 | if (assetType != null) 105 | { 106 | fileListsByAssetType.Add(dirPath.AbsolutePathToAssetPath(filePath), assetType.Value); 107 | } 108 | } 109 | } 110 | } 111 | } 112 | 113 | /// 114 | /// Reads the dependencies in a Nuspec file. These are directories. 115 | /// Accumulates the assets in those directories to in a FileListsByAssetType. 116 | /// This is then returned. 117 | /// 118 | /// This method calls the dependency resolver concurrently. 119 | /// 120 | /// 121 | /// Path of the nuspec file 122 | /// 123 | /// 124 | /// The directory where the nuspec file is located. 125 | /// 126 | /// 127 | private FileListsByAssetType GetDependencies(string absoluteNuspecPath, AssetPath nuspecFileDirPath) 128 | { 129 | FileListsByAssetType fileListsByAssetType = new FileListsByAssetType(); 130 | 131 | var nuspecFile = new NuspecFile(absoluteNuspecPath); 132 | List dependencyAssetPaths = nuspecFile.DependencyIds.Select(d => nuspecFileDirPath.Create(d)).ToList(); 133 | 134 | // Call the dependency resolver concurrently for each dependency 135 | foreach (AssetPath dependencyAssetPath in dependencyAssetPaths) 136 | { 137 | fileListsByAssetType.Append(GetRequiredFilesForDirectory(dependencyAssetPath)); 138 | } 139 | 140 | return fileListsByAssetType; 141 | } 142 | 143 | /// 144 | /// Takes a file path, and returns the asset type of that file. 145 | /// If there is no known asset type for the file, returns null. 146 | /// 147 | /// 148 | /// 149 | private AssetType? AssetTypeOfFile(string filePath) 150 | { 151 | string extension = Path.GetExtension(filePath).ToLower(); 152 | 153 | switch (extension) 154 | { 155 | case ".js": 156 | return AssetType.Script; 157 | 158 | case ".css": 159 | return AssetType.StyleSheet; 160 | 161 | default: 162 | return null; 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DynamicBundleCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Optimization; 7 | 8 | namespace DynamicBundles 9 | { 10 | public interface IDynamicBundleCollection 11 | { 12 | bool Exists(string bundleName); 13 | void Add(Bundle bundleName); 14 | } 15 | 16 | /// 17 | /// Encapsulates the MVC BundleCollection. The difference is that this class 18 | /// implements IBundleCollection, so it can be replaced by a mock 19 | /// during unit testing. 20 | /// 21 | internal class DynamicBundleCollection : IDynamicBundleCollection 22 | { 23 | private BundleCollection _bundles = null; 24 | 25 | public DynamicBundleCollection(BundleCollection bundles) 26 | { 27 | _bundles = bundles; 28 | } 29 | 30 | /// 31 | /// Returns true if a bundle with the passed in name exists. 32 | /// 33 | public bool Exists(string bundleName) 34 | { 35 | return (_bundles.GetBundleFor(bundleName) != null); 36 | } 37 | 38 | /// 39 | /// Adds the given Bundle to the bundle collection 40 | /// 41 | public void Add(Bundle bundle) 42 | { 43 | _bundles.Add(bundle); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DynamicBundles.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {37C5ED5D-3951-4325-9191-BCD55DDDD3FE} 8 | Library 9 | Properties 10 | DynamicBundles 11 | DynamicBundles 12 | v4.5 13 | 512 14 | ..\packages\WebGrease.1.5.2\lib 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll 39 | 40 | 41 | ..\packages\BundleTransformer.Core.1.9.25\lib\net40\BundleTransformer.Core.dll 42 | 43 | 44 | ..\packages\JavaScriptEngineSwitcher.Core.1.2.0\lib\net40\JavaScriptEngineSwitcher.Core.dll 45 | 46 | 47 | True 48 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 49 | 50 | 51 | False 52 | ..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll 53 | 54 | 55 | 56 | 57 | 58 | False 59 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll 60 | 61 | 62 | False 63 | ..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll 64 | 65 | 66 | False 67 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll 68 | 69 | 70 | False 71 | ..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll 72 | 73 | 74 | False 75 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll 76 | 77 | 78 | False 79 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll 80 | 81 | 82 | False 83 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 127 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DynamicBundles.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | http://getdynamicbundles.com/ 10 | false 11 | $description$ 12 | Copyright 2014 13 | MVC Bundles CSS JavaScript images HTML 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DynamicBundlesBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using DynamicBundles.Models; 7 | using System.Web.Optimization; 8 | 9 | namespace DynamicBundles 10 | { 11 | public class DynamicBundlesBuilder 12 | { 13 | IDynamicBundleCollection _bundles; 14 | ICacheHelper _cacheHelper; 15 | BundleFactories _bundleFactories; 16 | 17 | /// 18 | /// The bundle collection that the bundles will be added to. 19 | /// 20 | /// Outside tests, this would always be BundleTable.Bundles 21 | /// 22 | /// 23 | /// Cachehelper to use. 24 | /// 25 | public DynamicBundlesBuilder(IDynamicBundleCollection bundles, ICacheHelper cacheHelper, BundleFactories bundleFactories) 26 | { 27 | _bundles = bundles; 28 | _cacheHelper = cacheHelper; 29 | _bundleFactories = bundleFactories; 30 | } 31 | 32 | /// 33 | /// Builds the bundles that need to be loaded on the page. 34 | /// 35 | /// 36 | /// The directories with assets that need to be included. These directories may have dependencies 37 | /// on other directories, such as via .nuspec dependencies files and parent directories. 38 | /// 39 | /// When a view is processed, its directory is normally added to this list. 40 | /// 41 | /// 42 | /// The virtual paths of the generated script bundles. 43 | /// 44 | /// 45 | /// The virtual paths of the generated style bundles. 46 | /// 47 | public void Builder(List assetDirectoryList, 48 | out List scriptBundleVirtualPaths, 49 | out List styleBundleVirtualPaths) 50 | { 51 | var fileListsByAssetType = new FileListsByAssetType(); 52 | var dependencyResolver = new DependencyResolver(_cacheHelper); 53 | 54 | foreach (AssetPath assetDirectory in assetDirectoryList) 55 | { 56 | FileListsByAssetType requiredFilesByAssetType = dependencyResolver.GetRequiredFilesForDirectory(assetDirectory); 57 | fileListsByAssetType.Append(requiredFilesByAssetType); 58 | } 59 | 60 | // fileListsByAssetType now contains all required files by asset type 61 | 62 | scriptBundleVirtualPaths = CreateBundles(fileListsByAssetType, AssetType.Script, _bundleFactories.ScriptBundleFactory); 63 | styleBundleVirtualPaths = CreateBundles(fileListsByAssetType, AssetType.StyleSheet, _bundleFactories.StyleBundleFactory); 64 | } 65 | 66 | private List CreateBundles(FileListsByAssetType fileListsByAssetType, AssetType assetType, Func bundleFactory) 67 | { 68 | List files = fileListsByAssetType.GetList(assetType); 69 | List> filesByAreaController = RouteHelper.FilePathsSortedByRoute(files); 70 | List bundleVirtualPaths = BundleHelper.AddFileListsAsBundles(_bundles, filesByAreaController, bundleFactory); 71 | return bundleVirtualPaths; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/DynamicBundlesViewEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Mvc; 7 | 8 | namespace DynamicBundles 9 | { 10 | public class DynamicBundlesViewEngine : RazorViewEngine 11 | { 12 | public DynamicBundlesViewEngine(): base() 13 | { 14 | // Finds views sitting in own directories, such as ~/Views/Home/Index/Index.cshtml. 15 | // Note that this only works if you specify only the name of the view ("Index"), because only then 16 | // does the view engine do a search. If you specify the path, then you need to specify the view's directory as well 17 | // (such as: "~/Views/Shared/_Layout/_Layout.cshtml") 18 | // 19 | // See book "Pro ASP.NET MVC 4, page 495 20 | ViewLocationFormats = new string[] 21 | { 22 | "~/Views/{1}/{0}/{0}.cshtml", 23 | "~/Views/{1}/{0}/{0}.vbhtml", 24 | "~/Views/Shared/{0}/{0}.cshtml", 25 | "~/Views/Shared/{0}/{0}.vbhtml" 26 | }; 27 | 28 | MasterLocationFormats = ViewLocationFormats; 29 | PartialViewLocationFormats = ViewLocationFormats; 30 | 31 | AreaViewLocationFormats = new string[] 32 | { 33 | "~/Areas/{2}/Views/{1}/{0}/{0}.cshtml", 34 | "~/Areas/{2}/Views/{1}/{0}/{0}.vbhtml", 35 | "~/Areas/{2}/Views/Shared/{0}/{0}.cshtml", 36 | "~/Areas/{2}/Views/Shared/{0}/{0}.vbhtml" 37 | }; 38 | 39 | AreaMasterLocationFormats = AreaViewLocationFormats; 40 | AreaPartialViewLocationFormats = AreaViewLocationFormats; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/HttpContextStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | 8 | namespace DynamicBundles 9 | { 10 | /// 11 | /// Strongly typed access to the HttpContext.Items store, which holds 12 | /// per-request info. 13 | /// 14 | public static class HttpContextStore 15 | { 16 | private static readonly string AssetDirectoryItemKey = "__DynamicBundles_AssetDirectory"; 17 | private static readonly string FirstTimeItemKey = "__DynamicBundles_FirstTime"; 18 | private static readonly string TopBundleNamesItemKey = "__DynamicBundles_TopBundleNames"; 19 | private static readonly string BottomBundleNamesItemKey = "__DynamicBundles_BottomBundleNames"; 20 | 21 | /// 22 | /// Adds a directory with assets (script files, etc.) to the stored list of asset directories. 23 | /// 24 | /// 25 | public static void AddAssetDirectory(AssetPath dirPath) 26 | { 27 | List assetDirectoryList = (List)HttpContext.Current.Items[AssetDirectoryItemKey]; 28 | if (assetDirectoryList == null) 29 | { 30 | assetDirectoryList = new List(); 31 | HttpContext.Current.Items[AssetDirectoryItemKey] = assetDirectoryList; 32 | } 33 | 34 | assetDirectoryList.Add(dirPath); 35 | } 36 | 37 | /// 38 | /// Gets the list of asset directories 39 | /// 40 | /// 41 | public static List GetAssetDirectories() 42 | { 43 | List assetDirectoryList = (List)HttpContext.Current.Items[AssetDirectoryItemKey]; 44 | 45 | // There should be at least one asset directory - that of the main view. 46 | if (assetDirectoryList == null) 47 | { 48 | throw new Exception("GetAssetDirectories - assetDirectoryList is null"); 49 | } 50 | 51 | return assetDirectoryList; 52 | } 53 | 54 | /// 55 | /// Returns true if this is the first time this method is called 56 | /// for this request. Returns false otherwise. 57 | /// 58 | /// 59 | public static bool FirstTime() 60 | { 61 | object firstTimeSet = HttpContext.Current.Items[FirstTimeItemKey]; 62 | 63 | if (firstTimeSet != null) { return false; } 64 | 65 | HttpContext.Current.Items[FirstTimeItemKey] = true; 66 | 67 | return true; 68 | } 69 | 70 | /// 71 | /// Stores the list with names of bundles that need to be rendered 72 | /// near the top of the _Layout file. 73 | /// 74 | public static void StoreTopBundleNames(List bundleNames) 75 | { 76 | HttpContext.Current.Items[TopBundleNamesItemKey] = bundleNames; 77 | } 78 | 79 | /// 80 | /// Gets the list with names of bundles that need to be rendered 81 | /// near the top of the _Layout file. 82 | /// 83 | public static List GetTopBundleNames() 84 | { 85 | List bundleNames = (List)HttpContext.Current.Items[TopBundleNamesItemKey]; 86 | 87 | if (bundleNames == null) 88 | { 89 | throw new Exception("GetTopBundleNames - bundleNames is null"); 90 | } 91 | 92 | return bundleNames; 93 | } 94 | 95 | /// 96 | /// Stores the list with names of bundles that need to be rendered 97 | /// near the bottom of the _Layout file. 98 | /// 99 | public static void StoreBottomBundleNames(List bundleNames) 100 | { 101 | HttpContext.Current.Items[BottomBundleNamesItemKey] = bundleNames; 102 | } 103 | 104 | /// 105 | /// Gets the list with names of bundles that need to be rendered 106 | /// near the bottom of the _Layout file. 107 | /// 108 | public static List GetBottomBundleNames() 109 | { 110 | List bundleNames = (List)HttpContext.Current.Items[BottomBundleNamesItemKey]; 111 | 112 | if (bundleNames == null) 113 | { 114 | throw new Exception("GetBottomBundleNames - bundleNames is null"); 115 | } 116 | 117 | return bundleNames; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/Models/AssetType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DynamicBundles.Models 8 | { 9 | public enum AssetType 10 | { 11 | Script, 12 | StyleSheet 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/Models/FileListsByAssetType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DynamicBundles.Models 8 | { 9 | /// 10 | /// Stores lists of file paths by asset type. 11 | /// 12 | public class FileListsByAssetType: ListsByKey 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/Models/ListsByKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DynamicBundles.Models 8 | { 9 | /// 10 | /// Stores lists of T by keys of type K. 11 | /// 12 | public class ListsByKey 13 | { 14 | Dictionary> store = new Dictionary>(); 15 | 16 | private Dictionary> Store 17 | { 18 | get { return store; } 19 | } 20 | 21 | public ListsByKey() 22 | { 23 | } 24 | 25 | /// 26 | /// Appends another ListsByKey to this ListsByKey. 27 | /// This means that the lists of T of the other ListsByKey are appended 28 | /// to the lists in this ListsByKey, by key. 29 | /// 30 | /// The order of the items in listsByKey is preserved. 31 | /// 32 | /// 33 | public void Append(ListsByKey listsByKey) 34 | { 35 | foreach (KeyValuePair> kvp in listsByKey.Store) 36 | { 37 | AddRange(kvp.Value, kvp.Key); 38 | } 39 | } 40 | 41 | /// 42 | /// Adds an item to the list with the given key. 43 | /// 44 | public void Add(T item, K key) 45 | { 46 | if (!store.ContainsKey(key)) 47 | { 48 | store[key] = new List(); 49 | } 50 | 51 | store[key].Add(item); 52 | } 53 | 54 | /// 55 | /// Adds a list of items to the list with the given key. 56 | /// 57 | public void AddRange(List items, K key) 58 | { 59 | if (!store.ContainsKey(key)) 60 | { 61 | store[key] = new List(); 62 | } 63 | 64 | store[key].AddRange(items); 65 | } 66 | 67 | /// 68 | /// Returns the list for the given key. 69 | /// 70 | /// 71 | /// 72 | public List GetList(K key) 73 | { 74 | if (!store.ContainsKey(key)) 75 | { 76 | return new List(); 77 | } 78 | 79 | return store[key]; 80 | } 81 | 82 | /// 83 | /// Returns all lists, by key. 84 | /// 85 | /// 86 | public List>> GetListOfLists() 87 | { 88 | return store.ToList(); 89 | } 90 | 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/NuGet/readme.txt: -------------------------------------------------------------------------------- 1 | ================================== 2 | DynamicBundles is not yet fully installed 3 | ================================== 4 | 5 | To finish the installation, a few more steps need to be done. See 6 | 7 | http://getdynamicbundles.com/#installation 8 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/NuspecFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Xml.Serialization; 8 | 9 | namespace DynamicBundles 10 | { 11 | public class NuspecFile 12 | { 13 | #region classes 14 | 15 | /// 16 | [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 17 | [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] 18 | public partial class package 19 | { 20 | 21 | private packageMetadata metadataField; 22 | 23 | private packageFile[] filesField; 24 | 25 | /// 26 | public packageMetadata metadata 27 | { 28 | get 29 | { 30 | return this.metadataField; 31 | } 32 | set 33 | { 34 | this.metadataField = value; 35 | } 36 | } 37 | 38 | /// 39 | [System.Xml.Serialization.XmlArrayItemAttribute("file", IsNullable = false)] 40 | public packageFile[] files 41 | { 42 | get 43 | { 44 | return this.filesField; 45 | } 46 | set 47 | { 48 | this.filesField = value; 49 | } 50 | } 51 | } 52 | 53 | /// 54 | [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 55 | public partial class packageMetadata 56 | { 57 | 58 | private string idField; 59 | 60 | private string versionField; 61 | 62 | private string titleField; 63 | 64 | private string authorsField; 65 | 66 | private string ownersField; 67 | 68 | private string projectUrlField; 69 | 70 | private string iconUrlField; 71 | 72 | private bool requireLicenseAcceptanceField; 73 | 74 | private string descriptionField; 75 | 76 | private string copyrightField; 77 | 78 | private string tagsField; 79 | 80 | private packageMetadataDependency[] dependenciesField; 81 | 82 | /// 83 | public string id 84 | { 85 | get 86 | { 87 | return this.idField; 88 | } 89 | set 90 | { 91 | this.idField = value; 92 | } 93 | } 94 | 95 | /// 96 | public string version 97 | { 98 | get 99 | { 100 | return this.versionField; 101 | } 102 | set 103 | { 104 | this.versionField = value; 105 | } 106 | } 107 | 108 | /// 109 | public string title 110 | { 111 | get 112 | { 113 | return this.titleField; 114 | } 115 | set 116 | { 117 | this.titleField = value; 118 | } 119 | } 120 | 121 | /// 122 | public string authors 123 | { 124 | get 125 | { 126 | return this.authorsField; 127 | } 128 | set 129 | { 130 | this.authorsField = value; 131 | } 132 | } 133 | 134 | /// 135 | public string owners 136 | { 137 | get 138 | { 139 | return this.ownersField; 140 | } 141 | set 142 | { 143 | this.ownersField = value; 144 | } 145 | } 146 | 147 | /// 148 | public string projectUrl 149 | { 150 | get 151 | { 152 | return this.projectUrlField; 153 | } 154 | set 155 | { 156 | this.projectUrlField = value; 157 | } 158 | } 159 | 160 | /// 161 | public string iconUrl 162 | { 163 | get 164 | { 165 | return this.iconUrlField; 166 | } 167 | set 168 | { 169 | this.iconUrlField = value; 170 | } 171 | } 172 | 173 | /// 174 | public bool requireLicenseAcceptance 175 | { 176 | get 177 | { 178 | return this.requireLicenseAcceptanceField; 179 | } 180 | set 181 | { 182 | this.requireLicenseAcceptanceField = value; 183 | } 184 | } 185 | 186 | /// 187 | public string description 188 | { 189 | get 190 | { 191 | return this.descriptionField; 192 | } 193 | set 194 | { 195 | this.descriptionField = value; 196 | } 197 | } 198 | 199 | /// 200 | public string copyright 201 | { 202 | get 203 | { 204 | return this.copyrightField; 205 | } 206 | set 207 | { 208 | this.copyrightField = value; 209 | } 210 | } 211 | 212 | /// 213 | public string tags 214 | { 215 | get 216 | { 217 | return this.tagsField; 218 | } 219 | set 220 | { 221 | this.tagsField = value; 222 | } 223 | } 224 | 225 | /// 226 | [System.Xml.Serialization.XmlArrayItemAttribute("dependency", IsNullable = false)] 227 | public packageMetadataDependency[] dependencies 228 | { 229 | get 230 | { 231 | return this.dependenciesField; 232 | } 233 | set 234 | { 235 | this.dependenciesField = value; 236 | } 237 | } 238 | } 239 | 240 | /// 241 | [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 242 | public partial class packageMetadataDependency 243 | { 244 | 245 | private string idField; 246 | 247 | private string versionField; 248 | 249 | /// 250 | [System.Xml.Serialization.XmlAttributeAttribute()] 251 | public string id 252 | { 253 | get 254 | { 255 | return this.idField; 256 | } 257 | set 258 | { 259 | this.idField = value; 260 | } 261 | } 262 | 263 | /// 264 | [System.Xml.Serialization.XmlAttributeAttribute()] 265 | public string version 266 | { 267 | get 268 | { 269 | return this.versionField; 270 | } 271 | set 272 | { 273 | this.versionField = value; 274 | } 275 | } 276 | } 277 | 278 | /// 279 | [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 280 | public partial class packageFile 281 | { 282 | 283 | private string srcField; 284 | 285 | private string targetField; 286 | 287 | /// 288 | [System.Xml.Serialization.XmlAttributeAttribute()] 289 | public string src 290 | { 291 | get 292 | { 293 | return this.srcField; 294 | } 295 | set 296 | { 297 | this.srcField = value; 298 | } 299 | } 300 | 301 | /// 302 | [System.Xml.Serialization.XmlAttributeAttribute()] 303 | public string target 304 | { 305 | get 306 | { 307 | return this.targetField; 308 | } 309 | set 310 | { 311 | this.targetField = value; 312 | } 313 | } 314 | } 315 | #endregion 316 | 317 | private package _package; 318 | 319 | /// 320 | /// Constructor. 321 | /// 322 | /// 323 | /// Absolute path of the Nuspec file. 324 | /// 325 | public NuspecFile(string absolutePath) 326 | { 327 | using (TextReader reader = new StreamReader(absolutePath)) 328 | { 329 | XmlSerializer serializer = new XmlSerializer(typeof(package)); 330 | _package = (package)serializer.Deserialize(reader); 331 | } 332 | } 333 | 334 | public static bool IsNuspecFile(string absolutePath) 335 | { 336 | string extension = Path.GetExtension(absolutePath); 337 | return (String.CompareOrdinal(extension, ".nuspec") == 0); 338 | } 339 | 340 | /// 341 | /// Returns the ids of the dependencies in the nuspec file. 342 | /// 343 | /// 344 | public IEnumerable DependencyIds 345 | { 346 | get 347 | { 348 | if ((_package.metadata == null) || (_package.metadata.dependencies == null)) { return new List(); } 349 | 350 | return _package.metadata.dependencies.Select(d => d.id); 351 | } 352 | } 353 | } 354 | } 355 | 356 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------- 2 | // Generated.cs gets copied from Generated.cs.template 3 | // During the copy, 0.9.1 is replaced by the actual version. 4 | // --------------------------------------------------------------------------- 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("DynamicBundles - Dynamic MVC Bundles")] 14 | [assembly: AssemblyDescription("Co-locate HTML, CSS, JavaScript and image files that make up a page or component for easier reuse and maintainability. Auto generate your MVC bundles to ensure the right files are loaded in the right order.")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("Matt Perdeck")] 17 | [assembly: AssemblyProduct("DynamicBundles")] 18 | [assembly: AssemblyCopyright("Copyright ? 2014")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("12074b3f-e31f-4f70-ab10-4d6fde8d7209")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("0.9.1")] 41 | [assembly: AssemblyFileVersion("0.9.1")] 42 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/Properties/AssemblyInfo.cs.template: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------- 2 | // Generated.cs gets copied from Generated.cs.template 3 | // During the copy, __Version__ is replaced by the actual version. 4 | // --------------------------------------------------------------------------- 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("DynamicBundles - Dynamic MVC Bundles")] 14 | [assembly: AssemblyDescription("Co-locate HTML, CSS, JavaScript and image files that make up a page or component for easier reuse and maintainability. Auto generate your MVC bundles to ensure the right files are loaded in the right order.")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("Matt Perdeck")] 17 | [assembly: AssemblyProduct("DynamicBundles")] 18 | [assembly: AssemblyCopyright("Copyright © 2014")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("12074b3f-e31f-4f70-ab10-4d6fde8d7209")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("__Version__")] 41 | [assembly: AssemblyFileVersion("__Version__")] 42 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/RouteHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using DynamicBundles.Models; 8 | 9 | namespace DynamicBundles 10 | { 11 | public class RouteHelper 12 | { 13 | 14 | /// 15 | /// Takes a list of paths and puts them in separate lists, by area and controller. 16 | /// So all files in Area "Admin" and Controller "Home" go into one list, whilst 17 | /// all files without Area and Controller "About" go into another list. 18 | /// 19 | /// Within the lists, the original order of the files is preserved. So if 20 | /// the input list contains two files in Area "Admin" and Controller "Home", they are 21 | /// added to the result list in the same order as in the input list. 22 | /// 23 | /// The list of lists is sorted as follows, to ensure that the caller can 24 | /// place library files (such as jQuery) ahead of other files in the bundles: 25 | /// 26 | /// * files with no Area, with controller Shared, and that live in a directory with a name starting with _Layout 27 | /// * files with no Area, with controller Shared 28 | /// * files with an Area, with controller Shared, and that live in a directory with a name starting with _Layout 29 | /// * files with an Area, with controller Shared 30 | /// * all other files. 31 | /// 32 | /// 33 | /// 34 | public static List> FilePathsSortedByRoute(List filePaths) 35 | { 36 | var filePathsBySortKey = new ListsByKey(); 37 | 38 | foreach (AssetPath filePath in filePaths) 39 | { 40 | filePathsBySortKey.Add(filePath, FilePathSortKey(filePath)); 41 | } 42 | 43 | var sortedListOfLists = filePathsBySortKey.GetListOfLists(); 44 | sortedListOfLists.Sort((firstPair, nextPair) => firstPair.Key.CompareTo(nextPair.Key)); 45 | 46 | List> result = sortedListOfLists.Select(p => p.Value).ToList(); 47 | return result; 48 | } 49 | 50 | /// 51 | /// Takes a file path and returns a string formatted like this: 52 | /// 53 | /// * files with no Area, with controller Shared, and that live in a directory with a name starting with _Layout: 54 | /// @___@ 55 | /// 56 | /// * files with no Area, with controller Shared, but don't live in a directory with a name starting with _Layout: 57 | /// @___@@ 58 | /// 59 | /// * files with an Area, with controller Shared, and that live in a directory with a name starting with _Layout: 60 | /// [Area]___@ 61 | /// 62 | /// * files with an Area, with controller Shared, but don't live in a directory with a name starting with _Layout: 63 | /// [Area]___@@ 64 | /// 65 | /// * all other files, with no area 66 | /// @___[Controller] 67 | /// 68 | /// * all other files, with an area 69 | /// [Area]___[Controller] 70 | /// 71 | /// Note that alphabetically, @ sorts before any letter or digit. 72 | /// Also, @___@@ sorts after @___@. 73 | /// 74 | /// The method assumes that the file path is root relative, and follows MVC conventions: 75 | /// 76 | /// * path with an Area: 77 | /// ~/Areas/TestArea/Views/home/index/indexspecific.css 78 | /// 79 | /// * path without an Area: 80 | /// ~/Views/home/index/indexspecific.css 81 | /// 82 | /// If the file path doesn't adhere to this, the method returns 83 | /// @ 84 | /// 85 | /// 86 | /// 87 | public static string FilePathSortKey(AssetPath assetPath) 88 | { 89 | string filePath = assetPath.RootRelativePath; 90 | 91 | if (!filePath.StartsWith("~/")) 92 | { 93 | throw new Exception(string.Format("FilePathSortKey - filePath {0} does not start with ~/", filePath)); 94 | } 95 | 96 | string[] filePathComponents = filePath.Split(new char[] { '/' }); 97 | 98 | // Note that the first element in filePathComponents will be the ~ 99 | // The last element is the file name itself. 100 | 101 | string area = "@"; 102 | int nbrComponents = filePathComponents.Length; 103 | int controllerIdx = 2; 104 | 105 | if (string.CompareOrdinal(filePathComponents[1], "Areas") == 0) 106 | { 107 | if ((nbrComponents < 6) || (string.CompareOrdinal(filePathComponents[3], "Views") != 0)) 108 | { 109 | return "@"; 110 | } 111 | 112 | area = filePathComponents[2]; 113 | controllerIdx = 4; 114 | } 115 | else if (string.CompareOrdinal(filePathComponents[1], "Views") == 0) 116 | { 117 | if (nbrComponents < 4) 118 | { 119 | return "@"; 120 | } 121 | } 122 | else 123 | { 124 | return "@"; 125 | } 126 | 127 | string controller = filePathComponents[controllerIdx]; 128 | if (string.CompareOrdinal(controller, "Shared") == 0) 129 | { 130 | controller = "@"; 131 | } 132 | 133 | string postfix = "@"; 134 | int postControllerDirectoryIdx = (controllerIdx + 1); 135 | if (nbrComponents > postControllerDirectoryIdx) 136 | { 137 | string postControllerDirectory = filePathComponents[postControllerDirectoryIdx].ToLower(); 138 | if (postControllerDirectory.StartsWith("_layout")) 139 | { 140 | postfix = ""; 141 | } 142 | } 143 | 144 | string sortKey = area + "___" + controller + postfix; 145 | 146 | return sortKey; 147 | } 148 | } 149 | } 150 | 151 | 152 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/StringListHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DynamicBundles 8 | { 9 | public static class StringListHelper 10 | { 11 | /// 12 | /// Returns a string that is unique to the given list of strings. 13 | /// Order and casing are not relevant here, so (a.css, b.css) and (B.css, a.css) 14 | /// give the same code. 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// See http://stackoverflow.com/questions/670063/getting-hash-of-a-list-of-strings-regardless-of-order 20 | /// 21 | public static string HashCodeForList(IEnumerable list) 22 | { 23 | List codes = new List(); 24 | foreach (string item in list) 25 | { 26 | codes.Add(item.ToLower().GetHashCode()); 27 | } 28 | 29 | codes.Sort(); 30 | long hash = 0; 31 | 32 | foreach (int code in codes) 33 | { 34 | unchecked { 35 | hash *= 251; // multiply by a prime number 36 | hash += code; // add next hash code 37 | } 38 | } 39 | 40 | return hash.ToString("X"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/WebViewPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Web.Optimization; 7 | using System.Web; 8 | using System.IO; 9 | using DynamicBundles.Models; 10 | 11 | namespace DynamicBundles 12 | { 13 | /// 14 | /// All view classes inherit either this class, or WebViewPage 15 | /// 16 | public abstract class WebViewPage: System.Web.Mvc.WebViewPage 17 | { 18 | protected override void InitializePage() 19 | { 20 | WebViewPageStatic.InitializePage(this.VirtualPath); 21 | base.InitializePage(); 22 | } 23 | 24 | public override void ExecutePageHierarchy() 25 | { 26 | WebViewPageStatic.ExecutePageHierarchy(); 27 | base.ExecutePageHierarchy(); 28 | } 29 | 30 | public static IHtmlString DynamicBundlesTopRender() 31 | { 32 | return WebViewPageStatic.DynamicBundlesTopRender(); 33 | } 34 | 35 | public static IHtmlString DynamicBundlesBottomRender() 36 | { 37 | return WebViewPageStatic.DynamicBundlesBottomRender(); 38 | } 39 | } 40 | 41 | public abstract class WebViewPage: System.Web.Mvc.WebViewPage 42 | { 43 | protected override void InitializePage() 44 | { 45 | WebViewPageStatic.InitializePage(this.VirtualPath); 46 | base.InitializePage(); 47 | } 48 | 49 | public override void ExecutePageHierarchy() 50 | { 51 | WebViewPageStatic.ExecutePageHierarchy(); 52 | base.ExecutePageHierarchy(); 53 | } 54 | 55 | public static IHtmlString DynamicBundlesTopRender() 56 | { 57 | return WebViewPageStatic.DynamicBundlesTopRender(); 58 | } 59 | 60 | public static IHtmlString DynamicBundlesBottomRender() 61 | { 62 | return WebViewPageStatic.DynamicBundlesBottomRender(); 63 | } 64 | } 65 | 66 | internal static class WebViewPageStatic 67 | { 68 | private static DynamicBundlesBuilder _dynamicBundlesBuilder = 69 | new DynamicBundlesBuilder(new DynamicBundleCollection(BundleTable.Bundles), 70 | new CacheHelper(), 71 | new BundleFactories()); 72 | 73 | /// 74 | /// Called when a view file is being processed, such as the main view file, partial views and layout views. 75 | /// 76 | /// 77 | /// Root relative path to the view. 78 | /// 79 | public static void InitializePage(string viewVirtualPath) 80 | { 81 | // Store the directory that the view file lives in 82 | HttpContextStore.AddAssetDirectory(new AssetPath(Path.GetDirectoryName(viewVirtualPath), HttpContext.Current.Server.MapPath)); 83 | } 84 | 85 | /// 86 | /// ExecutePageHierarchy is executed after all InitializePage calls, 87 | /// but before the bundles are created. 88 | /// 89 | public static void ExecutePageHierarchy() 90 | { 91 | } 92 | 93 | /// 94 | /// Call this method from the top level _Layout view, in the head section. 95 | /// It replaces the normal 96 | /// @Styles.Render("....") and 97 | /// @Scripts.Render("....") 98 | /// lines that sit near the top of the page. 99 | /// 100 | /// It renders all the bundles that the page needs (these can be different per page) and need to go 101 | /// near the top (mainly style bundles). 102 | /// 103 | /// 104 | /// 105 | /// When this method is called, you have to add any bundles that need to be added, 106 | /// so the ones that need to be rendered at the top of the page can be rendered here. 107 | /// That is, when this runs, the time for gathering file dependencies is over and you need to 108 | /// process them into bundles. 109 | /// 110 | public static IHtmlString DynamicBundlesTopRender() 111 | { 112 | if (!HttpContextStore.FirstTime()) { return new HtmlString(""); } 113 | 114 | List assetDirectoryList = HttpContextStore.GetAssetDirectories(); 115 | List scriptBundleVirtualPaths; 116 | List styleBundleVirtualPaths; 117 | 118 | _dynamicBundlesBuilder.Builder(assetDirectoryList, out scriptBundleVirtualPaths, out styleBundleVirtualPaths); 119 | 120 | HttpContextStore.StoreBottomBundleNames(scriptBundleVirtualPaths); 121 | 122 | // Note that Styles.Render assumes that all the bundles are StyleBundles 123 | return Styles.Render(styleBundleVirtualPaths.ToArray()); 124 | } 125 | 126 | /// 127 | /// Same as DynamicBundlesTopRender, but to be used near the bottom of the page 128 | /// (would render script bundles). 129 | /// 130 | /// 131 | public static IHtmlString DynamicBundlesBottomRender() 132 | { 133 | // Note that this assumes that all the bundles are ScriptBundles 134 | return Scripts.Render(HttpContextStore.GetBottomBundleNames().ToArray()); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DynamicBundles/DynamicBundles/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dynamicbundles 2 | ============== 3 | 4 | Dependency resolver for MVC web sites, using MVC bundles 5 | --------------------------------------------------------------------------------