Saturday, July 19, 2008

Creating Custom Controls in ASP .Net

Creating Custom Controls in ASP .Net

In this article I have simply demonstrated 2 code examples for creating Custom Web Controls.

Why Custom Controls?
To cater through the real world scenarios that may not be supplemented by inbuilt .Net controls, the need for Custom Control arises. Also their are several other reasons for creating custom control like reusability, centralized management over the control, ease of usage etc.

How to approach the requirement for creating Custom Controls?
If any of the inbuilt .Net control meets your requirement than you should always use these controls. If not than ask yourself a question

Would any of the existing control help me?

If yes than
Inherit from the existing control and add the new features to it and extend it further.
If No than
You need to build the control from scratch. In this case inherit from WebControl class.

 

How to create Custom Controls?

Their are two ways in which you can create a custom control.
1) You can inherit from existing .net web control to extend its features further. OR
2) You can directly inherit from WebControl class to create a web control from scratch.

Depending upon the approach you choose their will be several properties and methods for you to override. All of them cannot be explained here so I am explaining some important among them that I have used in my code samples.

AddAttributesToRender - Adds HTML or Style attributes for any of your HtmlTextWriterTag. You can also use HtmlTextWriter's "AddAttribute" , "AddStyleAttribute" methods to achieve the same functionality. Make sure that you add this attributes before using "RenderBeginTag" method.

RenderContents - Outputs HTML content of Server Control to HtmlTextWriter object. So override this method to manage the HTML that your custom control renders to the browser.

TagKey - WebControl renders a span TAG by default on the cient browser. But to render any specific TAG you need to override this method.

Inheriting from the existing control
This example depicts the creation of a new web control named "myButton" that is derived from the Button class. It has all the features that a normal button control has. But for a twist I have added a simple feature that prompts for a message before submitting the page back to the server. I have added a new property called "AlertMessage" to quench this requirement.

[sourcecode language='csharp']

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace myControlLib
{
public class myButton : Button
{
public myButton() { }
private string _AlertMessage = "Are you sure to process this request!";
public string AlertMessage
{
set { _AlertMessage = value; }
get { return _AlertMessage; }
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "return confirm('" + _AlertMessage + "')"); base.AddAttributesToRender(writer);
}
}
}

[/sourcecode]

Registering the control on the web page

[sourcecode language='html']

<%@ Register Assembly="myControlLib" Namespace="myControlLib" TagPrefix="myUcl" %>

[/sourcecode]

Using the control

[sourcecode language='html']





[/sourcecode]





Inheriting from the WebControl class
This example depicts the creation of a new web control named "myImage" that is directly derived from the WebControl class. This control renders a Picture, Name of the Picture and Description of the Picture. Description of the Picture is displayed when the mouse is moved over the picture.
For this I have created 3 additional properties for this.

ImageUrl - The url of the image to be displayed

ImageName - The name of the image.

ImageDescription - The description for the image.

[sourcecode language='csharp']

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace myControlLib
{
public class myImage : WebControl
{
public myImage() { }

private string _ImageUrl = "";
public string ImageUrl
{
get { return _ImageUrl; }
set { _ImageUrl = value; }
}
private string _ImageName = "";
public string ImageName
{
get { return _ImageName; }
set { _ImageName = value; }
}
private string _ImageDescription = "";
public string ImageDescription
{
get { return _ImageDescription; }
set { _ImageDescription = value; }
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.AddAttribute("onmousemove", "javascript:document.getElementById('" + this.UniqueID + "_divDescription').style.display='';");
writer.AddAttribute("onmouseout", "javascript:document.getElementById('" + this.UniqueID + "_divDescription').style.display='none';");
writer.AddAttribute(HtmlTextWriterAttribute.Src, _ImageUrl);
writer.RenderBeginTag(HtmlTextWriterTag.Img);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("Name : " + _ImageName);
writer.RenderEndTag();
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.UniqueID + "_divDescription");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("Description : " + _ImageDescription);
writer.RenderEndTag();
base.RenderContents(writer);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
}

[/sourcecode]

Registering the control on the web page

[sourcecode language='html']

<%@ Register Assembly="myControlLib" Namespace="myControlLib" TagPrefix="myUcl" %>

[/sourcecode]

Using the control

[sourcecode language='html']

ImageDescription="My Image Description........" />

[/sourcecode]

Note: The above examples are the simplest controls that one can create. Remember that you can create more complex controls using the same approach. Choosing the best control that can serve the purpose of the requirement is our JOB and so make this decision very carefully.

How to make better appearance of your custom control in Visual Studio.

How to add custom control in Visual Studio Toolbox.

How to make better appearance of your custom control in Visual Studio.

How to make better appearance of your custom control in Visual Studio.

In the previous article Creating Custom Controls in ASP .Net I have covered the technical approach for creating custom control.

Here I will explain how to improve the appearance of your custom control
Their are two ways in which this job can be done.
1) By decorating your control and control properties with some design time attributes.
2) By making your own control designer.

Decorating your control and control properties with some design time attributes:
.Net provides various design time attributes that can be applied on control or on property to take control over the design aspects of the control. You can do lots of things with this attributes let’s say:

One can choose the default event or default property for their controls.

One can assign the description to the property that is displayed in the last section of the property window when the property is selected.

One can categorize their additional properties in property window. This would be helpful when the property window is switched to "Categorized" mode.Etc...

Their are lots of such attributes with which you can playaround.
Some of them I have described below.

Attributes you can apply to your control class:

DefaultEvent - This attribute specifies the default event for your control. So when a control is double clicked, the event handler is automatically created for this event.

DefaultProperty - This attribute specifies the default property for your control. So when you open the property window for your control, this property will be focused by default.

ToolboxData - This attribute allows you to specify any tags that are added to the markup of your control whenever it is added to the page.

ToolboxItem - This attribute allows you to block the control from appearing in the toolbox.

TagPrefix - This attribute allows you to manage the html markup for the registration tag of your control.

Attributes you can apply to your control property:

Bindable - Displays a data binding dialog box for the property.

Browsable - This attribute allows you to block the property from appearing in Property window.

Category - This attribute allows you to group properties in a particular stencil. The property will appear under this category in the property window.

DefaultValue - This attribute allows you to give default value for the property.

Description - This attribute allows you to specify the description for the property. This description is displayed below in the property window when the property is selected.

Editor - This attribute allows you to specify the custom editor window for the property. Examples of custom editor are ImageUrlEditor, MailFileEditor,  MdbDataFileEditor,  UrlEditor etc...

EditorBrowsable - This attribute allow you to block a property from being display in the Intellisense.


Example Source Code
private string _ImageUrl = "";
[Category("My Custom Properties")]
[Description("Specify path of the image to be displayed.")]
[Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[DefaultValue("")]
[UrlProperty]
[Bindable(true)]
public string ImageUrl
{
    get { return _ImageUrl; }
    set { _ImageUrl = value; }
}
Making your own control designer:
Control Designer help to take control over the appearance of the control when they are drag dropped in the page. One can also create a smart tag that can help user to easily configure some properties of your control. Example: Some of the .Net controls like FormView, DetailsView, GridView have smart tags that help users to easily configure some important properties like Datasource, Templates etc. I will try to cover How to make smart tag controller in my next article.

Example Source Code
using System;

using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;


[assembly: TagPrefix("myControlLib", "myUcl")]
namespace myControlLib
{
public class myImageDesigner : ControlDesigner
{
myImage objmyImage;
public override string GetDesignTimeHtml()
{
if (objmyImage.ImageUrl.Trim().Length == 0)
{
return "Please set Image URL Property!";
}
else
{
return base.GetDesignTimeHtml();
}
}
public override void Initialize(IComponent component)
{
objmyImage = (myImage)component;
base.Initialize(component);
return;
}
}
[Designer("myControlLib.myImageDesigner,myControlLib")]
[ToolboxBitmap(typeof(myImage), "myImageLogo.bmp")]
[ToolboxData(@"<{0}:myImage runat=""server"" ImageUrl="" "" ImageName="" "" ImageDescription="" "" />")]
public class myImage : WebControl
{
public myImage() { }
private string _ImageUrl = "";
[Category("My Custom Properties")]
[Description("Specify path of the image to be displayed.")]
[Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[DefaultValue("")]
[UrlProperty]
[Bindable(true)]
public string ImageUrl
{
get { return _ImageUrl; }
set { _ImageUrl = value; }
}
private string _ImageName = "";
[Category("My Custom Properties")]
[Description("Specify name of the image to be displayed.")]
public string ImageName
{
get { return _ImageName; }
set { _ImageName = value; }
}
private string _ImageDescription = "";
[Category("My Custom Properties")]
[Description("Specify description of the image to be displayed.")]
public string ImageDescription
{
get { return _ImageDescription; }
set { _ImageDescription = value; }
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.AddAttribute("onmousemove", "javascript:document.getElementById('" + this.UniqueID + "_divDescription').style.display='';");
writer.AddAttribute("onmouseout", "javascript:document.getElementById('" + this.UniqueID + "_divDescription').style.display='none';");
writer.AddAttribute(HtmlTextWriterAttribute.Src, _ImageUrl);
writer.RenderBeginTag(HtmlTextWriterTag.Img);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("Name : " + _ImageName);
writer.RenderEndTag();
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.UniqueID + "_divDescription");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("Description : " + _ImageDescription);
writer.RenderEndTag();
base.RenderContents(writer);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
}


Note: Do not forget to add a .bmp image named ("myImageLogo.bmp") to this project. This image would be displayed as the icon for your control in the toolbox. You can also create .bmp file using inbuilt .Net design tool. Just click on the added .bmp file to open this editor.
Your bmp should be 16x16 pixels in size.


To add custom control to your toolbox refere
How to add custom control in Visual Studio Toolbox.

How to add custom control in Visual Studio Toolbox.

How to add custom control in Visual Studio Toolbox.

In my previous article Creating Custom Controls in ASP .Net  we have seen the technical approach for creating custom control and  in How to make better appearance of your custom control in Visual Studio we have gone through the design aspects of custom control.

Now in this article I will explain how to add your custom control to your Toolbox.


Making Custom Control Class Library Project.

Step 1 - Create a class library project named myControlLib.

Step 2 - Add the following code to a new class named myImage. To download sample code files click here. After downloading add “myImage.cs” and “myImageLogo.bmp” file to your “myControlLib” project. Change the “Build Action” property of “myImageLogo.bmp” to Embedded Resource.

Step 3 - Compile the project.

Note: Above given steps are specific to the code sample that I have created. If you want to rename any of the file or change any other aspects than make sure that you also change the design time attributes of your control.

Example: [Designer ("myControlLib.myImageDesigner,myControlLib")] uses the namespace “myControlLib” that is directly related to the name of the class library project you make.


Adding custom control to toolbox.

Step 1 - Switch over to the web project in which you want to use the control.

Step 2 - In toolbox add your own tab or click on general tab.

Step 3 - Right click in the selected tab area and click Chose Items.



Step 4 - This will open Choose Toolbox Item screen. Click on Browse button and specify the path of dll you created in your myControlLib project.





Step 5 - Click Ok and you’re done. Your Custom control will be added to the toolbox as shown below.



Saturday, July 5, 2008

Application Caching in .Net 2.0

Application Caching in .Net 2.0

What is Application Caching?
Application Caching is a technique in .Net 2.0 for caching different type of objects for faster access. As the name itself depicts, the Cache Object can be used from the entire application. A single cache object lies for the entire application and so can be used between various different user sessions and requests.

How Application Caching works and How to use it?
The main motive for Application Caching is to store cached Objects in memory for faster access. Expensive operation to obtain and persists data or information can lead to application failure or sluggishness at time of heavy traffic. Also the amount of time and resources involved in such operations may not be satisfactionary. So to improve upon the performance and the scalability of your application you can cache the expensive data for faster access.

You can use either Cache.Add() or Cache.Insert() methods for caching your data. The only difference between the two is, Cache.Add() method returns the object which you want to cache.
So let’s say if you want to use the object and cache it as well. You can do so in a single line of code with the help of Cache.Add().

Cache.Insert() methods has 4 different types of overloaded methods while Cache.Add() has only one.



Different Parameters used for the above methods:

Key
It is the name for the cached object by which it will be accessed. You can also use the key to remove the cached object from the memory. Following code will remove the cached object named “customerList” from the memory.

Cache.Remove("customerList");


Object to be cached
It is the object that you want to cache. This object will be stored in the memory for faster retrieval.


Dependency
It is the CacheDependency object that can be a file or cache key. So if the file or cache key is changed than the object in the cached will be invalidated and removed from the cache. This can be used to maintain the freshness of the data. This is an optional parameter. You can set it to null. Incase of multiple dependency conditions you can use AggregateCacheDependency object instead of CacheDependency.


Absolute Expiration DateIt is the time at which the object will be removed from the cache. To remove the object from cache after 10 minutes you can set this parameter to DateTime.Now.AddMinutes(10) as shown in the below code.

Cache.Insert("customerList", objDataSet, new CacheDependency(Server.MapPath("~/App_Data/customerList.xml")),DateTime.Now.AddMinutes(10), Cache.NoSlidingExpiration,CacheItemPriority.Normal, null);


If you do not want the object to expire forcefully after some time than you may set this parameter to Cache.NoAbsoluteExpiration as shown in below code.
Cache.Insert("customerList", objDataSet,new CacheDependency(Server.MapPath("~/App_Data/customerList.xml")),Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,CacheItemPriority.Normal, null);

Time Span
It is the time span after which the object will be removed from the cache if it was not accessed. So lets say if you want to remove the object from cache if it has not been accessed since last 10 minutes than you can use the below code.

Cache.Insert("customerList", objDataSet,new CacheDependency(Server.MapPath("~/App_Data/customerList.xml")),Cache.NoAbsoluteExpiration,DateTime.Now.AddMinutes(10),CacheItemPriority.Normal, null);


If you do not want the object to expire forcefully after some time it was last accessed than you may set this parameter to use Cache.NoSlidingExpiration  as shown in below code.
Cache.Insert("customerList", objDataSet,new CacheDependency(Server.MapPath("~/App_Data/customerList.xml")),Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,CacheItemPriority.Normal, null);

Note: If you are using this sliding expiration time parameter than Absolute Expiration Date parameter must be Cache.NoAbsoluteExpiration

Priority
It is the priority at which the objects will be purged from the memory incase if the memory runs low. Lower priority objects will be removed first.

Callback Method
It is the event handler that will run when the object is removed from the cache. If you do not want to use this parameter than you can set this to null.

To download Application caching code sample Click Here.
Note: To introduce sophisticated caching layer in your application you can always use Microsoft’s Enterprise Library - Caching Application Block.