Today we’re going to see one common need for control developers and shared libraries, that is, the ability to store resources (JavaScript, CSS, image files …) inside an external DLL.
Embed Selected Resources
First thing is to embed the resources on our external library. Just copy the files you need (png, js, css … ) to the project and add them. I have created them inside a folder, as you can see in the picture.
Creating Route Handler
Because we have the embeded resources stored internally on our external library, we need several things:
- Custom route handler to correctly redirect requests to these files and serve them
- Reflection mechanism to extract these files from the assembly manifest to a stream
- Write stream to the current response stream, back to the browser
Fortunately, .NET makes all of this very easy for us.
public sealed class UiResourceRouteHandler : IRouteHandler
public sealed class UiResourceRouteHandler : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new EmbeddedResourceHttpHandler(requestContext.RouteData);
}
public class EmbeddedResourceHttpHandler : IHttpHandler
{
private RouteData _RouteData;
public EmbeddedResourceHttpHandler(RouteData routeData)
{
_RouteData = routeData;
}
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
string group = _RouteData.Values["group"].ToString();
string fileName = _RouteData.Values["file"].ToString();
string fileExtension = _RouteData.Values["extension"].ToString();
if (!Regex.IsMatch(fileExtension, ("js|cs|png")))
throw new InvalidOperationException("Request not valid");
string nameSpace = GetType().Assembly.GetName().Name;
string manifestResourceName = string.Format("{0}.{1}.{2}.{3}",
nameSpace, group, fileName, fileExtension);
using (Stream stream = GetType().Assembly.GetManifestResourceStream(manifestResourceName))
{
context.Response.Clear();
if (fileExtension == "js")
context.Response.ContentType = "text/javascript";
else if (fileExtension == "css")
context.Response.ContentType = "text/css";
else if (fileExtension == "png")
context.Response.ContentType = "image/png";
stream.CopyTo(context.Response.OutputStream);
}
}
}
}
What we’re doing here is to create our custom handler, that will handle the requests to these files.
Registering Our New Route Handler
The last step is to register this route handler on our MVC application, inside RegisterRoutes
method that is called from Application_Start
.
public static void RegisterRoutes(RouteCollection routes)
{
routes.Insert(0,
new Route("UiControls/{group}/{file}.{extension}",
new RouteValueDictionary(new { }),
new RouteValueDictionary(new { }),
new RouteValueDictionary(new { extension = "css|js|png" }),
new UiResourceRouteHandler()
));
}
Things To Keep In Mind
- As you can see in the code, the handler will accept requests as /UiControls/UiGrid/UiGrid.png. But you can find these per your needs.
- When using folders to store the resources, as in this case, the manifest name is
namespace.folder.filename.extension
, you can do a loop over all your embedded manifest resources using Assembly.GetManifestResourceNames
.
- The regular expression only validates against css, js or png. You can add more types per your convenience.
That’s all! Enjoy!
CodeProject