Integration of dynamic content into the bundling process requires the following steps:
Writing the logic that requests / builds the required content. For SignalR you could use this code snippet:
public static string GetSignalRContent() { var resolver = new DefaultHubManager(new DefaultDependencyResolver()); var proxy = new DefaultJavaScriptProxyGenerator(resolver, new NullJavaScriptMinifier()); return proxy.GenerateProxy("/signalr"); }
Implement a virtual path provider that wraps the existing one and intercept all virtual paths that should deliver the dynamic content (just "~/signalr/hubs" in your case).
public class CustomVirtualPathProvider : VirtualPathProvider { public CustomActionVirtualPathProvider(VirtualPathProvider virtualPathProvider) { // Wrap an existing virtual path provider VirtualPathProvider = virtualPathProvider; } protected VirtualPathProvider VirtualPathProvider { get; set; } public override string CombineVirtualPaths(string basePath, string relativePath) { return VirtualPathProvider.CombineVirtualPaths(basePath, relativePath); } public override bool DirectoryExists(string virtualDir) { return VirtualPathProvider.DirectoryExists(virtualDir); } public override bool FileExists(string virtualPath) { if (virtualPath == "~/signalr/hubs") { return true; } return VirtualPathProvider.FileExists(virtualPath); } public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { // BaseClass can't create a CacheDependency for your content, remove it // You could also add your own CacheDependency and aggregate it with the base dependency List<string> virtualPathDependenciesCopy = virtualPathDependencies.Cast<string>().ToList(); virtualPathDependenciesCopy.Remove("~/signalr/hubs"); return VirtualPathProvider.GetCacheDependency(virtualPath, virtualPathDependenciesCopy, utcStart); } public override string GetCacheKey(string virtualPath) { return VirtualPathProvider.GetCacheKey(virtualPath); } public override VirtualDirectory GetDirectory(string virtualDir) { return VirtualPathProvider.GetDirectory(virtualDir); } public override VirtualFile GetFile(string virtualPath) { if (virtualPath == "~/signalr/hubs") { return new CustomVirtualFile(virtualPath, new MemoryStream(Encoding.Default.GetBytes(GetSignalRContent()))); } return VirtualPathProvider.GetFile(virtualPath); } public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) { return VirtualPathProvider.GetFileHash(virtualPath, virtualPathDependencies); } public override object InitializeLifetimeService() { return VirtualPathProvider.InitializeLifetimeService(); } } public class CustomVirtualFile : VirtualFile { public CustomVirtualFile (string virtualPath, Stream stream) : base(virtualPath) { Stream = stream; } public Stream Stream { get; private set; } public override Stream Open() { return Stream; } }
Register your virtual path provider:
public static void RegisterBundles(BundleCollection bundles) { // Set the virtual path provider BundleTable.VirtualPathProvider = new CustomVirtualPathProvider(BundleTable.VirtualPathProvider); Bundle include = new Bundle("~/bundle") .Include("~/Content/static.js") .Include("~/signalr/hubs"); bundles.Add(include); }
For some samples of virtual path providers + bundling, see Bundling and Minification and Embedded Resources or Bundling Dynamic Generated Controller / Action Content for example.