Tuesday, May 03, 2005

.NET 2.0 Generics

I am testing out the new .NET 2.0 Generics feature, and found it's very cool.

Generics allow you to define type-safe classes without compromising type safety, performance, or productivity (From MSDN). That's really true especially on productivity. With Generics you are no longer need to do the type casting. Goodbye ArrayList because we have generic List!
using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
public interface ITimeable
{
DateTime GetTime();
}

public class MyEvent : ITimeable
{
private string _name;
private DateTime _time;
public MyEvent(string name, DateTime time)
{
_name = name;
_time = time;
}
public DateTime GetTime()
{
return _time;
}
public override string ToString()
{
return _name;
}
}

public class Helper
{
public static List<T> GenericSortByTime<T>(List<T> items) where T : ITimeable
{
items.Sort(delegate(T item1, T item2)
{
return item1.GetTime().CompareTo(item2.GetTime());
});
return items;
}

public static List<T> GenericSortByName<T>(List<T> items) where T : class
{
items.Sort(delegate(T item1, T item2)
{
return item1.ToString().CompareTo(item2.ToString());
});
return items;
}
}

class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
List<MyEvent> events = new List<MyEvent>();
events.Add(new MyEvent("1", now.AddDays(1)));
events.Add(new MyEvent("3", now.AddDays(2)));
events.Add(new MyEvent("2", now.AddDays(3)));
events.Add(new MyEvent("a", now.AddDays(-1)));
events.Add(new MyEvent("b", now.AddDays(-2)));
Console.WriteLine("Original list:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
events = Helper.GenericSortByTime(events);
Console.WriteLine("Sort by time:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
events = Helper.GenericSortByName(events);
Console.WriteLine("Sort by name:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
Console.Read();
}
}
}

Result:

Monday, April 18, 2005

.NET 2.0 Beta 2

.NET 2.0 Beta 2 and Visual Studio 2005 Beta 2 were just released last week. I tested it and did see a lot of improvements comparing previous version: full 64-bit support, enhanced intelli-sense, generics, partial class, typed data table, and a lot of new controls...

But one thing confused me is that VS2005 is still built by C++. Why not C#/VB.NET? It's more convincing to people that .NET is robust and mature enough for enterprise applications, if Microsoft is building their own tools using .NET.

Monday, March 07, 2005

Email Sending in .NET

First you need a SMTP server (relay server) available for your .NET application to send out emails. SMTP server can be a Linux Sendmail demon or IIS SMTP service.

To send an email in .NET 1.1, you need a reference to System.Web.dll and use the System.Web.Mail namespace:

MailMessage emailMsg = new MailMessage();
emailMsg.From =
"sender@mydomain.com";
emailMsg.To =
"receiver@mydomain.com";
emailMsg.Subject =
"Subject";
emailMsg.Body =
"Body";
SmtpMail
.SmtpServer = "mysmtpserver.com";
SmtpMail
.Send(emailMsg);

Be aware that under the hood .NET dispatches email message to a COM library CDO.Message included in cdosys.dll, which come with Windows 2003 server (in $Windows$/system32 folder). So .NET email function is just a wrapper function, and unmanaged (native) code is involved during the email sending.

If SMTP server requires authenitcation, you need to add following setting for MailMessage:

emailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1;
emailMsg.Fields[
"http://schemas.microsoft.com/cdo/configuration/sendusername"] = "myLogin";

emailMsg.Fields[
"http://schemas.microsoft.com/cdo/configuration/sendpassword"] = "myPassword";

If you want the a HTML format of email, and add an attachment to it:

emailMsg.BodyFormat = MailFormat.Html;
MailAttachment
emailAttchement = new MailAttachment(fileName);
emailMsg.Attachments.Add(emailAttchement);

Tuesday, February 22, 2005

ASP.NET Session Cookies and Authentication Cookies

In previous blog I briefly mentioned the Session cookie and the Authentication Cookie. How do they work?

First let's look at the Session in ASP.NET. ASP.NET Session is a state management mechanism that maintains session data inside the server for a unique user interacting with the server for a period of time. For example, you can pull a user profile data from database during user's first visit and store it into Session, then for the next requests from the same user you can retrieve the profile data directly from Session without bothering database:

User currentUser = Session["UserProfile"] as User;
if (currentUser == null)
{

currentUser = UserService.GetUserById(id);
Session[
"UserProfile"] = currentUser;
}


The Session data are stored in memory by default. But you have option to store Session data in a dedicated machine, in database, or use your you own session provider. This is important in a web farm environment.

How do ASP.NET web server identify a user and retrieve its Session data? ASP.NET uses a 120 bit identifier (Session ID) to track each session. When the user first talks to the server, the Session cookie is empty and the server will create a new Session ID and set to Session cookie which will be kept in user's browser store (non-persistent cookie). When the user talks the server again, ASP.NET looks on to Session ID and retrieves corresponding data. You can see the Session cookie using a traffic monitor tool such as Fiddler :

Cookie: ASP.NET_SessionId=ezdpwa55i5xo41rbp5bfbv55;

Now let's discuss the Authentication and Authentication cookie. Authentication is a mechanism to obtain a user's identity by validating its credential against the authority such as Active Directory or LDAP. By default ASP.NET supports Windows Authentication, Passpart Authentication, and Forms Authentication. In short, Windows Authentication is managed by IIS, Passport Authentication is handled by a web-based and centralized store control by Microsoft, and Forms Authentication is the only one that is able to check user credentials stored in a file or in a custom database. Authentication cookie is used in all three scenarios, but we only cover Forms Authentication cookie here.

With Forms Authentication, usually you create a login form with the logic to validate a user against credential store. If authentication fails then the user will be treated as anonymous user and granted limited permssion. If authentication succeeds, the server will create a Forms Authentication ticket and add the ticket in Authenticaiton cookie. This is usually done by:

FormsAuthentication.SetAuthCookie(userName, false);

Or

FormsAuthentication.RedirectFromLoginPage(userName, false);


The second parameter in above two methods sets the Authentication cookie to be non-persistent or persistent.

For security consideration, the Forms Authentication ticket is encrypted and signed using server's Machine.config configuration before saving to Authentication cookie. The default encryption algorithm is 3DES. You will see the real Authentication cookie like:

Cookie: .ASPXAUTH=5D49D0CFCC287EE624F53A0FFC51F436C098E90D6345ACC06BF249661725E004E403880ACEA9F069A221C2D4893D5BBDDA2AFE4A63D17DC04;


Because different machines have different encryption/decryption keys, the same Authentication cookie won't be able to be decrypted in all machines inside a web farm. To resolve this problem, you have to explicitly specify the values for "validationKey" and "decryptionKey" attributes in the section of your application’s web.config file in each machine cross the web farm, so all machines will use the same encryption/decryption keys.

(2006/03 updated) The same encryption/decryption keys are used to handled the ViewState for ASP.NET pages. You have to do the same configuration update if you have a web farm, otherwise you will get a server error:

Saturday, February 12, 2005

ASP.NET Cookies

A cookie is a small piece of data that is created in the server and stored in a client's web browser. Cookies are part of the request data that sent to the server. And server are able to retrieve or update cookies.

Cookie is used in ASP.NET to do the authentication and session tracing. Cookie can be easily manipulated in your ASP.NET web application, such as storing user preferences. It's a good practice to only store small piece of data inside cookie because browsers have cookie size limit. For example, IE has 4K of maximum size of cookie, and only allows 20 cookies per domain name.

To read a cookie, you get the HttpCookie collection from the Request object:
HttpCookie cookie = Request.Cookies["MyCookie"]; // Or Request.Cookies[0]
string cookieName = cookie.Name; // = "MyCookie"
string cookieValue = cookie.Value;
To set or update a cookie:
HttpCookie cookie = new HttpCookie("MyCookie");
cookie.Value = "My Value";
Response.Cookies.Add(aCookie);
Or simply:
Response.Cookies["MyCookie"].Value = "My Value";
To delete a Cookie, you have to update the cookie with expiration defined before current time:
Response.Cookies["MyCookie"].Expires = DateTime.Now.AddDays(-1);
Cookie with expiration time tells browser to remove the cookie when it's expired. A cookie without expired time is called non-persistent cookie because it won't store in user's hard disk, and the cookie is discarded when browser is closed. By default, Session cookie in ASP.NET is non-persistent cookie, while authentication cookie is persistent cookie.

Domain is another property you can set for a cookie. You may have a website of http://www.mysite.com and have a subdomain of http://sales.mysite.com. If you want to share the cookie in these two domains then you should do:
cookie.Domain = "mysite.com";
You can also limit the cookie to a folder in your application by setting cookie's Path property. For example, you want to have a cookie only available in http://www.mysite.com/Application1 and another cookie only available for http://www.mysite.com/Applicaiton2:
cookie1.Path = "/Application1";
cookie2.Path = "/Application2";
You can store one value in a cookie as described above. You can also store multiple name-value pairs in a single cookie:
Response.Cookies["MyCookie"]["Name1"] = "value1";
Response.Cookies["MyCookie"]["Name2"] = "value2";
To get a multi-value cookie:
string cookieValue1 = Request.Cookies["MyCookie"]["Name1"];
string cookieValue2 = Request.Cookies["MyCookie"]["Name2"];
Just for your curiosity, the multi-value cookie transferred between browser and server is something like:

Cookie: MyCookie=Name1=value1|Name2=value2;

Wednesday, January 19, 2005

A Few Findings About .NET Delegate/Event

Events are allowed in an interface. Delegates are not allowed in an interface, but delegate properties are allowed in an interface.

Delegates are immutable, and cannot be modified after they are constructed.

There's no straight or easy way to remove all delegates attached to an event.

A separate thread will be created by .NET to handle the FileSystemWatcher events with asynchronous processing.

Wednesday, December 22, 2004

ASP.NET 1.1 Application/Page Lifecycle

It's essential to understand the execution lifecycle of ASP.NET. There's probably been plenty written on this topic but I just want to do a quick exercise to make sure the order is correct. So I created a simple page with a user control, and traced each event inside Global.asax and page's code behind. Here's the result:
  1. Application_Start //Only occurs when application is loaded
  2. Application_Init //Only occurs when application is loaded
  3. Application_BeginRequest
  4. Application_AuthenticateRequest
  5. Session_Start
  6. Page_Control_Init
  7. Page_Init
  8. Page_Control_LoadViewState
  9. Page_ProcessPostData // In Poskback
  10. Page_Load
  11. Page_Control_Load
  12. Page_RaisePostBackEvent // In Postback
  13. Page_SaveViewState
  14. Page_Control_SaveViewState
  15. Page_Control_Render
  16. Page_Render
  17. Page_Control_Unload
  18. Page_Unload
Notice the order of control events and page events. Control's Init, Render, Unload events occur earlier than Page's equivalents, but control's Load and SaveViewState events come later than Page's.

Monday, November 15, 2004

Remove Hidden Folders Recursively in Windows

In a Windows XP machine there's a folder copied from a Unix machine which contains many useless and hidden .cache folders. Following script can delete all these hidden folders recursively in DOS command line:

C:\temp>for /f "tokens=* delims=" %x in ('dir /s /b /a:d *cache') do rd /s /q "%x"

Alternatively we can create .bat batch file so we can just click it to run the script, but the token needs to be changed from %x to %%x:

for /f "tokens=* delims=" %%x in ('dir /s /b /a:d *cache') do rd /s /q "%%x"

Friday, November 12, 2004

C# vs Java

C# syntax is very similar to Java. Most noticeable ones to me are following ( based on C# 1.0 and Java 1.4):

1. C# uses namespace to organize the class by "using" keyword. Not like Java's package, C#'s namespace is purely logical without any implication of file/folder relation.

2. No "throws" in C# since C# doesn't have checked exceptions. C# only handles exception when it's actually thrown (not may be thrown). While in Java you must try-catch a potential exception or throws it explicitly, otherwise your code won't compile.

3. C# has "internal" and "protected internal" access modifiers. You can define a class with more granular scale.

3. No primitive type in C#. All C# types are rooted from System.Object. Following code is fine in C# but not in Java:
ArrayList list = new ArrayList
list.Add(123); // Java compile error
int
number = (int)list[0]; // Java compile error
Type
type = number.GetType(); // Java compile error

5. C# property is more intuitive than Java's accessor methods.

6. C# has "struct" while Java doesn't. .NET will put structs in stack instead of heap.

7. C# has "virtual" functions and you have to use "override" modifier explicitly to override a method in subclasses. A "new" function in C# creates a new method with same signature in subclasses, which is only visible in that specific class. Java doesn't have "virtual", "override" and "new" function modifiers. Function is picked based on class type checking.

8. C# doesn't have "final" constants but it has "const" and "readonly" for constant declaration. The difference between "const" and "readonly":
const
  • Can't be static.
  • Value evaluated at compile time.
  • Initialized at declaration only.
readonly
  • Can be static or instance.
  • Value evaluated at run time.
  • Declaration or initialized in the constructor.

9. C# has delegate - a type-safe method pointer. This delegate is very useful from my opinion. You can do interesting things similar to C/C++ pointers. Java doesn't have equivalent function.

10. Passing by values is default in C#. In addition C# has option to pass by references using keyword of "ref" or "out" (you have to initialize the "out" parameters). You can not pass by references in Java (for objects, Java creates a copy of parameter pointing to the same object in the heap, which leads to confusion in some cases).

Looks like C# is more powerful than Java at a glance, or just some syntax sugar you would argue?

Friday, October 08, 2004

HPCBench Now Open Source

Part of my work for High Performance Computing (HPC) analysis, I wrote a C/MPICH toolkit named HPCBench to evaluate the network performance for Linux-based clusters. Now it becomes an open-source project in SourceForge (http://hpcbench.sf.net).

Overview

Hpcbench is a Linux-based network benchmark evaluating the high performance networks such as Gigabit Ethernet, Myrinet and QsNet. Hpcbench measures the network latency and achievable throughput between two ends. Hpcbench is able to log the kernel information for each test, which includes the CPU and memory usage, interrupts, swapping, paging, context switches, network cards' statistics, etc.

Hpcbench consists of three independent packages that test UDP, TCP and MPI communications respectively. A kernel resources tracing tool "sysmon" is also included, whose output is similar to that of vmstat, but has more information of network statistics.

Programming language: C, MPI.
Recommended OS and compiler: Linux kernel 2.4 and gcc.

Features

UDP communication:

  • Microsecond resolution
  • Roundtrip time test (UDP ping)
  • Throughput test
  • Unidirectional and Bidirectional test
  • UDP traffic generator (can run in single mode)
  • Fixed size and exponential test
  • Log throughputs and process resource usage of each test
  • Log system resources information of client and server (Linux only)
  • Create plot configuration file for gnuplot
  • Configurable message size
  • Other tunable parameters:
    • Port number
    • Client and server's UDP socket buffer size
    • Message size
    • Packet (datagram) size
    • Data size of each read/write
    • QoS (TOS) type (Pre-defined six levels)
    • Test time
    • Test repetition
    • Maximum throughput restriction (Unidirectional and UDP traffic generator)

TCP communication:

  • Microsecond resolution
  • Roundtrip Time test (TCP ping)
  • Throughput test
  • Unidirectional and Bidirectional test
  • Blocking and non-blocking test
  • Fixed size and exponential test
  • Linux sendfile() test
  • Log throughputs and process resource usage of each test
  • Log system resources information of client and server (Linux only)
  • Create plot configuration file for gnuplot
  • Configurable message size
  • Other tunable parameters:
    • Port number
    • Client and server's TCP socket buffer (window) size
    • Message size
    • Data size of each read/write
    • Iteration of read/write
    • MTU (MSS) setting
    • TCP socket's TCP_NODELAY option setting
    • TCP socket's TCP_CORK option setting
    • QoS (TOS) type (Pre-defined six levels)
    • Test time
    • Test repetition

MPI communication:

  • Microsecond resolution
  • Roundtrip Time test (MPI ping)
  • Throughput test
  • Unidirectional and Bidirectional test
  • Blocking and non-blocking test
  • Fixed size and exponential test
  • Log throughputs and process resource usage of each test
  • Log system resources information of two processes (nodes) (Linux only)
  • Create plot configuration file for gnuplot
  • Tunable parameters:
    • Message size
    • Test time
    • Test repetition