Update: Not sure if it matters but I am using MVC 5.2.3 and Visual Studio 2015, question is a little old.
However I made dynamic bundling that works in _viewStart.cshtml. What I did was I made a helper class that stores bundles in a dictionary of bundles. Then at app start I pull them from the dictionary and register them. And I made a static boolen "bundlesInitialzed" so that the bundles only add to the dictionary once.
Example Helper:
public static class KBApplicationCore: .....
{
private static Dictionary<string, Bundle> _bundleDictionary = new Dictionary<string, Bundle>();
public static bool BundlesFinalized { get { return _BundlesFinalized; } }
/// <summary>
/// Add a bundle to the bundle dictionary
/// </summary>
/// <param name="bundle"></param>
/// <returns></returns>
public static bool RegisterBundle(Bundle bundle)
{
if (bundle == null)
throw new ArgumentNullException("bundle");
if (_BundlesFinalized)
throw new InvalidOperationException("The bundles have been finalized and frozen, you can only finalize the bundles once as an app pool recycle is needed to change the bundles afterwards!");
if (_bundleDictionary.ContainsKey(bundle.Path))
return false;
_bundleDictionary.Add(bundle.Path, bundle);
return true;
}
/// <summary>
/// Finalize the bundles, which commits them to the BundleTable.Bundles collection, respects the web.config's debug setting for optimizations
/// </summary>
public static void FinalizeBundles()
{
FinalizeBundles(null);
}
/// <summary>
/// Finalize the bundles, which commits them to the BundleTable.Bundles collection
/// </summary>
/// <param name="forceMinimize">Null = Respect web.config debug setting, True force minification regardless of web.config, False force no minification regardless of web.config</param>
public static void FinalizeBundles(bool? forceMinimize)
{
var bundles = BundleTable.Bundles;
foreach (var bundle in _bundleDictionary.Values)
{
bundles.Add(bundle);
}
if (forceMinimize != null)
BundleTable.EnableOptimizations = forceMinimize.Value;
_BundlesFinalized = true;
}
}
Example _ViewStart.cshtml
@{
var bundles = BundleTable.Bundles;
var baseUrl = string.Concat("~/App_Plugins/", KBApplicationCore.PackageManifest.FolderName, "/");
//Maybe there is a better way to do this, the goal is to make the bundle configurable without having to recompile the code
if (!KBApplicationCore.BundlesFinalized)
{
//Note, you need to reset the application pool in order for any changes here to be reloaded as the BundlesFinalized property is a static field that will only reset to false when the app restarts.
Bundle mainScripts = new ScriptBundle("~/bundles/scripts/main.js");
mainScripts.Include(new string[] {
baseUrl + "Assets/lib/jquery/jquery.js",
baseUrl + "Assets/lib/jquery/plugins/jqcloud/jqcloud.js",
baseUrl + "Assets/lib/bootstrap/js/bootstrap.js",
baseUrl + "Assets/lib/bootstrap/plugins/treeview/bootstrap-treeview.js",
baseUrl + "Assets/lib/angular/angular.js",
baseUrl + "Assets/lib/ckEditor/ckEditor.js"
});
KBApplicationCore.RegisterBundle(mainScripts);
Bundle appScripts = new ScriptBundle("~/bundles/scripts/app.js");
appScripts.Include(new string[] {
baseUrl + "Assets/app/app.js",
baseUrl + "Assets/app/services/*.js",
baseUrl + "Assets/app/directives/*.js",
baseUrl + "Assets/app/controllers/*.js"
});
KBApplicationCore.RegisterBundle(appScripts);
Bundle mainStyles = new StyleBundle("~/bundles/styles/main.css");
mainStyles.Include(new string[] {
baseUrl + "Assets/lib/bootstrap/build/less/bootstrap.less",
baseUrl + "Assets/lib/bootstrap/plugins/treeview/bootstrap-treeview.css",
baseUrl + "Assets/lib/ckeditor/contents.css",
baseUrl + "Assets/lib/font-awesome/less/font-awesome.less",
baseUrl + "Assets/styles/tlckb.less"
});
mainStyles.Transforms.Add(new BundleTransformer.Core.Transformers.CssTransformer());
mainStyles.Transforms.Add(new CssMinify());
mainStyles.Orderer = new BundleTransformer.Core.Orderers.NullOrderer();
KBApplicationCore.RegisterBundle(mainStyles);
KBApplicationCore.FinalizeBundles(true); //true = Force Optimizations, false = Force non Optmizations, null = respect web.config which is the same as calling the parameterless constructor.
}
}
Note: This should be updated to use thread locking to prevent 2 requests entering the bundle code before the first one exits.
The way this works is the view start runs on the first request to the site after an app pool reset. It calls the RegisterBundle on the helper and passes the ScriptBundle or StyleBundle to the dictionary in the order RegisterBundles is called.
When FinalizeBundles is called you can specify True which will force optimizations regardless of web.config debug setting, or leave it null or use the constructor without that parameter to have it respect the web.config setting. Passing false will force it to use no optimization even if debug is true. FinalizeBundles Registers the bundles in the bundles table and set's _BundlesFinalized to true.
Once finalized, an attempt to call RegisterBundle again will throw an exception, it's frozen at that point.
This setup allows you to add new bundles to view start and reset the app pool to get them to take effect. The original goal I had writing this was because I am making something others will use so I wanted them to be able to completely change the front end UI without having to rebuild the source to change the bundles.