Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web.Optimizations - any way to get all includes from a Style/Script Bundle?

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?

like image 815
timothyclifford Avatar asked Feb 15 '13 04:02

timothyclifford


2 Answers

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.

like image 65
Corey Avatar answered Oct 21 '22 19:10

Corey


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.

like image 20
Herman Kan Avatar answered Oct 21 '22 17:10

Herman Kan