ASP.NET MVC Bundle with absolute paths
Asked Answered
M

1

7

I have virtual directory on IIS which contains all javascript and css files. Is it possible to include those files into ASP.NET MVC app using Bundles.

I have already tried something like this:

bundles.Add(new ScriptBundle("~/bundles/jquery").Include("/public/javascript/jquery-{version}.js"));

but got error:

Only application relative URLs (~/url) are allowed.:

/public/javascript is virtual directory on IIS.

Merylmes answered 12/2, 2013 at 14:54 Comment(2)
Are you using MVC3 or 4? Why do you tag twice?Extrasystole
I'm looking for this, too. But I'm afraid that MVC bundle doesn't support anything except application relative paths like ~/public/javascript/foo.jsTrichoid
T
4

Actually Bundle class doesn't support absolute paths. I've opened a feature request here.

I've solved this problem with a custom VirtualPathProvider and a controller. But it is very fragile implementation. You can modify so far as what you need.

public class ModuleScriptProvider : VirtualPathProvider
{
    public static IBundleModule GetModulePath(string moduleName)
    {
       //return the absolute or relative path.
    }

    public static void ParseVirtualPath(string virtualPath, out string moduleName, out string path)
    {
        var parts = virtualPath.Replace("~/", "").Split('/').Where(p => !string.IsNullOrEmpty(p)).Skip(1).ToList();
        if (parts.Count < 2 || !virtualPath.EndsWith(".js"))
            throw new FileNotFoundException("Script file doesn't found in the module script directory", virtualPath);
        moduleName = parts.First(); // ~/ModuleScript/ModuleName/....
        path = string.Join(@"\", parts.Skip(1)); 
    }

    public static string MapPathMethod(string virtualPath)
    {
        if (IsModuleScriptPath(virtualPath))
        {
            string moduleName;
            string path;
            ParseVirtualPath(virtualPath, out moduleName, out path);
            var moduleDir = GetModulePath(moduleName); //absolute path
            if (!moduleDir.EndsWith(@"\"))
                moduleDir += @"\";
            return moduleDir + path;
        }
        return HttpContext.Current.Server.MapPath(virtualPath);
    }

    public static bool IsModuleScriptPath(string virtualPath)
    {
        String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);

        return checkPath.StartsWith("~/ModuleScript/", StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool FileExists(string virtualPath)
    {
        return (IsModuleScriptPath(virtualPath) || base.FileExists(virtualPath));
    }
    public override VirtualFile GetFile(string virtualPath)
    {
        if (IsModuleScriptPath(virtualPath))
            return new ModuleScriptVirtualFile(virtualPath);
        return base.GetFile(virtualPath);
    }

    public override CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
    {
        if (IsModuleScriptPath(virtualPath))
        {
            string moduleName;
            string path;
            ParseVirtualPath(virtualPath, out moduleName, out path);
            var bundleModulePath = GetModulePath(moduleName);
            return new CacheDependency(bundleModulePath);
        }

        return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
    }
    public override string CombineVirtualPaths(string basePath, string relativePath)
    {
        return base.CombineVirtualPaths(basePath, relativePath);
    }
}

class ModuleScriptVirtualFile : VirtualFile
{
    private readonly string _path;
    private readonly string _moduleName;
    public ModuleScriptVirtualFile(string virtualPath)
        : base(virtualPath)
    {
        ModuleScriptProvider.ParseVirtualPath(virtualPath, out _moduleName, out _path);
    }
    public override Stream Open()
    {
        var moduleDir = ModuleScriptProvider.GetModulePath(_moduleName);
        if (!moduleDir.EndsWith(@"\"))
            moduleDir += @"\";

        return new FileStream(moduleDir + _path, FileMode.Open);
    }
}

Controller:

public class ModuleScriptController : Controller
{
    public FileStreamResult GetFile(string path)
    {
        return new FileStreamResult(new ModuleScriptProvider().GetFile("~/ModuleScript/" + path).Open(), "text/javascript");
    }
}

In Global.asax Application_Start method:

HostingEnvironment.RegisterVirtualPathProvider(new ModuleScriptProvider());
BundleTable.EnableOptimizations = true;
BundleTable.MapPathMethod = ModuleScriptProvider.MapPathMethod;

God speed.

Trichoid answered 16/4, 2013 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.