Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Another look at Dynamic Content Rendering focusing on Images and JScript

0.00/5 (No votes)
5 Dec 2004 1  
Information and examples about rendering dynamic content using ASP.NET.

Sample Image

Introduction

There have been several articles written on the subject of dynamic image rendering. This article discusses a more generic approach to implementing this concept. Some of the techniques discussed in this article are based on the concepts of similar articles that focused on a specific area of dynamic content rendering such as with graphs, image text, etc..

Namely, the following articles were a vital asset in writing this article:

This article attempts to generalize the concept of dynamic rendering to allow the programmer to implement their own dynamic content. This can form the basis of creating custom ASP.NET web controls that can serve up a variety of different types of dynamic content. We will look at ways to render dynamic content that is created on the fly or embedded in an assembly DLL. This helps eliminate the need for separate files such as JavaScript or images that normally have to be separately included with the web control assembly DLL.

A few advantages of dynamic rendering are:

  • The ability to have all static files embedded into an assembly DLL for easier distribution.
  • Hiding script source code.
  • Being able to create dynamic images at the server without having to save an image file to disk.

Background

As I read articles and sample code on dynamic image rendering, I decided to take what I had learned and try to improve upon it. As I dug into dynamic image rendering, I soon realized that other contents could be dynamically rendered as well, such as scripts, style sheets, etc.. I decided to implement generic dynamic content classes based on the dynamic image content articles that I had read. I also elected to incorporate the image drawing into user controlled drawing rather than specific classes for specific types of drawing. The result is the source portrayed in this article.

Using the code

The primary class that is used for serving up the dynamic content is the CustomHttpModule class. This is a module handler class that is used to intercept aspx URL requests. This class is registered in the Web.Config file under <System.web> section as follows:

<httpModules>
   <add name="CustomModule" type="Custom.Web.CustomHttpModule, CustomWeb"/>
</httpModules>

Note that the CustomWeb.dll produced by the CustomWeb project must be accessible to the ASP.NET page that implements it. This usually involves copying the produced CustomWeb.DLL file into the bin directory of the ASP.NET page.

In order to see how to use the CustomHttpModule class, I have supplied two classes that implement it. One is the CustomImage class, and the other is the EmbeddedJScript class. Note that the EmbeddedJScript class implements the more generic EmbeddedWebContent class which encapsulates the CustomHttpModule class, whereas the CustomImage class directly implements the CustomHttpModule class.

Let's first examine the CustomImage class. This class is a Custom Control derived from the Image control. It can be dropped onto a Web Form using Visual Studio .NET.

The first area of interest is in the Render() method. It is in this method that the CustomImage control calls an event handler called OnImageRender. This event handler is implemented by the control object's parent page to draw into the GDI+ Graphics object that is provided in the EventArgs. This dynamically drawn image will then be dynamically streamed to the web page using the CustomHttpModule class.

protected override void Render(HtmlTextWriter writer)
{
   if (Site != null && Site.DesignMode)
   {
      Label DesignerLabel = new Label();

      DesignerLabel.Width = this.Width;
      DesignerLabel.Height = this.Height;
      DesignerLabel.Text = "CUSTOM IMAGE";
      DesignerLabel.BorderStyle = this.BorderStyle;
      DesignerLabel.BorderWidth = this.BorderWidth;
      DesignerLabel.BorderColor = this.BorderColor;
      DesignerLabel.CssClass = this.CssClass;
      DesignerLabel.RenderControl(writer);
   }
   else
   {
      String SaveUrl = null;

      if (OnImageRender != null)
      {
         Bitmap Bmp = new Bitmap((int) this.Width.Value,(int) this.Height.Value);
         Graphics Graph = Graphics.FromImage(Bmp);
         MemoryStream MemStream = new MemoryStream();

         Graph.FillRectangle(new SolidBrush(this.BackColor),0,0,Bmp.Width,Bmp.Height);
         OnImageRender(this,new RenderImageEventArgs(Graph));

         Bmp.Save(MemStream,RenderImageFormat);

         ImageData.Data = MemStream.ToArray();

         SaveUrl = ImageUrl;

         ImageUrl = CustomHttpModule.RegisterHandler(Page.Application,
                                     ID,
                                     new HttpModuleHandler(ModuleHandler),
                                     this.ImageData);

         Graph.Dispose();
         Bmp.Dispose();
         MemStream.Close();
      }
      
      base.Render(writer);
      
      if (SaveUrl != null)
      {
         ImageUrl = SaveUrl;
      }
   }

The CustomHttpModule is implemented in two different areas of the CustomImage class. Here is where the static call to CustomHttpModule.RegisterHandler() is made.

ImageUrl = CustomHttpModule.RegisterHandler(Page.Application,
                                            ID,
                                            new HttpModuleHandler(ModuleHandler),
                                            this.ImageData);

The above call basically registers the control as a custom image handler control. The return value of CustomHttpModule.RegisterHandler() is a URL that is to be used to signal the CustomHttpModule class to invoke the HttpModuleHandler delegate (ModuleHandler) to be called when the dynamic content is requested by the web page. The last argument to RegisterHandler is optional data that will be passed to the delegate when it is called. In this case, it is the image raw data bytes that are drawn by the code in the event handler.

When the Image control is rendered, it will use the URL returned from RegisterHandler as the <Img> tag SRC attribute. When the browser goes to locate the image, the module handler takes over. It locates the appropriate registered caller and then calls the ModuleHandler delegate. The delegate then streams out the image content to the requesting URL.

static private void ModuleHandler(CustomHttpModule Module, 
                                    CustomHttpModuleEventData e)
{
   HttpContext context = e.HttpApp.Context;

   CustomImage.ImageDataType ImgData = e.ModuleObj as ImageDataType;
   
   if (ImgData != null)
   {
      MemoryStream MemStream = new MemoryStream();
   
      MemStream.Write(ImgData.Data,0,ImgData.Data.Length);
      MemStream.WriteTo(context.Response.OutputStream);
      MemStream.Close();
      
      context.Response.Cache.SetNoServerCaching();
      context.Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
      context.Response.Cache.SetNoStore();
      context.Response.Cache.SetExpires(new DateTime(1900,01,01,00,00,00,00));     
         
      context.ClearError();
      context.Response.ContentType = "image/" + ImgData.RenderImageFormat.ToString();
      context.Response.StatusCode = 200;
      context.Response.Flush();
   }
}

The EmbeddedJScript class uses a similar technique; however, it incorporates the EmbeddedWebContent class which provides a generic ModuleHandler delegate function that streams out the data. The main reason for using the EmbeddedWebContent class is to allow the streaming of resource embedded data as dynamic content. Thus, you can create a JavaScript .JS file, and add it to the VS.NET project as an embedded resource. Simply set the JavaScript .JS file's Build Action to Embedded Resource in Visual Studio. This is accessed under the file properties (right click on JS file and select Properties).

When a JScript file is embedded, it is part of the assembly DLL and does not need to be included as a separate file when distributing the Web Control. The JScript source is loaded from the resource, and directly streamed to the web page as dynamic content using the HttpModuleHandler class as shown for the CustomImage class. Note that a similar approach can also be used for resource embedded images, style sheets, etc..

In conclusion, the primary goal here was to show the uses of various forms of dynamic content and illustrate a central control class (HttpModuleHandler) to handle the process with some sense of structure. Who knows, maybe others will be able to build upon this code as I had from articles that I read. I hope this helps.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here