Florence Blogspot about asp.net tutorials and web design and web development

Tuesday, February 5, 2008

Master Pages in ASP.Net 2.0

Introduction

One of the new features of ASP.Net 2.0 is Master Pages. Master Pages enables us to apply the same page layout to multiple pages in a Web Application. A page that uses a master page is known as the content page.

Using Master Pages we can create a consistent look and feel for our websites. Pages in a web application have the standard elements such as logos, menus, copyright notices, etc. that are repeated on each and every page. And usually a web-site has a single layout design that each page corresponds to. Using master pages, we can place all these elements and define the layout and design in a master page. And when we base a content page on this master page, then all of the content pages will automatically include all of the standard elements and will define whatever layout you defined in the master page.

In this article, I'll spin through a small sample application to help you in understanding the advantages of master pages and how can work with them. I'll also explore some of the advanced features of Master Pages, such as modifying header element from the content page, so that if each content page needs to display a different Title Header, you can easily have it done. I will also take a look at loading the master page at run-time, and use of Nested Master pages.
Prerequisites

This tutorial assumes that you own a copy of Visual Studio 2005 or Visual Web Developer Express. It also assumes that you are familiar with ASP.Net 2.0 basics.
Creating the Website

If you have an existing web site, you can skip this section. Otherwise, you can create a new web site and page by following these steps.

To create a file system Web site:
- Open Visual Studio 2005.
- On the File menu, open New and click on Web Site.

The New Web Site dialog box appears.
- Under Visual Studio installed templates, click ASP.NET Web Site.
- In the Location box, enter the name of the folder where you want to keep the pages of your Web site.

For example, type the folder name C:\WebSites\mySite.
- In the Language list, click Visual Basic (or the language you prefer to work with).
- Click OK.

Visual Web Developer creates the folder and a new page named Default.aspx.
Creating a Simple Master Page
Right-click in the solution explorer and select Add New Item. Select Master Page from the template and provide a name for the page. In this example I am using myMaster.master (where .master is the extension of the file). Click Add.
This will add the .master file to the project. Which is our master page.

A Master Page can contain the same Web controls, User controls, HTML content, and scripts that can be added to a standard ASP.NET page. There are three important differences between a Master Page and a normal ASP.NET page.

First, unlike a normal ASP.NET page, the name of a Master Page must end with the special extension .master. This extension marks the page as a Master Page. Furthermore, an ASP.NET application is configured so that you cannot request pages with the .master extension.
Second, a Master Page includes a <%@ Master %> directive instead of the normal <%@ Page %> directive. The <%@ Master %> directive supports many of the same attributes as the <%@ Page %> directive. For example, you can specify the programming language of the page with the directive <%@ Master Language="vb" %>.

The final difference between a Master Page and a normal ASP.NET page is that a Master Page can contain zero or more ContentPlaceHolder controls. A ContentPlaceHolder control can be used only within a Master Page. This control marks an area of a Master Page that can be overridden by a particular content page.

The HTML code for this is:
<>














ForeColor="WhiteSmoke" Text="Welcome to the Master/Content Tutorial">

Text="Writer: M.Salman Khalid.">





Microsoft

MSDN

Channel 9

Code Project





In the above HTML code, the ContentPlaceHolder control is what identifies the area where the content place data will come. With Master/Content pages, you can have multiple ContentPlaceHolder controls in the Master Page.
Creating a Content Page
Right-click the project in the solution explorer and select Add New Item. Select Web Page from the template and check Select Master Page. Click on Add. This will open the Select Master Page dialog box, listing all the master pages defined in the project. Select the master page myMaster.master and click OK.
The HTML code for the new content page is:
<%@ Page Language="VB" MasterPageFile="~/myMaster.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" title="Untitled Page" %>



We've looked at how one can create a single Master Page and base a content page on the Master Page.
Furthermore, if you have the need, you can even nest multiple Master Pages. For example, you can create one Master Page for the entire Web site and then nest Master Pages below the site Master Page for individual sections.
Visual Studio/Visual Web Developer does not provide designer support for doing this. So, if you want to nest Master Pages, you'll need to stick to either source code view or build your pages using Notepad.
For example, following could be used for a Site Master Page. This Master Page contains the opening and closing HTML and Form tags and a single ContentPlaceHolder control.
<%@ Master %>
<.html>
<.head>
<.title>Site Master
<./head>
<.body bgcolor="LightGreen">

Site Master Page


id="SiteContentPlaceHolder"
runat="server" />



And the following could be the nested master page. This Master Page overrides the content in the Site Master Page. Notice that the <%@ Master %> directive refers to the SiteMaster.master Master Page.
<%@ Master MasterPageFile="~/SiteMaster.master" %>
ContentPlaceHolderID="SiteContentPlaceHolder"
runat="server">









Section Master Page



id="LeftColumn"
Runat="Server" />

id="RightColumn"
Runat="Server" />


Finally, the content is based on the Section Master Page. Notice that this page overrides the two ContentPlaceHolder controls contained in the Section Master Page.
<%@ Page MasterPageFile="~/SectionMaster.master" %>
ContentPlaceHolderId="LeftColumn"
Runat="Server">
This content appears in the left column

ContentPlaceHolderId="RightColumn"
Runat="Server">
This content appears in the right column


Configuring Master Pages
There is an alternative to associating a content page with a Master Page by using the <%@ Page %> directive. One can associate a Master Page with a content page within the Web application's configuration file. Using the configuration file makes it easier to maintain large Web sites, since they can change the Master Page associated with many content pages in a single location.
You set the Master Page within the element of a configuration file. (This element appears in the section of a configuration file.) For example, the following element sets the default Master Page to "myMaster.master":

Two major points to be aware of... The first is that if you want to use the Web.Config file to set the Master Pages, then you should not include the MasterPageFile attribute in the content pages. This is because setting a Master Page within a content page takes precedence over any Master Page set in the configuration file.
Second, the application can contain more than one Web.Config file located in different subfolders that set different Master Pages. In other words, one can override the Master Page set in a Web.Config file within a subfolder by creating a new Web.Config file. This is a really useful and important technique.
Overriding Master Page Properties
One issue that can be encountered almost immediately when working with Master Pages is the issue of how to override such properties as the page title and meta tags of a Master Page in individual content pages. It is common to want to display unique titles for each content page, even when the individual content pages are based on a shared Master Page.
There are multiple ways of overriding the content contained in a Master Page within a particular content page. I'll explore the most common two methods...
If you simply want to change the page title rendered by a Master Page from within a content page, then you can take advantage of the <%@ Page %> directive's Title attribute. This attribute only takes effect when the Master Page uses a server-side HtmlHead control.
For example, the Master Page Code below contains a server-side HtmlHead control.
<%@ Master %>
<.html>
<.head id="Head1" runat="server">
<.title>Master Title

<.body>

id="ContentPlaceHolder1"
runat="server" />



Notice that the <.head> tag includes a runat="server" attribute. This attribute transforms the <.head> tag into a server-side HtmlHead control.
The content page below overrides the page title. Notice that the <%@ Page %> directive at the top of this page has a value for its Title attribute. When the page is rendered, the text "Content Page Title" is displayed as the page title.
<%@ Page MasterPageFile="~/TitleMaster.master" Title="Content Page Title" %>
ContentPlaceHolderID="ContentPlaceHolder1"
Runat="Server">
Here is some content

If you need to override other attributes of an HTML header, such as the meta tags or style tags, then you can reference the HtmlHead element directly from a content page. The HtmlHead control implements the IPageHeader interface, which includes the following properties:
LinkedStyleSheets - The external style sheets linked to the HTML page.
Metadata - The collection of Metadata tags.
StyleSheet- Represents the styles applied to the HTML page.
Title- The title of the HTML page.
Any of these properties can be easily modified within a content page.
Dynamically loading Master Pages
In the end, I'll take a look at an advanced application of Master Pages, that is to dynamically load different Master Pages at run-time.
There are a couple of circumstances in which dynamically loading Master Pages is useful. First, you might need to co-brand your Web site with one or more partner Web sites. When someone links to your Web site from a partner Web site, you might want to automatically load up a Master Page that matches the look and feel of the partner Web site.
Another situation in which you might want to dynamically load Master Pages is when you want the users of your application to be able to pick a page layout. You can provide your users with a set of standard Master Pages. Users of your application can then select their favorite page layout by selecting their favorite Master Page.
You can dynamically load a Master Page by assigning a value to the MasterPageFile property of the Page object. The value assigned to this property should be a relative path to a valid Master Page file.
There is one important restriction that you must be aware of when using the MasterPageFile property. You can only assign a value to this property before or during the Page PreInit event. The PreInit is the earliest event during the page execution lifecycle. If you attempt to assign a value to this property during a later event, such as the Page Load event, then you'll receive an exception. This restriction makes sense, since different Master Pages will result in different sets of controls being loaded into the page.
To define a Master Page at run-time, simply add the handler for the PreInit even and supply the master page...

And all things must come to an end...
The main emphasis in this article was on ASP.Net 2.0 Master Pages. There is no question that Master Pages are my favorite new feature of ASP.Net 2.0. I hope you found this article interesting and informative. I am open for suggestions and remarks, both negative and positive.

Encryption and Decryption of a COOKIE

Tracking Visitors with ASP.NET, showed how to use cookies to keep track of site visitors across sessions. I also discussed privacy issues concerning the use of cookie data, particularly if you are storing sensitive information about your visitors/users. It is always a good idea to publish privacy statements to inform your users about how their data is being used and stored on your Web site.

Cookies can provide a real convenience to both visitors and programmers of a Web-based application. However, cookies are problematic from a security point of view for two reasons. First, unless your site uses SSL, cookie data is passed in the clear in the header of both the HTTP request and response. That means anyone who is clever enough to sniff packets on a particular port of a particular IP address can read cookie data as plain as day. The second problem is that cookie data is stored in nice little unrestricted cookie files in a browser's cache directory. This means that anyone that has access to your hard drive can see and open your cookies. Figure #1 shows an example of the contents of a cookie file.

So when your 16 year old finds this "convenient" data and forges off to rack up thousands of dollars in charges on www.HottiesBareAll.com, it will suddenly become clear why cookie security is important.

If you have never seen the voluminous quantity of cookie data on your machine, try the following. Open Internet Explorer, select Tools and then Internet Options from the menu. From the Internet Options dialog click the Settings button. Then on the Settings dialog click View Files. An Explorer window will display all the cached data your browser has kindly filled your hard drive with. Sort the list alphabetically, then scroll down to the Cs. (C is for "Cookie" :)) On my machine, there are currently 1,850 cookie files.

So, here is some advice - don't store sensitive data about users in cookies. If you must, then you have a responsibility to protect that data through encryption.

In previous versions of ASP, you would have been forced to purchase third party components to handle this encryption, or, if you are a genius, you could have ventured off and created your own components. However, most of us resorted to simple techniques that shift the ASCII values of each character in a string, like Rot13. Unfortunately, these techniques are more than obvious to people that are clever enough to sniff packets in the first place.

Fortunately, we no longer have to implement our own feeble security algorithms since the .NET Framework provides us with a slew of encryption classes in the System.Security.Cryptography namespace. Take a look for yourself.

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemsecuritycryptography.asp?frame=true

Overview of Cryptography in .NET

First, let's just acknowledge that encryption is really complicated. Frankly, it's supposed to be complicated because that is what makes it secure. And, by the way, I want to state here that I am in no way an encryption expert. There are probably only a handful of people that fully understand the intricacies of the math involved, and half of them probably wrote the cryptography classes for the .NET Framework.

Fortunately, we don't have to understand the intricacies to take advantage of encryption because the .NET Framework gives us a simple way to access the power of the best and most secure algorithms.
Before we begin encrypting our cookie data, we should have a little discussion about the cryptography classes and which ones are appropriate for securing our cookies.

What Is Encryption Exactly?

In the simplest terms, encryption is the process of taking a target string of characters (bytes, more specifically) and converting it into another string of characters so that by examination, the original characters cannot be deciphered. This process is performed with a second string of characters known as a "key". In technical terms, this key is mathematically "mashed" into the original string over many complex and compounded iterations. In addition, sometimes another string of characters, known as an "initialization vector", is "mangled" into the target string before the key is mashed. This helps to prevent obvious patterns in the target string from being revealed by mashing alone. Of course, the mashing and mangling is not permanent. If the key and the initialization vector remain intact, then the algorithms can use them in reverse to unmangle and unmash the original data.

The effectiveness or "strength" of the encryption is determined by the size of the key used. The larger the key, the stronger the encryption. Typical key sizes are 64 bit (8 bytes), 128 bit (16 bytes), 192 bit (24 bytes), 256 bit (32 bytes) and 512 bit (64 bytes). The only way to crack most of these algorithms is by sheer brute force, where an attacker creates a program to test every single possible key combination. For even the 64-bit option, there are 72,057,594,037,927,936 possible combinations (2^56 - 8 bits are held for parity). So basically, unless you have a very powerful computer, you are going to be waiting awhile to crack even the weakest key.

Cryptography Patterns

There are two basic approaches for handling data encryption: symmetric (or private key) and asymmetric (or public key). In symmetric cryptography techniques, both sides of the data exchange (the encryptor and decryptor) must have access to a single secret private key.

In asymmetric encryption, one side (the decryptor) requests a public key from the encryptor. The encryptor creates a public key and sends it to the requestor. Then the encryptor uses the public key to create a second unique private key that it holds on to. This new private key is used to encrypt the message sent to the decryptor, who then uses the public key to decrypt the message. If encrypted data must be sent in the other direction then the other side will create a new public key and sends it along in a reciprocal fashion. This asymmetric technique is used by SSL to secure HTTP transmissions.

For our cookie encryption purposes, we will use the symmetric approach since both the encryption and decryption will take place in the same application on the server; therefore, we only need one private key that we will keep secure in the compiled code of our cryptographic utility class.

Cryptographic Service Providers

The .NET Framework provides 4 cryptographic algorithms that extend from the base SymmetricAlgorithm class:

* System.Security.Cryptography.DES (Data Encryption Standard)

* System.Security.Cryptography.TripleDES (Triple Data Encryption Standard)

* System.Security.Cryptography.RC2

* System.Security.Cryptography.Rijndael

In our example project, we will demonstrate both the DES and TripleDES algorithms. Each of these algorithms is accessed through wrapper classes categorized as Cryptographic Service Providers (CSP).
All CSP objects have two important methods: CreateEncryptor & CreateDecryptor. Each method has two parameters for our private key and initialization vector. Each method returns an algorithm object with the ICryptoTransform interface. This object will be used by the CryptoStream object(which we will discuss in a minute.)

For more a in-depth discussion of Cryptography in .NET, visit the following link in the MSDN Library:

http://msdn.microsoft.com/library/en-us/cpguide/html/cpconcryptographyoverview.asp?frame=true

Key Size Considerations

DES is one of the weaker encryption methods because its key size is limited to 64 bits. However, for our cookie purposes, this level of encryption is probably sufficient. TripleDES, which, believe it or not, performs the encryption three times, also has a larger key size. The length of the key must be either 128 or 192 bits - two to three times larger. TripleDES is significantly more secure.
Deciding which algorithm to use should not only be based on your desire for stronger encryption but also by the size of the cookies you require. You will notice in our example application that encrypted data will grow in size. And of course, the larger the key, the larger the resulting data. This is an important consideration since cookie data is restricted to 4kb.

An alternative is to store data that you only need to persist temporarily in hidden input tags. Of course, this is exactly what ViewState does in ASP.NET. In addition, ViewState offers some built-in encryption. The ViewState of a Web form, by default, uses hash functions from some of the asymmetric algorithms to garble the content. This is not fully secure. However, you can configure your ASP.NET application or individual pages to use more secure encryption on the ViewState - specifying the same TripleDES algorithm we discussed earlier. Here is an article on MSDN on how to do just that:

http://msdn.microsoft.com/library/en-us/dnaspnet/html/asp11222001.asp?frame=true

Of course, if you are carrying that much data around in cookies, you really should reconsider you Web-application design. Remember, each request made of the server will need to pass this cookie blob back, unnecessarily chewing up bandwidth.

Finally, encryption is a processor intensive activity. The more data you are encrypting/decrypting or the stronger your algorithm, the more server resources you will require, potentially slowing down the entire site.

The CryptoStream Object

One of the things you may find hard to understand at first is that all encryption and decryption in .NET is handled through the CryptoStream object. I know you are thinking that all we need to do is convert a few strings. Why do we need to mess with complicated streams. Well, from the broader scope of cryptographic issues and from the design emphasis of the .NET Framework, using streams really makes sense. Nearly all access (IO) to external resources handled by the .NET Framework is done through the use of streams. While it is not in the System.IO namespace, the CryptoStream object inherits from the System.IO.Stream object.

The major advantage of using streams is that they can be chained together. This is particularly useful when performing file operations or accessing other network services. For instance, you can open a socket to a network service and stream data that is simultaneously being encrypted. The following link provides an example of DES provider encrypting a file through streams.

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemSecurityCryptographyDESClassTopic.asp?frame=true

So, in order to work with strings as a stream, we need to utilize a special class called a MemoryStream. This will allow us to handle strings as streams and flow them through the CryptoStream for processing.

Creating a Simple Cryptography Utility Class

Well, you have all been waiting patiently, so here is the code for our CryptoUtil class. As with many utility functions, these don't require state so all our methods are shared (static).





Imports System.Diagnostics
Imports System.Security.Cryptography
Imports System.Text
Imports System.IO

Public Class CryptoUtil

'8 bytes randomly selected for both the Key and the Initialization Vector
'the IV is used to encrypt the first block of text so that any repetitive
'patterns are not apparent
Private Shared KEY_64() As Byte = {42, 16, 93, 156, 78, 4, 218, 32}
Private Shared IV_64() As Byte = {55, 103, 246, 79, 36, 99, 167, 3}

'24 byte or 192 bit key and IV for TripleDES
Private Shared KEY_192() As Byte = {42, 16, 93, 156, 78, 4, 218, 32, _
15, 167, 44, 80, 26, 250, 155, 112, _
2, 94, 11, 204, 119, 35, 184, 197}
Private Shared IV_192() As Byte = {55, 103, 246, 79, 36, 99, 167, 3, _
42, 5, 62, 83, 184, 7, 209, 13, _
145, 23, 200, 58, 173, 10, 121, 222}

'Standard DES encryption
Public Shared Function Encrypt(ByVal value As String) As String
If value <> "" Then
Dim cryptoProvider As DESCryptoServiceProvider = _
New DESCryptoServiceProvider()
Dim ms As MemoryStream = New MemoryStream()
Dim cs As CryptoStream = _
New CryptoStream(ms, cryptoProvider.CreateEncryptor(KEY_64, IV_64), _
CryptoStreamMode.Write)
Dim sw As StreamWriter = New StreamWriter(cs)

sw.Write(value)
sw.Flush()
cs.FlushFinalBlock()
ms.Flush()

'convert back to a string
Return Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length)
End If
End Function


'Standard DES decryption
Public Shared Function Decrypt(ByVal value As String) As String
If value <> "" Then
Dim cryptoProvider As DESCryptoServiceProvider = _
New DESCryptoServiceProvider()

'convert from string to byte array
Dim buffer As Byte() = Convert.FromBase64String(value)
Dim ms As MemoryStream = New MemoryStream(buffer)
Dim cs As CryptoStream = _
New CryptoStream(ms, cryptoProvider.CreateDecryptor(KEY_64, IV_64), _
CryptoStreamMode.Read)
Dim sr As StreamReader = New StreamReader(cs)

Return sr.ReadToEnd()
End If
End Function

'TRIPLE DES encryption
Public Shared Function EncryptTripleDES(ByVal value As String) As String
If value <> "" Then
Dim cryptoProvider As TripleDESCryptoServiceProvider = _
New TripleDESCryptoServiceProvider()
Dim ms As MemoryStream = New MemoryStream()
Dim cs As CryptoStream = _
New CryptoStream(ms, cryptoProvider.CreateEncryptor(KEY_192, IV_192), _
CryptoStreamMode.Write)
Dim sw As StreamWriter = New StreamWriter(cs)

sw.Write(value)
sw.Flush()
cs.FlushFinalBlock()
ms.Flush()

'convert back to a string
Return Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length)
End If
End Function


'TRIPLE DES decryption
Public Shared Function DecryptTripleDES(ByVal value As String) As String
If value <> "" Then
Dim cryptoProvider As TripleDESCryptoServiceProvider = _
New TripleDESCryptoServiceProvider()

'convert from string to byte array
Dim buffer As Byte() = Convert.FromBase64String(value)
Dim ms As MemoryStream = New MemoryStream(buffer)
Dim cs As CryptoStream = _
New CryptoStream(ms, cryptoProvider.CreateDecryptor(KEY_192, IV_192), _
CryptoStreamMode.Read)
Dim sr As StreamReader = New StreamReader(cs)

Return sr.ReadToEnd()
End If
End Function

End Class





Note that our keys are initialized at the top as an array of bytes. Also, note that I am using numeric constants in these arrays. If you choose to do the same, be sure to keep the values greater than or equal to zero and less than or equal to 255. This is the allowable range for a byte value.

In the class, we have 2 pairs of functions for encrypting and decrypting under both the DES and TripleDES providers. On the encrypt functions, the final byte array in the Memory Stream buffer is converted back to a string using the ToBase64String function. The reverse is done on the decrypt functions with the FromBase64String function.

Creating a Cookie Utility Class

Our next step is to create a simple class for setting and retrieving either plain cookies or those with encryption on top. Again we use series of shared methods to simplify the setting and getting of cookie data, allowing you to handle cookie data with one line of code.
Imports System.Web




Public Class CookieUtil

'SET COOKIE FUNCTIONS *****************************************************

'SetTripleDESEncryptedCookie - key & value only
Public Shared Sub SetTripleDESEncryptedCookie(ByVal key As String, _
ByVal value As String)
'Convert parts
key = CryptoUtil.EncryptTripleDES(key)
value = CryptoUtil.EncryptTripleDES(value)

SetCookie(key, value)
End Sub

'SetTripleDESEncryptedCookie - overloaded method with expires parameter
Public Shared Sub SetTripleDESEncryptedCookie(ByVal key As String, _
ByVal value As String, ByVal expires As Date)
'Convert parts
key = CryptoUtil.EncryptTripleDES(key)
value = CryptoUtil.EncryptTripleDES(value)

SetCookie(key, value, expires)
End Sub


'SetEncryptedCookie - key & value only
Public Shared Sub SetEncryptedCookie(ByVal key As String, _
ByVal value As String)
'Convert parts
key = CryptoUtil.Encrypt(key)
value = CryptoUtil.Encrypt(value)

SetCookie(key, value)
End Sub

'SetEncryptedCookie - overloaded method with expires parameter
Public Shared Sub SetEncryptedCookie(ByVal key As String, _
ByVal value As String, ByVal expires As Date)
'Convert parts
key = CryptoUtil.Encrypt(key)
value = CryptoUtil.Encrypt(value)

SetCookie(key, value, expires)
End Sub


'SetCookie - key & value only
Public Shared Sub SetCookie(ByVal key As String, ByVal value As String)
'Encode Part
key = HttpContext.Current.Server.UrlEncode(key)
value = HttpContext.Current.Server.UrlEncode(value)

Dim cookie As HttpCookie
cookie = New HttpCookie(key, value)
SetCookie(cookie)
End Sub

'SetCookie - overloaded with expires parameter
Public Shared Sub SetCookie(ByVal key As String, _
ByVal value As String, ByVal expires As Date)
'Encode Parts
key = HttpContext.Current.Server.UrlEncode(key)
value = HttpContext.Current.Server.UrlEncode(value)

Dim cookie As HttpCookie
cookie = New HttpCookie(key, value)
cookie.Expires = expires
SetCookie(cookie)
End Sub

'SetCookie - HttpCookie only
'final step to set the cookie to the response clause
Public Shared Sub SetCookie(ByVal cookie As HttpCookie)
HttpContext.Current.Response.Cookies.Set(cookie)
End Sub

'GET COOKIE FUNCTIONS *****************************************************

Public Shared Function GetTripleDESEncryptedCookieValue(ByVal key As String) _ As String
'encrypt key only - encoding done in GetCookieValue
key = CryptoUtil.EncryptTripleDES(key)

'get value
Dim value As String
value = GetCookieValue(key)
'decrypt value
value = CryptoUtil.DecryptTripleDES(value)
Return value
End Function

Public Shared Function GetEncryptedCookieValue(ByVal key As String) As String
'encrypt key only - encoding done in GetCookieValue
key = CryptoUtil.Encrypt(key)

'get value
Dim value As String
value = GetCookieValue(key)
'decrypt value
value = CryptoUtil.Decrypt(value)
Return value
End Function

Public Shared Function GetCookie(ByVal key As String) As HttpCookie
'encode key for retrieval
key = HttpContext.Current.Server.UrlEncode(key)
Return HttpContext.Current.Request.Cookies.Get(key)
End Function

Public Shared Function GetCookieValue(ByVal key As String) As String
Try
'don't encode key for retrieval here
'done in the GetCookie function

'get value
Dim value As String
value = GetCookie(key).Value
'decode stored value
value = HttpContext.Current.Server.UrlDecode(value)
Return value
Catch
End Try
End Function

End Class




You'll notice most of the set functions are overloaded to provide an addition parameter for a cookie expiration date. Not setting the expiration will keep the cookie only for the browser session in memory. To set a permanent cookie, set an expiration date for a point in the future.

Also, note that the encryption functions handle the encryption of both the data and the key. It is important to encrypt the key as well since that can expose information about the nature of the data. For instance, if your key was "UserID", then it might be safe to assume that your encrypted value is a numeric string, giving an attacker an advantage.

Encoding Cookies

Note that our standard cookie functions encode and decode the keys and values of the cookies. The reason for this is that cookies fall under the same restrictions as URLs. Specifically, the characters '=' and ';' are reserved and must be escaped; this is especially important when saving encrypted data because the encryption algorithm will append "=" to fill the block with the allocated block size.

The Sample Project

Our sample project is actually two projects: EncryptingCookies (view demo) and Plourdenet.Com.WebTools. EncryptingCookies is the Web-application project that contains our Web forms and utilizes the utility classes. Plourdenet.Com.WebTools is a class library project housing the utility classes. Placing the utility classes in a separate project makes it easy for us to eventually deploy the assembly to be shared with multiple Web projects.

Figure #2 - Solution Explorer for the Sample Projects

There are two thing to remember when setting up a structure like this. First, you must add a reference to System.Web in your class library. Second, you must add a reference to your utility project in your Web application. In addition, all the code that references the utility project should provide an Imports statement as such:




Imports Plourdenet.Com.WebTools





Creating Web Forms To Set Cookies

In our sample application, I have two forms. The first (and the default form) is SetCookies.aspx, and the second is GetCookies.aspx

SetCookies.aspx Web Form

The set cookies form is quite simple. We have a single text box and a button to post the value back to the server.

Figure #3 - The SetCookies.aspx Web Form

When the Save Cookie button is clicked, the form returns to the server and initiates the following server-side event:




Protected Const COOKIE_KEYNAME = "MyKey"

Private Sub btnSaveCookie_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnSaveCookie.Click
CookieUtil.SetCookie(COOKIE_KEYNAME, _
txtCookieValue.Text, Now.AddDays(30))
CookieUtil.SetEncryptedCookie(COOKIE_KEYNAME, _
txtCookieValue.Text, Now.AddDays(30))
CookieUtil.SetTripleDESEncryptedCookie(COOKIE_KEYNAME, _
txtCookieValue.Text, Now.AddDays(30))
Response.Redirect("GetCookies.aspx")
End Sub




Using a constant for the cookie key name and the value submitted in the text box, we set three cookies. First, a standard unencrypted cookie. Second, a cookie encrypted with DES, and third, a cookie encrypted with Triple DES.

GetCookies.aspx Web Form

The Get Cookies Web Form is doing a little more work behind the scene to show you what happens to your cookie data.

Figure #4 - The GetCookies.aspx Web Form

In the Page_Load event, we retrieve the cookie data using our CookieUtil accessor functions. Then, finally we dump out the contents of the entire cookie collection, just to prove there was no funny business.




Protected Const COOKIE_KEYNAME = "MyKey"

Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'Put user code to initialize the page here
Dim DESCookieKey As String = CryptoUtil.Encrypt(COOKIE_KEYNAME)
Dim TripleDESCookieKey As String = _
CryptoUtil.EncryptTripleDES(COOKIE_KEYNAME)

lblCookieName.Text = COOKIE_KEYNAME
lblStandardCookieValue.Text = _
CookieUtil.GetCookieValue(COOKIE_KEYNAME)
lblDESEncryptedValue.Text = _
CookieUtil.GetCookieValue(DESCookieKey)
lblDESDecryptedValue.Text = _
CookieUtil.GetEncryptedCookieValue(COOKIE_KEYNAME)
lblTripleDESEncryptedValue.Text = _
CookieUtil.GetCookieValue(TripleDESCookieKey)
lblTripleDESDecryptedValue.Text = _
CookieUtil.GetTripleDESEncryptedCookieValue(COOKIE_KEYNAME)

'Start Cookie Dump
Dim cookie As HttpCookie
Dim key As String
lblAllCookies.Text = _
" " & vbCrLf
lblAllCookies.Text &= _
" " & vbCrLf
For Each key In Request.Cookies.Keys
cookie = Request.Cookies(key)
lblAllCookies.Text &= _
" " & vbCrLf
Next
lblAllCookies.Text &= "

" & vbCrLf

End Sub





Cautions about Cookies

So there you have it - a fairly simple yet powerful way to encrypt your cookie data. But before I leave you, I want to review a few issues to watch out for when using cookies.

* Your entire cookie collection is limited to 4 kilobytes in size. This includes key, the space for key names, and other related data.

* The size of your cookie data will increase when encrypted. Make sure you do not run over the limit.

* Cookies are sent to the server every time a request is made to the server. Therefore, if you are lugging large cookies back and forth, you are using additional bandwidth and server processing resources.

* Encrypting large amounts of data can impact application performance.

* Any initial values supplied by your user cannot be encrypted unless you use SSL on your site. For instance, in our sample set cookies form, the initial value was passed in the clear to the server.

* Cookies can be blocked or deleted at anytime by your users. If the use of cookies is critical to the operation of your application, you may need to find ways to work around users that can't or won't permit them.

Good Luck! And let me know when you have baked your first batch of encrypted cookies.

radio button inside datagrid

Using Radio buttons to select each row in datagrid
=====================================
Using ASP.net to handle radio button would be slow or very slow if datagrid has much data to display because ASP .net triggers "evey" event of any server side control by reloaing the page while posting some data back to it, which definitely reduce performance.So I suggest you to choose javascript for this in collaboration with ASP .net, infact ASP .net translates most of its commands into javascript.To have radio buttons to select each row inside the datagrid follow the following easy steps (100% tested, if found any problem post here):

.ASPX File:
========
In aspx page add the following javascript function




Your Radio Button ASP .net Control inside the data grid would look like this:

Here I used GroupName property to just Identify the row no in Database, where datagrid is bound to any datasource in page load event. RecID in this case is the Primary Key in the table holding unique RecID for each row in the table. You can replace this with your table's field name, or remove it at all if you donot want to record the row number for each radio button. You can also use the Text property to set text for the radio button.Thats all concerned in aspx page.
.CS File
======
Here Make the following function and call it in Page Load event, this function would set the OnClick event of each RadioButton inside the data grid, let say your data grid name is "grdDataGrid":

public void SetGrdRadiosOnClick()
{
int i;
RadioButton B;
for (i = 0; i
B.Attributes.Add("OnClick", "SelectMeOnly(" + B.ClientID + ", "+ "'grdDataGrid'" + ")");
}
}

You got it, Thats all it need to have radio button functionality to select rows in Datagrid and in fastest way.Further, if you want to get which radio is selected and at which row then you cn use the following function, let say you have a button name "btnSelect" outside the datagrid to process the selected row in datagrid. (Remember we set the Unique Row ID of database in GroupName property of each radio button):GridName is "grdDataGrid"RadioButton inside the grid was "radioSelect" which is repeated for each rowpublic

void btnSelect_Click(object sender, System.EventArgs e)
{
RadioButton B;
int i, RecID=0;
for (i = 0; i
{
B = (RadioButton) grdDataGrid.Items[i].FindControl("radioSelect");
if (B.Checked) RecID = int.Parse(B.GroupName);
}
Response.Redirect("./ProcessRecord.aspx?RecID=" + RecID);
}

God Bless You.

Monday, February 4, 2008

Sending Email in ASP.NET 2.0

Introduction

A lot of times, we are facing some issues when sending email through the mailserver. Especially if we host our websites in shared hosting and the mail will never get to the recipient. There are lots of reason for this to happen. In this article I would like to explain how to Send Email using .NET 2.0 Framework and how to troubleshoot your code if your email never reach the recipient. This article will only cover sending Email using ASP.NET 2.0 and will not work in ASP.NET 1.0.

Microsoft has improved the SMTP library in their .NET Framework 2.0 and therefore the code you find in this article will not work in .NET 1.0.



Main
Sending Email in .NET 2.0 is quite easy and straight forward and you can send Email with just five lines of code. In .NET 2.0, Sending Email library in ASP.NET 2.0 is called System.Net.Mail.SmtpClient library. Therefore your code need to Import System.Net.Mail or Using System.Net.Mail
in your code

Before you use the code below, please make sure that you know the ipaddress or the hostname of your mailserver. You can actually detect if the ipaddress of your mailserver is infact a mailserver by using telnet command.
In command prompt, type telnet ipaddress 25.
If you got replied from the telnet command, then the Ipaddress of your mail server has the SMTP Service started, and if not, then you cannot use the Mail Server to send email. SMTP Server is listening on port 25 and therefore you need to be able to telnet in before you can send email.

Basic Sample Code to Send Text Email in ASP.NET 2.0

C#


SmtpClient smtpClient = new SmtpClient("IPaddress");
MailMessage message = new MailMessage("sender@sender.com", "rcpt@recipient.com");
message.Subject = "Subject Email";
message.Body = "Body Email";
smtpClient.Send(message);

VB.NET

Dim message As New MailMessage("sender@sender.com", "rcpt@recipient.com")
Dim SmtpClient As New SmtpClient("ipaddress")
message.Subject = "Subject Email"
message.Body = "Body Email"
SmtpClient.Send(message)

As you can see that you only need 5 lines of code to send email. And thats all you need. However the code above will not work if your SMTP server is configured with authentication. Lots of mailserver these days has been configured with SMTP authentication to prevent spam and abuse. SMTP Authentication means that before you can send email against the mailserver, you need to provide your login id and password. This is to prevent spam and abuse from unauthorized users. The login ID and password will normally be your email user and password or your NT Login. You need to check with your MailServer administration for further information about this.

Basic Sample Code on Sending HTML Email in ASP.NET 2.0
C#


SmtpClient smtpClient = new SmtpClient("IPaddress");
MailMessage message = new MailMessage("sender@sender.com", "rcpt@recipient.com");
message.Subject = "Subject Email";
message.Body = "<H2>Testing HTML Email

";
message.IsBodyHtml = true;
smtpClient.Send(message);

VB.NET
Dim message As New MailMessage("sender@sender.com", "rcpt@recipient.com")
Dim SmtpClient As New SmtpClient("ipaddress")
message.Subject = "Subject Email"
message.Body = "

Testing HTML Email

"
message.IsBodyHtml = True
SmtpClient.Send(message)


As you can see that Sending HTML email from .NET framework is very easy. You just need to set the property IsBodyHtml = true and you are done!.

Basic Sample Code on Sending Email using Attachment
C#

message.Attachments.Add(new Attachment(@"C:\Data.txt"));


VB.NET
message.Attachments.Add(new Attachment("C:\Data.txt"))


For including attachments in your email, you just need to include the attachments in your MailMessage object. Adding above code to the previous code will allow you to send attachment email.

Sending Email through SMTP Authentication

If using above sample code doesn't let you send email, then you might need to try sending email using SMTP Authentication.

Basic Sample Code on Sending Email using SMTP Authentication
VB.NET

Dim message As New MailMessage("sender@sender.com", "rcpt@recipient.com")
Dim SmtpClient As New SmtpClient("IPAddress")
message.Subject = "Subject Email"
message.Body = "

Testing HTML Email

"
message.IsBodyHtml = True
SmtpClient.Credentials = new NetworkCredentials("sender@sender.com","password")
SmtpClient.Send(message)C#

SmtpClient smtpClient = new SmtpClient("IPaddress");
MailMessage message = new MailMessage("sender@sender.com", "rcpt@recipient.com");
message.Subject = "Subject Email";
message.Body = "<H2>Testing HTML Email

";
message.IsBodyHtml = true;
smtpClient.Credentials = new NetworkCredentials("sender@sender.com","password");
smtpClient.Send(message);
As you can see from the code above, you need to pass your email username and password before you can send email. Please note that the email username and password must belong to the mailserver or else it will reject if the mailserver couldn't validate the logon details.

Troubleshooting System.Net.Mail
Few tips and tricks for you to troubleshoot if you email never arrived to the destination

Check if the SMTP Server is listening on port 25 (telnet ipaddress 25)
Check if your Mailserver ip is being blacklisted (http://mxtoolbox.com/blacklists.aspx)
Check if your SMTP Server is being configured using SMTP Authentication.
If using SMTP Authentication, then check if your username and password is correct.
You can try login using the username and password using outlook and try to send email from outlook. Remember to check using SMTP Authentication is your outlook settings.

Conclusion

Sending Email in ASP.NET 2.0 is extremely easy and straight forward. Thanks to Microsoft Team that has made this library very easy to use. Feel free to add any comments to my article and Happy Programming !

Search