Using Embedded Resources

Sep 23, 2011 at 7:40 PM

Since I've shut down my blog (for update 149) and have no where "official" to post, I'll post it here in case anyone wants to do the same. If you're using RazorGenerator to precompile your controllers and views (which I imagine you are) you might have a need to also store supporting files in your DLL - CSS, JavaScript, etc. If so, the following will get you what you want:

This is an almost copy/paste from a working project, which uses Areas in the Razor project. So, keep that in mind (especially for my content folder).

Create a controller that will serve your embedded resources. I created a separate action per expected type, obviously you could make it more modular and use the route to determine the type. My controller is called ResourcesController. Since I want to use the same folder structure, I want to ensure that {area}/content/{files} points to my resource controller, you could just use the resource as part of the route and not bother with this. But it also helps me catch references I'm making to content that I don;t have resources embedded for...

 

MapRoute(
                "area-resources", // Route name
                "area51/content/{action}/{file}", // URL with parameters
                new { area = "area51", controller = "resources", action = "Index", file = UrlParameter.Optional }
            );

 

The Css action (for CSS files) will call a more generic function to get the actual resource. The output caching is to avoid repeated streaming for the resource. The v allows me to add a version file to avoid the cache. Here you could make the CSS part of the route, I chose not to.

        [OutputCache(Duration=90)]
        public ActionResult Css(string file, string v)
        {
            return GetResource("css", file);
        }

This function, which returns the action result, sets the content type and streams the resource into the response

        private ActionResult GetResource(string type, string file)
        {
            if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(file))
            {
                return NotFound();
            }

            string contentType;

            switch (type.ToUpperInvariant())
            {
                case "JS":
                    contentType = "text/javascript";
                    break;
                case "CSS":
                    contentType = "text/css";
                    break;
                default:
                    return NotFound();
            }

            try
            {
                using (var stream = GetResourceStream(type, file))
                {
                    stream.CopyTo(Response.OutputStream);
                }

                return Content(null, contentType);
            }
            catch { /* log */ }

            return NotFound();
        }
Lastly, let's look into the Assembly to do what we want. Like I mentioned, I left the files in the expected location using the normal /Content/ MVC folder structure (save the js files which I moved into a JS folder). These files have to be right-clicked and changed to EmbeddedResource; if you do not do this they will not be included in the DLL.
Every period must break down into a folder and then the name.
        private Stream GetResourceStream(string type, string file)
        {
            return typeof(ResourcesController).Assembly.GetManifestResourceStream("SuperDuperPrecompiledMvc3WebsiteApp.Areas.Area51.Content." + type + "." + file);
        }

And if you call <link href="/Area51/Content/css/site.css" /> you will pull the resource out of the DLL. 

Using this you could drop a projects DLL into another BIN and have a completely working module: controller, view, css, images, js, etc.

Hope that helps.


 

 

Coordinator
Sep 23, 2011 at 7:44 PM

Thanks for sharing! We have http://razorgenerator.codeplex.com/workitem/12 tracking that we wanted to support static resources, but haven't not really looked at implementing it yet.

Jun 18, 2014 at 3:00 PM
Any ideas or support for bundles (System.Web.Optimizations)?