Sunday, April 17, 2011

Cookieless Session State Asp.net

Cookieless Session State Asp.net

ASP.NET Session State by default uses a cookie to store session ID. Session ID is a unique string, used to recognize individual visitor between visits. But, if client's web browser doesn't support cookies or visitor has disabled cookies in web browser's settings, ASP.NET can't store session id on client's machine. In this case, new session will be created for every request. This behavior is useless because we can't remember information for certain visitor between two requests. We can say that, by default, sessions can't work if browser doesn't support cookies.

ASP.NET sessions without cookies (cookieless session)

ASP.NET supports sessions without cookies, known as cookieless sessions. As an alternative, ASP.NET can embed session id inside of page URL. On this way, all page links will contain session id string. When visitor clicks on some of these links, ASP.NET will read session id from page URL, so we don't need cookies support to have functional sessions.

To enable cookieless sessions, add cookieless="true", or cookieless="UseUri" (both options have the same meaning) inside sessionState tag in web.config file, like this:

<sessionState cookieless="true" />

SessionState element in web.config file is located inside <configuration>, <system.web> elements. Default behavior for sessions with cookies could be set with cookieless="false". Since it is already specified in machine.config file and inherited to all ASP.NET applications on server, you don't need any configuration change if you use cookie sessions.

As a result of cookieless="true", session id will be embedded in all page URLs. The drawback is that you'll end up with ugly URLs, which are not so good for SEO (search engine optimization) and visitor definitely will not remember it. Here is an example URL of website which uses ASP.NET cookieless sessions:

http://mappoint.msn.com/(22b5c4zyybphaw2mt3hjni2n)/Home.aspx

Bolded part represents session id, which is used to recognize a visitor. Possible problem is that URL will be different for every visitor and every visit, because they will have different session identities. If user just copy URL and paste it somewhere while recommending your website, he or she will send its session id too. This could be potential security risk if session is not expired yet. Also, search engines will consider any of these links as separate page. This will divide page ranking and decrease position of your page in search engine results.

Cookieless session and absolute URLs problem

There is a problem with absolute URLs if Cookieless session is used (e.g. URLs which starts with http://, https:// etc.), and with URLs which starts with slash character "/". So, you can't use links like /products/Product1.aspx anymore. If you place absolute link on your page, ASP.NET will not embed session id in it. If visitor clicks on link without current session id, he or she will get new session with new session id. Previous session and its data will be lost. With every next click on absolute links, visitor will get new session each time. On this way session becomes useless, because it cant remember user's data between two requests. So, easiest solution is to simply forget links with absolute URLs on cookieless website.

Other option is to embed session id into absolute URLs by using Response.ApplyAppPathModifier method. This could be useful, for example if we read and display a list of absolute URLs from database, or perform redirection from http:// to https:// etc. Here is a simple example of modification of absolute URL. Resulting URL will contain embedded current session id:

<a id="Hyperlink1" runat="server" href='<% =Response.ApplyAppPathModifier("http://mysite.com/Some-Absolute-Link.aspx"); %>' >Absolute link with cookieless session example</a>

In the other hand, absolute links are pretty useful for static files like images, .js, .css, .zip files etc.

Cookieless session and links to images, JavaScript files, CSS files etc.

When cookieless="true" is used, every relative link will be rewritten to embed session id. That includes links to files like images, JavaScript files, CSS files, PDF files, ZIP files for download etc.

In most cases, you don't need session id embedded inside of these links. Embedded session id inside of links to images and other similar files could cause cache problems.

For every new visit, visitor will get different session id. Thus, same image will always have different URL. Different URL means different image for web browser. If you check "Temporary Internet Files" in Internet Explorer or some other browser, notice that same image is saved many times. Actually, it is saved again each time you visit cookieless website. This could be a problem, especially on high traffic websites. In this case, cookieless session could increase bandwidth costs and slow down page loading, since same files must be downloaded multiple times and stored separately.

As a simple solution, you can use absolute links for images, JavaScript, CSS, PDF and similar files and avoid session id issue on this way.

ASP.NET cookieless options

ASP.NET offers six different options for cookieless attribute.

UseCookies - This is default option, set in machine.config file. ASP.NET website will use cookies to store session id, even if client doesn't support them. In case that client refuse to save cookie, session data will be lost and new session is created for each request. Thus, clients without cookie support can't use web application.

false - has same meaning as UseCookies.

UseUri - Website will embed session id inside of all relative URLs. ASP.NET Session State will never use cookies, even if client browser supports them. Sessions will work on each client, but could be less secure than session with cookie.

true - same as UseUri.

UseDeviceProfile - ASP.NET will check client if it's capable to support cookies. If client can support cookies, cookie will be used to store session id. Notice that this method just checks browser's features, but it doesn't consider an option that user is manually disabled cookies in browser. If web browser application supports cookies but user is disabled them, session will not work.

AutoDetect - ASP.NET will automatically detect if client supports cookies or not. If client supports cookies, website will use a cookie as storage for session id. If client doesn't support cookies, ASP.NET will embed session id in page URL. This looks as good compromise, although could cause problems with search engines.

Cookieless sessions and RegenerateExpiredSessionId parameter

To enable cookieless session, it is enough to set appropriate value for cookieless parameter. But, sessionState element contains RegenerateExpiredSessionId parameter which is important for security reasons. RegenerateExpiredSessionId could have two values:

True - Expired session ids can't be used again. If visitor comes to website using old session id, it will be replaced with new session id

False - If visitor uses old session id to visit website (e.g. through a bookmark, search engines, social networks etc.), website will create new session collection but session id will stay same.

For security reasons, especially with cookieless sessions, is better to always use RegenerateExpiredSessionId="True". On this way expired session id will not be used for new session, to avoid that different visitors have same session id.

SEO (Search Engine Optimization) and cookieless sessions

Search engines like Google could provide a lot of visits to website. Everything begins when Googlebot, or some others' search bot application, make requests to website to load its content and save it to their database for further analyze. Saved data are then provided for search on search engine, and possibly listed in search results.

Important issue when working with cookieless sessions is duplicate content. Let's suppose that you have one page with unique content. Each time when search bot reads that page, ASP.NET will assign different session id to it. Different session id means different URLs on page. So, instead to see your page as one page with original content, search bot could consider that you have a lot of different pages with same content. That is not good for search engine optimization, because your page will divide its ranking and be shown on the bottom of search results where no one clicks.

The solution for this could be to use cookieless="UseDeviceProfile" and then add new browser profile for each search bot inside <browsers> element in web.config. For example, if user agent string contains word "Googlebot", browser profile will tell ASP.NET that Googlebot supports cookies. On this way, session id will not use cookies when Google bot comes. Of course, we know that Googlebot doesn't support cookies, so this sounds more like hack than recommended nice looking solution. But, it will work and you can add new browser profile for any problematic search bot. Notice that UseDeviceProfile only looks on browser capabilities, thus on this way you are losing visitors with capable browsers, but who manually disabled cookies.

One more potential SEO problem with cookieless sessions is HTTP 302 redirect. When, search bot makes requests to some domain which uses cookieless sessions, ASP.NET will redirect visitor to other link with session id embedded. During this process, ASP.NET will use HTTP 302 Found message. Code 302 could have two meanings: 303 or 307. "303 See Other" means that correct content is found on different URL. 307 response represents temporary redirect. So, correct status code should be 307, temporary redirect, because in that case main link without session id is considered as the correct one. Unfortunately, bad architecture of ASP.NET cookieless session redirects using vague 302 message which is more often perceived as 303, than as 307. The consequence is that search bots usually save URL with session id embedded and even worse, see different pages each time when crawl through website.

Fortunately, main search engines learned how to deal with session variables, so now the problem is not so big as before. Still, clean URLs with keywords only will always rank better in search results, thus I can say that cookieless sessions generally are not good for SEO.

Security issues and cookieless session

Main security problem when working with sessions is a possibility that malicious user will find out others' session id. If two users share same session id, they share same session variables too and website is considering them as one visitor. This could be a security risk if session is used for any private or sensitive data, or to allow access to restricted areas of web site. When cookies are used, session id can be protected using SSL and by marking a cookie as secure. But, in case of cookieless session, session id is part of URL and is much more vulnerable.

Attacker could use network monitoring tool to see requested URLs. Because session id is part of URL, if you know requested URL you know session id too. Also, if malicious user get access to recent web server's logs, it is possible to read recent requested URLs and visit website with still active session.

On more problem is e-mail, social network or instant messenger communication. Pretty innocent question, as "Can you send me link to that page please?" could be huge security risk. Visitor could copy link from address bar and send it to someone through an email, some instant messenger, like AIM, Windows Live Messenger, Skype etc., or through social networks like Facebook. When other person use received link to open website, he or she will share same session as sender, and possibly see private data or have access to restricted area of web site.

Search bots generally don't accept cookies. That means that bots will get cookieless session and see URLs with embedded session id. If these URLs appear in search results, they will still contain that session id. So, imagine that first visitor comes to your website from Google search. Website will read session id from given URL. Then, after few minutes, second visitor comes using the same link. Now these two, and every next visitor that comes from search engine will share same session id, and same session variables and all of them will be considered as single visitor! This could make sessions useless and also be potential security risk. To solve this problem, always set RegenerateExpiredSessionId="True" when working with cookieless session. When RegenerateExpiredSessionId="True" and some visitor comes through an URL that contains expired session id, ASP.NET will assign new unique session id.

Since session id is so exposed when cookieless sessions are used, to increase security you can check some other information from visitor, like information from Request.Browser properties. Checking of IP address is also an option, but notice that some Internet service providers change IP address during the single visit. In cases like this, often you still can check first two numbers of IP address because they usually stay the same.

Notice that visitors usually disable cookies for security reasons. In case of cookieless sesions, ironically, visitor become much more insecure than if session with cookie is used.

Menu and TreeView control when cookieless session is used

Menu and TreeView controls are standard controls used for site navigation. Keep in mind that these controls will not automatically add session ids. For example, very common scenario is to bind Menu or TreeView control to SiteMapDataSource control. It looks logical that resulting links on page will have session id embedded. But, Menu or TreeView control will display just simple absolute links without ids.

To resolve this, we need to use Response.ApplyAppPathModifier method again. In this case, we'll use MenuItemDataBound or TreeNodeDataBound events respectively:

[ C# ]

// Cookieless sessions with Menu control
protected void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)
{
// Embeds session id
   e.Item.NavigateUrl = Response.ApplyAppPathModifier(e.Item.NavigateUrl);
}
// Cookieless sessions with TreeView control
protected void TreeView1_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
// Embeds session id
   e.Node.NavigateUrl = Response.ApplyAppPathModifier(e.Node.NavigateUrl);
}

[ VB.NET ]

' Cookieless sessions with Menu control
Protected Sub Menu1_MenuItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemDataBound
' Embeds session id
   e.Item.NavigateUrl = Response.ApplyAppPathModifier(e.Item.NavigateUrl)
End Sub
' Cookieless sessions with TreeView control
Protected Sub TreeView1_TreeNodeDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles TreeView1.TreeNodeDataBound
' Embeds session id
   e.Node.NavigateUrl = Response.ApplyAppPathModifier(e.Node.NavigateUrl)
End Sub

Now, all links in Menu or TreeView controls will have session ids embedded.

Session.IsCookieless property

You can check in run time if session is cookieless sessions or not. This is useful if you are creating an application that could be included as module on others' websites (e.g. forum, user support application etc.). In this case, you can't change settings in main web.config file, but you can check in code if session requires cookies but visitor is disabled them, and if needed redirect and inform visitor so he or she knows why application doesn't work. Example of using Session.IsCookieless property could look like this:

[ C# ]

if (Session.IsCookieless)
{
// Web application uses cookieless session
}
else
{
// Web application uses cookies to work with sessions
// If needed, inform visitor that cookies are required
}

[ VB.NET ]

If (Session.IsCookieless) Then
' Web application uses cookieless session
Else
' Web application uses cookies to work with sessions
' If needed, inform visitor that cookies are required
End If

Conclusion

HTTP is stateless protocol, which means that it doesn't provide a way to save information of same visitor between two requests. ASP.NET offers Session State as a method to resolve this problem. To find out more about other possible methods, check ASP.NET Session State Alternatives tutorial. In general, to save visitor's state when using stateless protocol, you can place id inside of page's HTML or as part of URL. In HTML, there are two options: <head> or <body> tags. Cookies are part of <head> tag, but this is automatically managed by web browser.

ASP.NET ViewState stores information inside of <body> tag, as hidden field. This works nice, but the problem is that this method can only work with POST, and can't work if GET method is used.

Third, and last option is to store information inside of page URL, and that is how cookieless session work. Be aware that some mobile devices can't read format of cookieless URLs with parentheses, and cookieless sessions could cause problems with some URL rewriting modules.

If you have pure HTML pages, there is a problem to share POST data between HTML form and ASP.NET web form. When cookieless ASP.NET form is posted, it contains information about session id too. But, if you make POST on HTML form, it will not contain session id and new session will be created. In that case, data of previous session will be lost. The solution could be to embed session id to link in form's action attribute. You can do that using Response.ApplyAppPathModifier method like in previous examples.

Limitations

The principal limitation of this feature is the limited amount of data that can be stored in the URL. This feature is not targeted at common browsers such as IE, since these do support cookies and do not require this feature. The browsers that do not support cookies are the ones found on mobile devices (such as phones), and these browsers typically severely limit the size of the URL they support. So, be careful when you use this feature—try to make sure that the cookieless string generated by your application is small.

A second limitation on the size comes on the Windows 2003 platform. A (configurable) setting on the Windows Networking layer requires that each segment of the URL be less than 256 chars in length. Since the entire cookieless string goes into 1 segment, it must be less than 256 chars. (A segment of the URL is the portion of the URL between two forward slashes ('/')).

Wednesday, April 13, 2011

Caching in Asp.net

 

Caching

This article, you will learn about concepts, advantages, types of caching and about implementation of caching in ASP.NET applications. The code also serves as an example of using inline coding, creating user controls, trace mechanism, etc.


What is Caching?

 

Caching is a technique of persisting the data in memory for immediate access to requesting program calls. Many in the developer community consider caching as one of the features available to improve performance of Web applications.


Why Caching?

Consider a page that has list of Employee name, contact numbers and mail-Ids of existing employees of a company on an intranet accessible by all employees. This is very useful information that is available throughout the company and could also be one of the most accessed pages. The functionality of adding, updating or deleting is usually less intensive compared to more transaction-based systems like Purchase ordering, Voucher creation etc. Now in a normal scenario the process of querying database for each request is not cost-effective in terms of server resources, hence is lot better to cache or persist the data to avoid this costly loss of resources.

The .NET Advantage

 ASP.NET provides the flexibility in terms of caching at different levels.


1. Page Level Output Caching


This is at the page level and one of the easiest means for caching pages. This requires one to specify Duration of cache and Attribute of caching.

Syntax: <%@ OutputCache Duration="60" VaryByParam="none" %> 





The above syntax specifies that the page be cached for duration of 60 seconds and the value "none" for VaryByParam* attribute makes sure that there is a single cached page available for this duration specified.

* VaryByParam can take various "key" parameter names in query string. Also there are other attributes like VaryByHeader, VaryByCustom etc. Please refer to MSDN for more on this.





2. Fragment Caching





Even though this definition refers to caching portion/s of page, it is actually caching a user control that can be used in a base web form page. In theory, if you have used include files in the traditional ASP model then this caching model is like caching these include files separately. In ASP.NET more often this is done through User Controls. Initially even though one feels a bit misleading, this is a significant technique that can be used especially when implementing "n" instances of the controls in various *.aspx pages. We can use the same syntax that we declared for the page level caching as shown above, but the power of fragment caching comes from the attribute "VaryByControl". Using this attribute one can cache a user control based on the properties exposed.






Syntax: <%@ OutputCache Duration="60" VaryByControl="DepartmentId" %>







The above syntax when declared within an *.ascx file ensures that the control is cached for 60 seconds and the number of representations of cached control is dependant on the property "DepartmentId" declared in the control.

Add the following into an *.ascx file. Please note the use of tag "Control" and the cache declaration.






<%@ Control Language="C#"%> 



<%@ outputcache duration="60" varybycontrol="DepartMentId" %> 



<script runat="server">
   1:  
   2: private int _Departmentid=0; 
   3: public int DepartMentId 
   4: { 
   5: get{return _Departmentid;} 
   6: set{_Departmentid =value;} 
   7: } 
   8: //Load event of control 
   9: void Page_Load(Object sender, EventArgs e) 
  10: { 
  11: lblText.Text = "Time is " + DateTime.Now.ToString() + " for Department id = " 
  12: + _Departmentid + "\n"; 
  13: } 
</script>



<asp:Label id="lblText" runat="server"></asp:Label> 




Add the following to an *.aspx file. Please note the way "Register" tag is used; the declaration of control using syntax <[TagPrefix]:[TagName]>; Usage of property " DepartMentId". Open the page in two browsers and closely watch the Base form timing and the User control timing. Also note that the following page results in two copies or representation of user control in the cache.






<%@ Page Language="C#" Trace="true" %> 



<%@ Register TagPrefix="CacheSample" TagName="Text" Src="CachingControl.ascx" %> 



<script runat=server>
   1:  
   2: void Page_Load(Object sender, EventArgs e) 
   3: { 
   4: this.lbltime.Text ="Base form time is " + DateTime.Now.ToString() + "\n"; 
   5: } 
</script>



<html> 



<head> 



</head> 



<body> 



<form runat="server" ID="Form2"> 



<table> 



<tbody> 



<tr> 



<td> 



<asp:Label id="lbltime" runat="server"></asp:Label> 



</td> 



</tr> 



<tr> 



<td> 



<CACHESAMPLE:TEXT id="instance1" runat="Server" DepartMentId="0"> 



</CACHESAMPLE:TEXT> 



</td> 



</tr> 



<tr> 



<td> 



<CACHESAMPLE:TEXT id="instance2" runat="Server" DepartMentId="1"> 



</CACHESAMPLE:TEXT> 



</td> 



</tr> 



</tbody> 



</table> 



</form> 



</body> 



</html> 





3. Application Level Caching






With Page level Output caching one cannot cache objects between pages within an application. Fragment caching is great in that sense but has limitations by using user controls as means to do. We can use the Cache object programmatically to take advantage of caching objects and share the same between pages. Further the availability of different overloaded methods gives a greater flexibility for our Cache policy like Timespan, Absolute expiration etc. But one of the biggest takes is the CacheDependancy. This means that one can create a cache and associate with it a dependency that is either another cache key or a file.

In almost all Web applications there could be numerous master tables that act as lookups to application specific tables. For e.g. if you take up adding a Employee, usually one has master tables like "tblQualification" to get list of qualifications, "tblLocations" to get list of locations etc. These tables* are usually set during the initial application configuration phase and could be modified once a month or even less than that. Hence it makes sense for us to use them in our Cache rather than making calls to database on each request. But then what Cache Policy do we adopt?


We cannot hold these objects in Cache for entire application instance, because if anybody changes data in these tables one has to also refresh the cache. It is here that CacheDependancy can be used.


* Even though these tables are less frequently used for updates, they are extensively used in our select statements through out the applications.


Find below the snippet that uses CacheDependancy. Here what I have done is to provide a list view of existing employees. You need to create a Database in Sql Server, setup some data before you can continue. The schema scripts are enclosed in the article.


Add database connection value in Web.Config and change the value as per your setup.






<appSettings> 



<add key="conn" value="Data Source=vishnu;trusted_connection=yes;Initial Catalog=Users"/> 



</appSettings> 




First I get the dataset into which I fill the user list. But before this I check for the cache initially if it exists I directly cast it to a dataset, if not create a cache again.

daUsers.Fill(dsUsers,"tblUsers");


I create the cache with "Users" as key using Cache.Insert* and link this with a file "Master.xml". This "Master.xml" is a XML file that contains Master data of "tblQualifications" and "tbllocations". I have used "Server.MapPath" to get the physical path of the file on the server. The CacheDependancy instance will make sure that any change in this dependency file means that you need to recreate your cache key definition. This is a great feature to use since I can recreate my cache only when required instead of caching the data at the page level
.







* For other overloaded parameters refer MSDN.Also note how we could use trace within to add my own statements.



 



Cache.Insert("Users",dsUsers,new System.Web.Caching.CacheDependency(Server.MapPath("Master.xml")) , DateTime.Now.AddSeconds(45),TimeSpan.Zero); 



HttpContext.Current.Trace.Write("from Database.."); 



 



<%@ Page Language="c#" Trace="true" %> 



<%@ import Namespace="System" %> 



<%@ import Namespace="System.Data" %> 



<%@ import Namespace="System.Data.SqlClient" %> 



<%@ import Namespace="System.Configuration" %> 



<%@ import Namespace="System.Web" %> 



<%@ import Namespace="System.Collections" %> 



<%@ import Namespace="System.IO" %> 



<script runat="server">
   1:  
   2: void Page_Load(Object sender, EventArgs e) 
   3: { 
   4: DataSet dsUsers; 
   5: try 
   6: { 
   7: if(Cache["Users"]==null) 
   8: { 
   9: SqlConnection cn; 
  10: dsUsers = new DataSet("new"); 
  11: cn = new SqlConnection(ConfigurationSettings.AppSettings.Get("conn")); 
  12: SqlDataAdapter daUsers; 
  13: daUsers = new SqlDataAdapter("Select * from tblUsers",cn); 
  14: cn.Open(); 
  15: daUsers.Fill(dsUsers,"tblUsers"); 
  16: //Update the cache object 
  17: Cache.Insert("Users",dsUsers, new System.Web.Caching.CacheDependency( 
  18: Server.MapPath("Master.xml")), DateTime.Now.AddSeconds(45),TimeSpan.Zero); 
  19: HttpContext.Current.Trace.Write(DateTime.Now.AddSeconds(45).ToString() + " 
  20: is expiry time.."); 
  21: cn.Close(); 
  22: cn.Dispose(); 
  23: HttpContext.Current.Trace.Write("from Database.."); 
  24: lblChange.Text ="From the database...."; 
  25: } 
  26: else 
  27: { 
  28: HttpContext.Current.Trace.Write("From cache.."); 
  29: lblChange.Text ="From the cache...."; 
  30: dsUsers= (DataSet) Cache["Users"]; 
  31: } 
  32: dlUsers.DataSource =dsUsers; 
  33: dlUsers.DataMember = dsUsers.Tables[0].TableName ; 
  34: //lblChange.Text += Server.MapPath("Master.xml"); 
  35: this.DataBind(); 
  36: } 
  37: catch(Exception ex) 
  38: { 
  39: lblChange.Text = ex.Message; 
  40: } 
  41: } 
</script>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > 



<html> 



<head> 



<title>Cache Dependency Tester</title> 



<meta content="Microsoft Visual Studio 7.0" name="GENERATOR" /> 



<meta content="C#" name="CODE_LANGUAGE" /> 



<meta content="JavaScript" name="vs_defaultClientScript" /> 



<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema" /> 



</head> 



<body ms_positioning="GridLayout"> 



<form id="Form1" method="post" runat="server"> 



<asp:DataList id="dlUsers" style="Z-INDEX: 101; LEFT: 44px; POSITION: absolute; TOP: 104px" runat="server" Height="148px" Width="343px" BorderWidth="1px" GridLines="Horizontal" CellPadding="4" BackColor="White" ForeColor="Black" BorderStyle="None" BorderColor="#CCCCCC"> 



<SelectedItemStyle font-bold="True" forecolor="White" backcolor="#CC3333"></SelectedItemStyle> 



<FooterStyle forecolor="Black" backcolor="#CCCC99"></FooterStyle> 



<HeaderStyle font-bold="True" forecolor="White" backcolor="#333333"></HeaderStyle> 



<ItemTemplate> 



<table> 



<tr> 



<td> 



<%
   1: #DataBinder.Eval(Container.DataItem,"UserId")
%></td>



<td> 



<%
   1: #DataBinder.Eval(Container.DataItem,"FirstName")
%></td>



<td> 



<%
   1: #DataBinder.Eval(Container.DataItem,"LastName")
%></td>



</tr> 



</table> 



</ItemTemplate> 



</asp:DataList> 



<asp:Label id="lblChange" style="Z-INDEX: 102; LEFT: 46px; POSITION: absolute; TOP: 63px" runat="server" Height="28px" Width="295px"></asp:Label> 



<asp:Button id="btnMaster" style="Z-INDEX: 103; LEFT: 50px; POSITION: absolute; TOP: 293px" onclick="btnMaster_Click" runat="server" Text="Refresh Master"></asp:Button> 



</form> 



</body> 



</html> 





We created the page that initiates and uses the Cache. For testing purpose we need another page that will overwrite this "Master.xml" on click of a button for which the code snippet is as follows. This ideally should be our master maintenance page that adds/updates Master records in database and overwrites the XML. But to make it easy I have just written an overwriting sample.





<%@ Page Language="C#" Trace="true"%> 



<%@ import Namespace="System" %> 



<%@ import Namespace="System.Data" %> 



<%@ import Namespace="System.Data.SqlClient" %> 



<script runat="server">
   1:  
   2: void btnMaster_Click(Object sender, EventArgs e) 
   3: { 
   4: //Call save function 
   5: this.Save(); 
   6: } 
   7: void Save() 
   8: { 
   9: try 
  10: { 
  11: SqlConnection cn; 
  12: DataSet dsUsers = new DataSet("Users"); 
  13: //I have used this to get the Connectionstring from the 
  14: //Configuration file. 
  15: cn = new SqlConnection(ConfigurationSettings.AppSettings.Get("conn")); 
  16: SqlDataAdapter daQualification; 
  17: SqlDataAdapter daLocations; 
  18: daQualification = new SqlDataAdapter("Select * from tblqualifications",cn); 
  19: daLocations = new SqlDataAdapter("Select * from tblLocations",cn); 
  20: cn.Open(); 
  21: daQualification.Fill(dsUsers,"tblqualifications"); 
  22: daLocations.Fill(dsUsers,"tblLocations"); 
  23: HttpContext.Current.Trace.Write("Masters data up.."); 
  24: //Overwrite the XML file. Also please read MSDN on the overloaded parameters for WriteXml 
  25: dsUsers.WriteXml(HttpContext.Current.Server.MapPath 
  26: "Master.xml"),XmlWriteMode.WriteSchema); 
  27: cn.Close(); 
  28: cn.Dispose(); 
  29:  
  30: Technorati Tags: Asp.net,Caching,C#
  31: } 
  32: catch(Exception ex) 
  33: { 
  34: throw new Exception(ex.Message); 
  35: } 
  36: } 
</script>



<html> 



<head> 



</head> 



<body> 



<form runat="server" ID="Form1"> 



<span> 



<table> 



<tbody> 



<tr> 



<td> 



<label id="lblRefresh" runat="server"> 



Rewrite the XML File by clicking the buttonbelow.</label> 



</td> 



</tr> 



<tr align="middle"> 



<td> 



<asp:Button id="btnMaster" onclick="btnMaster_Click" runat="server" 



Text="Write XML"></asp:Button> 



</td> 



</tr> 



</tbody> 



</table> 



</span> 



</form> 



</body> 



</html> 




Now once you have created the above pages i.e. one that implements caching and other that overwrites the dependency file, create two instance of browser and open the cache implementation page and note for trace, label text; open the other instance of browser with the page which overwrites the XML. Note the former, the first time it fetches data from the database and the subsequent request will be from cache till your expiration time of 45 seconds is reached or anyone overwrites or changes the "Master.xml" file. Also give a look on Timespan parameter since you have a concept of Sliding expiration that can also be implemented. Keep refreshing the first page and you will see that trace indicates the cached page retrieval. Click the overwrite XML button on the latter page that would overwrite the XML and again refresh the former page to note that the data is retrieved from database. Though in this example I have not shown any direct relation between the cached data and the dependency file (like get values from dependency file and merge with cached object etc) in terms of integrated usage, this could very easily be designed and implemented. Dependency caching is a powerful technique that .NET supports and should be utilized wherever applicable.

PDF Arabic watermark using MVC and iTextSharp

PDF full page Arabic watermark using MVC and iTextSharp Download :  Source Code Most of the time we have requirement to  gen...