I'm working with some dynamic bundling which adds CSS and JS files based on configuration.
I spin up a new StyleBundle such that:
var cssBundle = new StyleBundle("~/bundle/css");
Then loop through config and add any found includes:
cssBundle.Include(config.Source);
Following the loop I want to check if there was actually any files/directories included. I know there's EnumerateFiles() but I don't think this 100% serves the purpose.
Anyone else done anything similar previously?
The Bundle
class uses an internal items list that is not exposed to the application, and isn't necessarily accessible via reflection (I tried and couldn't get any contents). You can fetch some information about this using the BundleResolver
class like so:
var cssBundle = new StyleBundle("~/bundle/css");
cssBundle.Include(config.Source);
// if your bundle is already in BundleTable.Bundles list, use that. Otherwise...
var collection = new BundleCollection();
collection.Add(cssBundle)
// get bundle contents
var resolver = new BundleResolver(collection);
List<string> cont = resolver.GetBundleContents("~/bundle/css").ToList();
If you just need a count then:
int count = resolver.GetBundleContents("~/bundle/css").Count();
Edit: using reflection
Apparently I did something wrong with my reflection test before.
This actually works:
using System.Reflection;
using System.Web.Optimization;
...
int count = ((ItemRegistry)typeof(Bundle).GetProperty("Items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(cssBundle, null)).Count;
You should probably add some safety checks there of course, and like a lot of reflection examples this violates the intended safety of the Items
property, but it does work.
You can use the following extension methods for Bundle
:
public static class BundleHelper
{
private static Dictionary<Bundle, List<string>> bundleIncludes = new Dictionary<Bundle, List<string>>();
private static Dictionary<Bundle, List<string>> bundleFiles = new Dictionary<Bundle, List<string>>();
private static void EnumerateFiles(Bundle bundle, string virtualPath)
{
if (bundleIncludes.ContainsKey(bundle))
bundleIncludes[bundle].Add(virtualPath);
else
bundleIncludes.Add(bundle, new List<string> { virtualPath });
int i = virtualPath.LastIndexOf('/');
string path = HostingEnvironment.MapPath(virtualPath.Substring(0, i));
if (Directory.Exists(path))
{
string fileName = virtualPath.Substring(i + 1);
IEnumerable<string> fileList;
if (fileName.Contains("{version}"))
{
var re = new Regex(fileName.Replace(".", @"\.").Replace("{version}", @"(\d+(?:\.\d+){1,3})"));
fileName = fileName.Replace("{version}", "*");
fileList = Directory.EnumerateFiles(path, fileName).Where(file => re.IsMatch(file));
}
else // fileName may contain '*'
fileList = Directory.EnumerateFiles(path, fileName);
if (bundleFiles.ContainsKey(bundle))
bundleFiles[bundle].AddRange(fileList);
else
bundleFiles.Add(bundle, fileList.ToList());
}
}
public static Bundle Add(this Bundle bundle, params string[] virtualPaths)
{
foreach (string virtualPath in virtualPaths)
EnumerateFiles(bundle, virtualPath);
return bundle.Include(virtualPaths);
}
public static Bundle Add(this Bundle bundle, string virtualPath, params IItemTransform[] transforms)
{
EnumerateFiles(bundle, virtualPath);
return bundle.Include(virtualPath, transforms);
}
public static IEnumerable<string> EnumerateIncludes(this Bundle bundle)
{
return bundleIncludes[bundle];
}
public static IEnumerable<string> EnumerateFiles(this Bundle bundle)
{
return bundleFiles[bundle];
}
}
Then simply replace your Include()
calls with Add()
:
var bundle = new ScriptBundle("~/test")
.Add("~/Scripts/jquery/jquery-{version}.js")
.Add("~/Scripts/lib*")
.Add("~/Scripts/model.js")
);
var includes = bundle.EnumerateIncludes();
var files = bundle.EnumerateFiles();
If you are also using IncludeDirectory()
, just complete the example by adding a respective AddDirectory()
extension method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With