架构深渊

慢慢走进程序的深渊……关注领域驱动设计、测试驱动开发、设计模式、企业应用架构模式……积累技术细节,以设计架构为宗。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Embedding Resources in ASP.NET 2.0 Assemblies

Posted on 2009-04-26 17:39  chen eric  阅读(254)  评论(0编辑  收藏  举报
Unedited - Community Contributed
Abstract
With ASP.NET version 2.0, it has become a snap for server control authors to embed image and script resources into assemblies, making deployment clean and error-free. Mark Hines shows you how, and notes a few pitfalls of which to be aware.
by Mark Hines
One of the greatest difficulties when developing common web controls (either server or user controls) that we’ve come across in our development group is how to deal with client-side scripts and images.  In ASP.NET 1.1 we have recently started using an HttpModule and compiled resource files, but ASP.NET 2.0 makes it much easier to manage embedding resources in assemblies.

The Problem

During your development of robust, rich
-client web applications, you’ll quickly develop a set of controls that use JavaScript to provide your application’s users with a really pleasant experience.  Now, you have to figure out what to do with these controls.  Do you create user controls and cut and paste them between your web applications, or do you create custom server controls that compile nicely and are easy to share?  Once you tackle that decision, you have to figure out what you’re going to do with the JavaScript.  If you embed it in the user control, it has to travel over the wire every time the page is requested, which will negatively impact any low-bandwidth users of the web application.  If you make it a server control, then you have to create an installation script or somehow manage the distribution and location of the external files across all applications using the control.

The ASP.NET 
1.1 Solution

To avoid these issues 
in ASP.NET 1.1, you could create an HttpModule or HttpHandler that responded to your own key filename.  This HttpModule or HttpHandler would then return the appropriate resource that had been compiled into a specific resource assembly.  In this case, you had to manage the HttpModule or HttpHandler, make sure it was referenced correctly in the web.config, make sure that the compiled resource was available, and cross your fingers and hope for the best.  While this is a solution to the problem described above, it is still a lot of work.

The ASP.NET 
2.0 Solution

The 
new version of ASP.NET has integrated the 1.1 solution, and now we get to reap the rewards.  So, you can just embed your resources in the appropriate assemblies and reference them without having to worry about configuration or deployment issues.  The necessary process is described in the following sections.

Embedding the Resource

To make the file or image accessible from your server control’s assembly, simply add the file to your project, go to the Properties pane, and 
set the Build Action to Embedded Resource.  To expose the file to a web request, you need to add code like that shown in Listing 1 to your AssemblyInfo.cs file.  These entries expose the embedded resource so that the ClientScriptManager can both get to the file and know what kind of file it is.  

Listing 
1: AssemblyInfo.cs entries


[assembly: System.Web.UI.WebResource(
"myImage.gif""img/gif")]
[assembly: System.Web.UI.WebResource(
"myStylesheet.css""text/css")]
[assembly: System.Web.UI.WebResource(
"myJavascript.js""text/js")]
Namespace Note

The project’s 
default namespace (defined in the Application tab of the project's Properties page) will be added as a prefix to the filename of embedded resources.  In this case, I’ve set the default namespace to an empty string.  Otherwise, the tag’s first parameter would need to be DefaultNamespace.Filename.Extension instead of simply Filename.Extension.  (This was the biggest pitfall I encountered because it wasn’t obvious that the namespace would be added as a prefix, and so I was referencing the resources by their short names when I should have been using the long format.)

Accessing the Embedded Resource

To add the embedded resource to our ASP.NET page, we will be calling the ClientScriptManager’s GetWebResourceUrl method.  Its first parameter 
is the Type of the control’s class (which will eventually provide .NET with an assembly reference where the embedded resource is contained) and its second parameter is the name of the resource as specified in the AssemblyInfo.cs file.  For example, to load an image in an Image control, use the code in Listing 2.  To add a stylesheet to the Page header area, use the code in Listing 3.  To render a JavaScript include tag, use the code in Listing 4.

Listing 
2: Setting an image control’s source


Image theImage 
= new Image();
theImage.ImageUrl 
=
      Page.ClientScript.GetWebResourceUrl(
this.GetType(), "myImage.gif");
Listing 
3: Adding a stylesheet to the page header


string includeTemplate =
      
"<link rel='stylesheet' text='text/css' href='{0}' />";
string includeLocation =
      Page.ClientScript.GetWebResourceUrl(
this.GetType(), "myStylesheet _Links.css");
LiteralControl include 
=
      
new LiteralControl(String.Format(includeTemplate, includeLocation));
((HtmlControls.HtmlHead) Page.Header).Controls.Add(include);
Listing 
4: Rendering a javascript include


string scriptLocation =
      Page.ClientScript.GetWebResourceUrl(
this.GetType(), "MSDWUC_WindowStatus.js");
Page.ClientScript.RegisterClientScriptInclude(
"MSDWUC_WindowStatus.js", scriptLocation);
 
ClientScriptManager Quirks

One of the things I encountered when working with 
this technique was that most examples of server controls do their “thing” during the Render event.  So, I attempted to be a good corporate citizen and have my controls behave the same way and I found that I could not use RegisterClientScriptBlock at this point in the page life cycle.  RegisterStartupScript seemed to work fine in this scenario and IE 6.0 apparently tolerates rendering styles at this point and applying them to the page’s rendered contents, but I wasn’t happy with that.  So, I discovered that I had to make all calls to RegisterClientScriptBlock on or before the OnPreRender event for them to be added to the correct part of the page.

Conclusion

We’ve covered how you can embed resources 
in your server control projects and how to reference them in a web environment.  This should simplify your life from a deployment perspective, and should make your server controls tighter now that they can leverage static images and files, and do not require any installation other than deployment of the compiled assembly.