Saturday, September 27, 2008

Cookie in ASP.NET

The HTTP protocol, the fundamental protocol of the World Wide Web, is a stateless protocol. What this means is that from a web server’s perspective, every request is from a new user.

Cookie

  • You can create two types of cookies:
    • Session Cookie:
      • Exists only in memory.
      • Disappears when browser is closed.
      • If you do not specify an expiration date for the newly created cookie, then it will become a session cookie.
    • Persistent Cookie:
      • IE stores cookies in: \Documents and Settings\[user]\Cookies
      • FireFox stores cookies in: \Documents and Settings\[user]\Application Data\Mozilla\Firefox\Profiles\[random folder name]\Cookies.txt
  • Browser Relative
    • Cookies created by IE will not be recognised by FireFox.
  • Stored in Clear Text
    • You should never store sensitive information in a cookie.
  • Domain Relative
    • When a browser creates a cookie, the browser records the domain associated with the cookie and doesn’t send the cookie to another domain.
  • Cookie names are case sensitive.
  • Size
    • A single domain cannot store more than 4096 bytes which includes both the cookie names and the cookie values.
    • Most browsers restrict the number of cookies that can be set by a single domain to
      no more than 20 cookies (but not IE). If you attempt to set more than 20 cookies, the oldest cookies are automatically deleted. You can work around this limitation by creating multi-valued cookies.
  • Usage
    • Many parts of the ASP.NET Framework rely on cookies.
      • Web Parts
      • Forms Authentication
      • Session State
      • Anonymous Profiles
    • Many websites rely on cookies.
      • Yahoo
      • MSDN

Cookie Properties

  • Domain:
    • This property is useful when your organization includes subdomains.
    • Use this property to associate a cookie with a subdomain, but not an entirely different domain.
  • HttpOnly
    • Specify whether a cookie can be accessed from JavaScript code.
    • This property works only with Internet Explorer 6 (Service Pack 1) and above.
    • The property was introduced to help prevent cross-site scripting attacks.

Multi-Valued Cookies

  • A multi-valued cookie is a single cookie that contains subkeys. You can create as many subkeys as you need.
  • You can use the HttpCookie.HasKeys property to detect whether a cookie is a normal cookie or a multi-valued cookie.

Code Sample:

In the sample code, I will show you how to create, display and delete cookie.

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="TestCookie._Default" Trace="true"%>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">


<title>Untitled Page</title>


</head>


<body>


<form id="form1" runat="server">


<div>


<asp:Button ID="btnCreate" runat="server" Text="Create Cookie" />


<asp:Button ID="btnPostBack" runat="server" Text="Post Back" />


<asp:Button ID="btnDisplay" runat="server" Text="Display Cookie" />


<asp:Button ID="btnDelete" runat="server" Text="Delete Cookie" />


<asp:Button ID="btnCreateMultiValued" runat="server" Text="Create multi-valued Cookie" />


<asp:Button ID="btnDisplayMultiValued" runat="server" Text="Display multi-valued Cookie" />


</div>


</form>


</body>


</html>

Partial Public Class _Default


Inherits System.Web.UI.Page


Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load


End Sub


Private Sub btnCreate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCreate.Click


Response.Cookies("TestUserFirstName").Value = "Sam"


Response.Cookies("TestUserFirstName").Expires = DateTime.MaxValue


Response.Cookies("TestUserLastName").Value = "Fu"


Response.Cookies("TestUserLastName").Expires = DateTime.MaxValue


End Sub


Private Sub btnDisplay_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDisplay.Click


For i As Integer = 0 To Request.Cookies.Count - 1


Response.Write(String.Format("{0}: {1}<br />", Request.Cookies(i).Name, Request.Cookies(i).Value))


Next


If Request.Cookies("TestUserFirstName") IsNot Nothing Then


Response.Write("TestUserFirstName=" + Request.Cookies("TestUserFirstName").Value)


End If


If Request.Cookies("TestUserLastName") IsNot Nothing Then


Response.Write("TestUserLastName=" + Request.Cookies("TestUserLastName").Value)


End If


End Sub


Private Sub btnDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDelete.Click


Dim cookies As String() = Request.Cookies.AllKeys


For Each cookie As String In cookies


Response.Cookies(cookie).Expires = DateTime.Now.AddDays(-1)


Next


End Sub


Private Sub btnCreateMultiValued_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCreateMultiValued.Click


Response.Cookies("TestUser")("FirstName") = "Sam"


Response.Cookies("TestUser")("LastName") = "Fu"


Response.Cookies("TestUser").Expires = DateTime.MaxValue


End Sub


Private Sub btnDisplayMultiValued_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDisplayMultiValued.Click


If Request.Cookies("TestUser") IsNot Nothing Then


Response.Write(Request.Cookies("TestUser")("FirstName"))


Response.Write(Request.Cookies("TestUser")("LastName"))


End If


End Sub


End Class

Note:

  • Request.Browser.Cookies will only check whether the browser support cookie, not whether or not they're enabled.

How it works

Step 1. Before any request.


Step 2. Click the create cookie button. The server send the response back with an additional HTTP header to the browser. The HTTP response header looks like this: Set-Cookie: TestUserFirstName=Sam. This Set-Cookie header causes the browser to create a cookie named TestUserFirstName that has the value Sam. The 'Headers Collection' of the tracing ouput is always the request header, not the response header, so you cannot see 'Set-Cookie' in this section.



Step 3. Click the postback button. After a cookie has been created on a browser, whenever the browser requests a page from the same application in the future, the browser sends a request header that looks like this:Cookie: TestUserFirstName=Sam. The Cookie header contains all the cookies that have been set by the web server.


Note:

  • There are two HTTP headers, Set-Cookie and Cookie, that are related to cookies.
    • Set-Cookie response header is sent by the server in response to an HTTP request, which is used to create a cookie on the user's system. (Refer to Step 2 above)
    • Cookie request header is included by the client application with an HTTP request sent to a server if there is a cookie that has a matching domain and path. (Refer to Step 3 above)

Reference:

ASP.NET 2.0 Unleashed

Working with Cookies

Monday, September 15, 2008

WCF vs. ASMX

Protocols Support

  • WCF
    • HTTP
    • TCP
    • Named pipes
    • MSMQ
    • Custom
    • UDP
  • ASMX
    • HTTP only

Hosting

  • ASMX
    • Can be hosted only with HttpRuntime on IIS.
  • WCF
    • A WCF component can be hosted in any kind of environment in .NET 3.0, such as a console application, Windows application, or IIS.
    • WCF services are known as 'services' as opposed to web services because you can host services without a web server.
    • Self-hosting the services gives you the flexibility to use transports other than HTTP.

WCF Backwards Compatibility

  • The purpose of WCF is to provide a unified programming model for distributed applications.
  • Backwards compatibility
    • WCF takes all the capabilities of the existing technology stacks while not relying upon any of them.
    • Applications built with these earlier technologies will continue to work unchanged on systems with WCF installed.
    • Existing applications are able to upgrade with WCF
    • New WCF transacted application will work with existing transaction application built on System.Transactions

WCF & ASMX Integration

  • WCF can use WS-* or HTTP bindings to communicate with ASMX pages

Limitations of ASMX:

  • An ASMX page doesn’t tell you how to deliver it over the transports and to use a specific type of security. This is something that WCF enhances quite significantly.
  • ASMX has a tight coupling with the HTTP runtime and the dependence on IIS to host it. WCF can be hosted by any Windows process that is able to host the .NET Framework 3.0.
  • ASMX service is instantiated on a per-call basis, while WCF gives you flexibility by providing various instancing options such as Singleton, private session, per call.
  • ASMX provides the way for interoperability but it does not provide or guarantee end-to-end security or reliable communication.

References:

Pro WCF: Practical Microsoft SOA Implementation

Migrating ASP.NET Web Services to WCF

Monday, September 8, 2008

Sharepoint Lookup Column - Get multiple values

In this post, I will show you how to display lookup column data in a multiple selection format.

Steps:

1. I have a list called 'ATSCompany' which has a lookup column called 'Video' which references a document library called 'ATSCompany Videos'. Notice that I have selected the 'Allow multiple values' checkbox.

2. Edit a list item of the ATSCompany list, here is what it looks like.


3. After you have selected all 3 videos, the value of the video column is a string containing all the three video file name separated by semicolon.

4. In Sharepoint designer, I have created a custom list form for viewing the ATSCompany List. Right click the List and go to List Properties, you can see that I have specified CompanyProfile.aspx as the view item page for the ATSCompany Page. More
details.



5. In the CompanyProfile.aspx, it should displays three links which link to the videos in the 'ATSCompany Videos' document library.


6. In the Sharepoint designer, under the WebPartPages:dataformwebpart of the ATSCompany List. You will have the following to show the video links. Note that template ParseVideoString makes a recursive call to itself.

1 <xsl:if test=" string-length(@Video) &gt;0" ddwrt:cf_ignore="1">


2 <div>


3 <br />


4 <h3>Videos</h3>


5 <xsl:call-template name="ParseVideoString">


6 <xsl:with-param name="parse-string" select="@Video" />


7 </xsl:call-template>


8 </div>


9 </xsl:if>



1 <xsl:template name="ParseVideoString">


2 <xsl:param name="parse-string"></xsl:param>


3 <xsl:if test="not($parse-string='')">


4 <xsl:choose>


5 <xsl:when test="contains($parse-string, ';')">


6 <a href="../ATSCompany Videos/{substring-before($parse-string, ';')}" ><xsl:value-of select="substring-before($parse-string, ';')"/></a><br /></xsl:when>


7 <xsl:otherwise>


8 <a href="../ATSCompany Videos/{$parse-string}" ><xsl:value-of select="$parse-string"/></a></xsl:otherwise>


9 </xsl:choose>


10 <xsl:call-template name="ParseVideoString">


11 <xsl:with-param name="parse-string">


12 <xsl:value-of select="substring-after($parse-string, ';')"/>


13 </xsl:with-param>


14 </xsl:call-template>


15 </xsl:if>


16 </xsl:template>


Monday, September 1, 2008

Passing QueryString to IFrame

Page Redirection

If you have a page contains an iframe which contains Page1.aspx, and you want to redirect to Page2.aspx from Page1.aspx, you cannot just use response.redirect in Page1.aspx.vb, you could use the following in Page1.aspx.vb:

1 Dim cs As ClientScriptManager = Me.ClientScript


2 Dim script As String


3 script = String.Format("<script>window.parent.location='Page2.aspx?group={0}&type={1}';</script>", _


4 ddlGrouping.SelectedIndex, ddlStudentType.SelectedIndex)


5 cs.RegisterStartupScript(Me.GetType(), "Redirect", script)


You will notice that when the page is redirected, if you click the browser back button, you will not be able to click back since location.href will not keep the browser history. But even you use location.replace, the back button is still greyed out, I think that is because Page1.aspx is inside of an Iframe.

Reading QueryString

If Page2.aspx contains an iframe which contains Page3.aspx. And now you want to pass values from Page1.aspx to Page3.aspx through querystring, here is how:

1 <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Page2.aspx.vb" Inherits="Page2.TestIFrame" %>


2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


3 <html xmlns="http://www.w3.org/1999/xhtml" >


4 <head runat="server">


5 <title>Untitled Page</title>


6 </head>


7 <body>


8 <form id="form1" runat="server">


9 <div>


10 <iframe class=home_hero marginWidth=0 marginHeight=0


11 src="Page3.aspx?<%=Request.ServerVariables("QUERY_STRING")%>"


12 frameBorder=0 width=981 scrolling=no height=800></iframe>


13 </div>


14 </form>


15 </body>


16 </html>


If Page2.aspx contains a RadEditor which contains an iframe, the iframe contains Page3.aspx. And now you want to pass values from Page1.aspx to Page3.aspx through querystring, you cannot use the above code in the RadEditor, Request.ServerVariables("QUERY_STRING") will not be recoginized in RadEditor. You could type the following into the RadEditor:

1 <div><iframe id=test name=test marginWidth=0 marginHeight=0 frameBorder=0 width=981 scrolling=no height=800></iframe></div>


2 <script>


3 function getQueryVariable(variable)


4 {


5 var query = window.location.search.substring(1);


6 var vars = query.split("&");


7 for (var i=0;i<vars.length;i++)


8 {


9 var pair = vars[i].split("=");


10 if (pair[0] == variable)


11 {


12 return pair[1];


13 }


14 }


15 }


16 function load()


17 {


18 var g = getQueryVariable("group") ;


19 var t = getQueryVariable("type") ;


20 if (g != null && t != null)


21 {


22 document.getElementById('test').src = 'Page3.aspx?group='+g+'&type='+t;


23 }


24 }


25 window.onload = load;


26 </script>


Reference:

Javascript to parse query string variables from URL