If you want to share your application resources(like css, javascript, images, etc) between different projects then embedded resource is a great choice. Embedded resource is also good for component/control writers because it allows component/control writers to distribute all the application resources with just a single assembly. A lot of vendors are already using this approach. It will great for component/control writers if they can leverage the ASP.NET bundling and minification for improving the performance. So, in this article we will show you how to write a very basic component(helper) which will use the ASP.NET bundling and minification feature on embedded javascript/css files.

 

About ASPHostPortal.com

ASPHostPortal.com is Microsoft No #1 Recommended Windows and ASP.NET Spotlight Hosting Partner in United States. Microsoft presents this award to ASPHostPortal.com for ability to support the latest Microsoft and ASP.NET technology, such as: WebMatrix, WebDeploy, Visual Studio 2012, ASP.NET 4.5, ASP.NET MVC 4.0, Silverlight 5 and Visual Studio Lightswitch. Click here for more information

First of all create a new Class Library project and install the Microsoft.AspNet.Mvc, WebActivator and Microsoft ASP.NET Web Optimization Framework 1.1.0-alpha1(make sure to include the -Pre parameter in Package Manager Console) nuget packages. Next, add a reference of System.Web assembly. Then, create your control/component/helper. For demonstration purpose, We will use this sample helper:

01.          public static class HtmlHelpers
02.          {

03.                          public static MvcHtmlString NewTextBox(this HtmlHelper html, string name)

04.                          {
05.                                          var js = Scripts.Render("~/Test/Embedded/Js").ToString();
06.                                          var css = Scripts.Render("~/Test/Embedded/Css").ToString();

07.                                          var textbox = html.TextBox(name).ToString();

08.                                          return MvcHtmlString.Create(textbox + js + css);

09.                          }
10.          }

 

In this helper, I am just using a textbox with a style and script bundle. Style bundle include 2 css files and script bundle include 2 js files. So, just create 2 css files(NewTextBox1.css and NewTextBox2.css) and 2 javascript files(NewTextBox1.js and NewTextBox2.js) and then mark these files as embedded resource. Next, add a AppStart.cs file and add the following lines inside this file:

01.          [assembly: WebActivator.PostApplicationStartMethod(typeof(AppStart), "Start")]
02.          namespace Test

03.          {

04.                          public static class AppStart

05.                          {

06.                                          public static void Start()

07.                                          {

08.                                                          ConfigureRoutes();

09.                                                          ConfigureBundles();

10.                                          }

11.                                          private static void ConfigureBundles()

12.                                          {

13.                                                          BundleTable.VirtualPathProvider = new
                                                             EmbeddedVirtualPathProvider(HostingEnvironment.VirtualPathProvider);

14.                                                          BundleTable.Bundles.Add(new ScriptBundle("~/Test/Embedded/Js")

15.                                                          .Include("~/Test/Embedded/NewTextBox1.js")

16.                                                          .Include("~/Test/Embedded/NewTextBox2.js")

17.                                                          );

18.                                                          BundleTable.Bundles.Add(new StyleBundle("~/Test/Embedded/Css")

19.                                                          .Include("~/Test/Embedded/NewTextBox1.css")

20.                                                          .Include("~/Test/Embedded/NewTextBox2.css")

21.                                                          );

22.                                          }

23.                                          private static void ConfigureRoutes()

24.                                          {

25.                                                          RouteTable.Routes.Insert(0,

26.                                                          new Route("Test/Embedded/{file}.{extension}",

27.                                                          new RouteValueDictionary(new { }),

28.                                                          new RouteValueDictionary(new { extension = "css|js" }),

29.                                                          new EmbeddedResourceRouteHandler()

30.                                                          ));

31.                                          }

32.                          }

33.          }

 

The above class using WebActivator's PostApplicationStartMethod, which allows your assembly to run some code after the Application_Start method of global.asax. The Start method simply register a custom virtual path provider and two bundles which are used in our NewText helper class. But ASP.NET optimization framework will only emit a bundle url when debug="false" or when BundleTable.EnableOptimizations = true. Therefore, we also need to handle the normal javascript and css requests. For this case, the above method has also register a specific route for handling embedded resource requests using EmbeddedResourceRouteHandler route handler. Here is the definition of this handler:

01.          public class EmbeddedResourceRouteHandler : IRouteHandler
02.          {

03.                          IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)

04.                          {

05.                                          return new EmbeddedResourceHttpHandler(requestContext.RouteData);

06.                          }

07.          }

08.          public class EmbeddedResourceHttpHandler : IHttpHandler

09.          {

10.                          private RouteData _routeData;

11.                          public EmbeddedResourceHttpHandler(RouteData routeData)

12.                          {

13.                                          _routeData = routeData;

14.                          }

15.                          public bool IsReusable

16.                          {

17.                                          get { return false; }

18.                          }

19.                          public void ProcessRequest(HttpContext context)

20.                          {

21.                                          var routeDataValues = _routeData.Values;

22.                                          var fileName = routeDataValues["file"].ToString();

23.                                          var fileExtension = routeDataValues["extension"].ToString();

24.                                          string nameSpace = typeof(EmbeddedResourceHttpHandler)

25.                                          .Assembly

26.                                          .GetName()

27.                                          .Name;// Mostly the default namespace and assembly name are same

28.                                          string manifestResourceName = string.Format("{0}.{1}.{2}", nameSpace, fileName, fileExtension);

29.                                          var stream =
                                             typeof(EmbeddedResourceHttpHandler).Assembly.GetManifestResourceStream(manifestResourceName);

30.                                          context.Response.Clear();

31.                                          context.Response.ContentType = "text/css";// default

32.                                          if (fileExtension == "js")

33.                                          context.Response.ContentType = "text/javascript";

34.                                          stream.CopyTo(context.Response.OutputStream);

35.                          }

36.          }

 

EmbeddedResourceRouteHandler returns EmbeddedResourceHttpHandler http handler which will be used to extract embedded resource file from the assembly and then write the file to the response body. Now, the only missing thing is EmbeddedVirtualPathProvider:

01.          public class EmbeddedVirtualPathProvider : VirtualPathProvider
02.          {

03.                          private VirtualPathProvider _previous;

04.                          public EmbeddedVirtualPathProvider(VirtualPathProvider previous)

05.                          {

06.                                          _previous = previous;

07.                          }

08.                          public override bool FileExists(string virtualPath)

09.                          {

10.                                          if (IsEmbeddedPath(virtualPath))

11.                                                          return true;

12.                                          else

13.                                                          return _previous.FileExists(virtualPath);

14.                          }

15.                          public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime
                             utcStart)

16.                          {

17.                                          if (IsEmbeddedPath(virtualPath))

18.                                          {

19.                                                          return null;

20.                                          }

21.                                          else

22.                                          {

23.                                                          return _previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);

24.                                          }

25.                          }

26.                          public override VirtualDirectory GetDirectory(string virtualDir)

27.                          {

28.                                          return _previous.GetDirectory(virtualDir);

29.                          }

30.                          public override bool DirectoryExists(string virtualDir)

31.                          {

32.                                          return _previous.DirectoryExists(virtualDir);

33.                          }

34.                          public override VirtualFile GetFile(string virtualPath)

35.                          {

36.                                          if (IsEmbeddedPath(virtualPath))

37.                                          {

38.                                                          string fileNameWithExtension = virtualPath.Substring(virtualPath.LastIndexOf("/") + 1);

39.                                                          string nameSpace = typeof(EmbeddedResourceHttpHandler)

40.                                                          .Assembly

41.                                                          .GetName()

42.                                                          .Name;// Mostly the default namespace and assembly name are same

43.                                                          string manifestResourceName = string.Format("{0}.{1}", nameSpace,
                                                             fileNameWithExtension);

44.                                                          var stream =
                                                             typeof(EmbeddedVirtualPathProvider).Assembly
                                                             .GetManifestResourceStream(manifestResourceName);

45.                                                          return new EmbeddedVirtualFile(virtualPath, stream);

46.                                          }

47.                                          else

48.                                                          return _previous.GetFile(virtualPath);

49.                          }

50.                          private bool IsEmbeddedPath(string path)

51.                          {

52.                                          return path.Contains("~/Test/Embedded");

53.                          }

54.          }

55.

56.          public class EmbeddedVirtualFile : VirtualFile

57.          {

58.                          private Stream _stream;

59.                          public EmbeddedVirtualFile(string virtualPath, Stream stream)

60.                          : base(virtualPath)

61.                          {

62.                                          _stream = stream;

63.                          }

64.                          public override Stream Open()

65.                          {

66.                                          return _stream;

67.                          }

68.          }

EmbeddedVirtualPathProvider class is self explanatory. It simply maps a bundling url(used above) and return the embedded request as stream. Note, this class will be invoked by ASP.NET optimization framework during bundling and minifying process. Now, just build your component/control/helper assembly. Then, create a sample ASP.NET(MVC) application and then use this component/control/helper in your page. For example, like,

[email protected]using Test.Helpers
[email protected]("New")