Skip to content

Instantly share code, notes, and snippets.

@speier
Created July 19, 2013 09:16
Show Gist options
  • Save speier/6037842 to your computer and use it in GitHub Desktop.
Save speier/6037842 to your computer and use it in GitHub Desktop.
ASP.NET MVC embedded views and virtual path provider
using System.Web.Mvc;
using System.Web.Routing;
namespace Portal.Common.EmbeddedResources
{
public class EmbeddedResourcesController : Controller
{
public static void RegisterRoutes()
{
RouteTable.Routes.InsertRoute(
"Content",
"Content/{*virtualPath}",
new { controller = "EmbeddedResources", action = "Index" },
typeof(EmbeddedResourcesController).Namespace
);
RouteTable.Routes.InsertRoute(
"Scripts",
"Scripts/{*virtualPath}",
new { controller = "EmbeddedResources", action = "Index" },
typeof(EmbeddedResourcesController).Namespace
);
RouteTable.Routes.InsertRoute(
"Templates",
"Templates/{*virtualPath}",
new { controller = "EmbeddedResources", action = "Index" },
typeof(EmbeddedResourcesController).Namespace
);
}
public ActionResult Index(string virtualPath)
{
var virtualFile = EmbeddedResourcesManager.GetEmbeddedResourceFile(virtualPath);
if (virtualFile == null)
{
Response.StatusCode = 404;
return null;
}
return File(virtualFile.Open(), EmbeddedResourceTypes.GetContentType(virtualPath));
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
namespace Portal.Common.EmbeddedResources
{
public static class EmbeddedResourcesManager
{
public static IEnumerable<EmbeddedResourceItem> EmbeddedResources { get; private set; }
static EmbeddedResourcesManager()
{
EmbeddedResources = GetEmbeddedResources();
}
public static void Init()
{
HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewProvider());
}
public static bool IsEmbeddedResource(string virtualPath)
{
var relativePath = VirtualPathUtility.ToAppRelative(virtualPath);
return ContainsEmbeddedResource(relativePath);
}
public static bool IsEmbeddedView(string virtualPath)
{
return IsEmbeddedResource(virtualPath) && virtualPath.Contains("/Views/", StringComparison.InvariantCultureIgnoreCase);
}
public static bool ContainsEmbeddedResource(string virtualPath)
{
var foundResource = FindEmbeddedResource(virtualPath);
return (foundResource != null);
}
public static EmbeddedResourceItem FindEmbeddedResource(string virtualPath)
{
var name = GetNameFromPath(virtualPath);
var fileName = Path.GetFileName(virtualPath);
return string.IsNullOrEmpty(name)
? null
: EmbeddedResources.FirstOrDefault(r => r.Name.EndsWith(name, StringComparison.InvariantCultureIgnoreCase));
}
public static Stream GetManifestResourceStream(string virtualPath)
{
var embeddedResource = FindEmbeddedResource(virtualPath);
if (embeddedResource == null)
return null;
var assembly = GetAssemblies().FirstOrDefault(a => a.FullName.Equals(embeddedResource.AssemblyFullName, StringComparison.InvariantCultureIgnoreCase));
return (assembly == null) ? null : assembly.GetManifestResourceStream(embeddedResource.Name);
}
public static EmbeddedResourceFile GetEmbeddedResourceFile(string virtualPath)
{
var manifestResourceStream = GetManifestResourceStream(virtualPath);
return (manifestResourceStream == null) ? null : new EmbeddedResourceFile(virtualPath, manifestResourceStream);
}
public static string GetManifestResourceString(string virtualPath)
{
var resourceFile = GetEmbeddedResourceFile(virtualPath);
return (resourceFile == null) ? string.Empty : new StreamReader(resourceFile.Open()).ReadToEnd();
}
public static string GetNameFromPath(string virtualPath)
{
if (string.IsNullOrEmpty(virtualPath))
return null;
return virtualPath.Replace("~", string.Empty).Replace("/", ".");
}
private static IEnumerable<EmbeddedResourceItem> GetEmbeddedResources()
{
var assemblies = GetAssemblies();
if (assemblies == null || assemblies.Count() == 0)
return null;
var embeddedResources = new List<EmbeddedResourceItem>();
foreach (var assembly in assemblies)
{
var names = GetNamesOfAssemblyResources(assembly);
if (names == null || names.Length == 0)
continue;
var validNames = from name in names
let ext = Path.GetExtension(name)
where EmbeddedResourceTypes.Contains(ext) || name.ToLowerInvariant().Contains(".views.")
select name;
foreach (var name in validNames)
{
embeddedResources.Add(new EmbeddedResourceItem { Name = name, AssemblyFullName = assembly.FullName });
}
}
return embeddedResources;
}
private static IEnumerable<Assembly> GetAssemblies()
{
try
{
return AppDomain.CurrentDomain.GetAssemblies();
}
catch
{
return null;
}
}
private static string[] GetNamesOfAssemblyResources(Assembly assembly)
{
// GetManifestResourceNames will throw a NotSupportedException when run on a dynamic assembly
try
{
return assembly.GetManifestResourceNames();
}
catch
{
return new string[] { };
}
}
}
public class EmbeddedResourceItem
{
public string Name { get; set; }
public string AssemblyFullName { get; set; }
}
public class EmbeddedResourceFile : VirtualFile
{
private readonly Stream _manifestResourceStream;
public EmbeddedResourceFile(string virtualPath, Stream manifestResourceStream) :
base(virtualPath)
{
_manifestResourceStream = manifestResourceStream;
}
public override Stream Open()
{
return _manifestResourceStream;
}
}
}
using System.Collections.Generic;
using System.IO;
namespace Portal.Common.EmbeddedResources
{
public static class EmbeddedResourceTypes
{
public static string GetContentType(string path)
{
return MimeTypes[Path.GetExtension(path)];
}
public static bool Contains(string extension)
{
return MimeTypes.ContainsKey(extension.ToLowerInvariant());
}
public static readonly Dictionary<string, string> MimeTypes = new Dictionary<string, string>
{
{".js", "text/javascript"},
{".css", "text/css"},
{".gif", "image/gif"},
{".png", "image/png"},
{".jpg", "image/jpeg"},
{".xml", "application/xml"},
{".txt", "text/plain"},
{".html", "text/html"}
};
}
}
using System;
using System.Collections;
using System.Net;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
namespace Portal.Common.EmbeddedResources
{
public class EmbeddedViewProvider : VirtualPathProvider
{
public override bool FileExists(string virtualPath)
{
return base.FileExists(virtualPath) || EmbeddedResourcesManager.IsEmbeddedView(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
if (base.FileExists(virtualPath))
return base.GetFile(virtualPath);
try
{
return EmbeddedResourcesManager.GetEmbeddedResourceFile(virtualPath);
}
catch
{
throw new HttpException((int)HttpStatusCode.NotFound, "Embedded resource not found.");
}
}
public override CacheDependency GetCacheDependency(string virtualPath,
IEnumerable virtualPathDependencies, DateTime utcStart)
{
return EmbeddedResourcesManager.IsEmbeddedResource(virtualPath)
? null
: base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
}
}
@saadahmedkhan
Copy link

Can you let me know how to use it? I tried your code snippet but it doesn't work.
I have scripts, cshtml and other embedded files in an assembly named MyAssembly.

So I tried following urls to see if it works:
/Content/MyAssembly.Folder.Web.Views.Home.Index.cshtml
/Scripts/MyAssembly.Folder.Web.Scripts/Jquery.js

@lismore
Copy link

lismore commented Nov 19, 2015

I got this to work by adding the following to my AreaRegistration file where i map by routes and removing it from the class shown above.


RouteTable.Routes.InsertRoute(
            "Content",
            "Content/{*virtualPath}",
            new { controller = "EmbeddedResources", action = "Index" },
            typeof(EmbeddedResourcesController).Namespace
        );

        RouteTable.Routes.InsertRoute(
            "Scripts",
            "Scripts/{*virtualPath}",
            new { controller = "EmbeddedResources", action = "Index" },
            typeof(EmbeddedResourcesController).Namespace
        );

        RouteTable.Routes.InsertRoute(
            "Templates",
            "Templates/{*virtualPath}",
            new { controller = "EmbeddedResources", action = "Index" },
            typeof(EmbeddedResourcesController).Namespace
        );

however I had to make slight changes,

InsertRoute changed to MapRoute and the line with typeof(EmbeddedResourcesController).Namespace

had to be changed to: new[] {typeof (EmbeddedResourcesController).Namespace}

 RouteTable.Routes.InsertRoute(
            "Content",
            "Content/{*virtualPath}",
            new { controller = "EmbeddedResources", action = "Index" },
            typeof(EmbeddedResourcesController).Namespace
        );

Mine looks like

context.MapRoute(
           "Content",
           "Content/{*virtualPath}",
           new { controller = "EmbeddedResources", action = "Index" },
           new[] {typeof (EmbeddedResourcesController).Namespace}
          );

Then I can access any files through the url:
http:/mysite.com/EmbeddedResources/index/?virtualPath=my.css

If you want to access other folders resources, just copy and change "Content/{_virtualPath}" to your other folder like "Scripts/{_virtualPath}".

Then use
http:/mysite.com/EmbeddedResources/index/?virtualPath=myscript.js

@herbrich
Copy link

It's possible to get aspx and masterpage files from a embeddet resource with this code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment