Edit or 's N ot e : Th is a r t icle ' s code h a s be e n u pda t e d t o w or k w it h t h e fin a l r e le a se of t h e .N e t fr a m e w or k . did before, first defining our basic requirem ent s, set t ing up t he necessary m odificat ions, and finally convert ing it t o code.
These enhancem ent s w ill dem onst r at e how easy it is t o add new funct ionalit y t o t he fram ew or k described in t he previous art icle, by adding a cust om er rat ing cont rol for t he available it em s. We w ill also build an adm inist rat ion console, w hich w ill enable us t o m anage t he online st ore t hrough t he w eb. We w ill also discuss t he secur it y issues
CATEGORY: Applicat ion Developm ent
ARTI CLE TYPE: Tut orial Reader Com m ent s I n t his art icle, Juan Mart inez cont inues his work in building an online shopping cart applicat ion. I n part
one, he discussed t he basic fram ew ork of t he applicat ion, now t he t im e has com e t o increase t he feat ures of t he shopping cart and have a com plet e syst em for online use. These enhancem ent s w ill dem onst rat e how easy it is t o add new funct ionalit y t o t he fram ew ork, by adding a cust om er rat ing cont rol for t he available it em s. He w ill also build an adm inist rat ion console, which will enable us t o m anage t he online st ore t hrough t he web, and will discuss t he secur it y issues on t he w eb, and how t o im plem ent SSL in you ser ver for encr ypt ion. Finally he w ill briefly discuss t he various paym ent services available on t he w eb.
Art icle Discussion Rat e t his ar t icle Relat ed Links I ndex Ent ries
Before w e st art t o put t oget her our new com ponent s, w e need t o rem em ber t he archit ect ure of our exist ing shopping cart . We w ill review t he shopping cart m odel and st at e w here our m odificat ions w ill be. We w ill also look back at our exist ing dat abase, w hich w e w ill t hen m odify t o support t he new feat ures.
Th e sh oppin g ca r t m ode l
The shopping cart m odel is a sim plified flow of inform at ion t hat happens in all online shopping car t im plem ent at ions, and is t he basis for our online car t .
We t hen have four basic m odules in our applicat ion:
z I t em Cat alog - Here w e display t he opt ions t o our client s in an or ganized w ay.
z I t em Det ails - Here w e show t he client as m uch info as w e can t o show off our product . z Shopping Cart - Here w e m anage t he user's select ed it em s.
z Checkout Syst em - Her e w e save t he it em s select ed and t he client 's infor m at ion t o close t he t ransact ion.
We w ill build addit ional feat ures inside t he " it em det ails" m odule by coding new user cont rols and sim ply include t hem in t he Web Form .
The adm inist rat ion console w ill cont rol t he inform at ion in t he dat abase. I t w ill not have any influence on t he shopping cart m odel, as it w ill act as a back end.
Th e da t a ba se m ode l
The t ables ar e gr ouped as follow s:
z Green - The cat alog part of our applicat ion. z Blue - I t em det ails.
z Orange - Shopping cart basket . z Yellow - The checkout syst em .
The new feat ures of our applicat ion w ill have t o int eract w it h t his exist ing dat abase schem a. The det ails w ill be discussed aft erw ards.
Th e j ob a h e a d
D e fin in g ou r n e w r e qu ir e m e n t s
As in every soft w are developm ent cycle, w e need t o define our requirem ent s first , so t hat w e can design soft w ar e capable of giving sat isfact ion t o our cust om ers.
Our online shopping cart applicat ion should add t he follow ing feat ures:
z I nclude a cust om er rat ing com ponent .
z An adm inist r at ion console t o m odify t he exist ing infor m at ion for t he cat alog sect ion / subsect ion, it em s and have a list of orders.
z The adm inist rat ion console should allow regist ered users only t hrough a login screen. z The console should also provide a way t o m anage t hese users.
z The sit e should im plem ent SSL encrypt ion in t he back end for securit y. z The shopping cart should also accept online t ransact ions t hrough t he web.
Th e cu st om e r r a t in g fe a t u r e
This w ill be a new feat ure t o int egr at e int o t he exist ing w ebsit e. The goal of t his part of t he art icle is t o show how easy it is t o develop new funct ionalit y int o exist ing websit es using t he ASP. Net fram ew ork.
This new feat ure requires us t o develop a new user cont rol t o im plem ent t he funct ionalit y. This will be
uc_item_rating.ascx, used to display the existing comments and add new ones.
D a t a ba se m odifica t ion s
The dat abase needs t o be m odified t o accom m odat e t he new feat ure. We j ust need t o add a new t able and a relat ionship t o t he it em t able.
N e w con t r ols
Our Web Applicat ion is m ade up of user cont rols. We do t his t o im plem ent funct ionalit y in a m odular fashion. I t is now t im e t o ext end our im plem ent at ion. We w ill add a new user cont rol t o hold t he new funct ionalit y. This cont r ol will present t he list of user reviews, and provide a form t o add new com m ent s. I t will be added w it h t he follow ing code:
Regist ered in t he page:
<%@ Register TagPrefix="SC" TagName="ItemRating" Src="uc_item_rate.ascx" %>
And included in t he page body:
<SC:ItemRating runat="server" />
Code be h in d cla sse s
The code t o achieve t he desired behavior resides in t he UcI t em Rat ing class. The follow ing code populat es t he rat ing list and calculat es t he average rat ing for t he select ed it em :
int myItemId = 0;
if (Request.QueryString["itemId"] != null)
{
myItemId = Int32.Parse(Request.QueryString["itemId"]);
}
//Bind the rating list
string SQLQuery = "SELECT itemRatingAuthor, itemRatingComment, itemRatingRate FROM itemR
WHERE itemId = " + myItemId.ToString() + " ORDER BY itemRatingId ASC";
String connString = ConfigurationSettings.AppSettings["connString"];
SqlConnection myConnection = new SqlConnection(connString);
SqlDataAdapter myCommand = new SqlDataAdapter(SQLQuery, myConnection);
myCommand.Fill(ds, "itemRating");
MyRatingList.DataSource = new DataView(ds.Tables[0]);
MyRatingList.DataBind();
//Calculate the average rating for the item
string strSelect = "SELECT itemRatingRate AS rate FROM itemRating";
myConnection = new SqlConnection(connString);
lblRating.Text = "Average Rating: " + rate.ToString();
The follow ing code adds a new user rat ing t o t he list .
//Retreive new Id from main order table
string strSelect = "SELECT COUNT(itemRatingId) AS myId FROM itemRating";
SqlConnection myConnection = new SqlConnection(connString);
//Add new order to the main order table
itemRatingAuthor, itemRatingComment, itemRatingRate) "
+ "VALUES (" + newRateId.ToString() + ", "
+ "" + myItemId.ToString() + ","
+ "'" + author + "',"
+ "'" + comment + "',"
+ "" + rate.ToString() + ")";
myConnection = new SqlConnection(connString);
myCommand = new SqlCommand(strInsert, myConnection);
myConnection.Open();
int queryResult = myCommand.ExecuteNonQuery();
myConnection.Close();
txtAuthor.Text = "";
txtComment.Text = "";
Radio1.Checked = false;
Radio2.Checked = true;
Radio3.Checked = false;
BindRatingList();
Fin a l scr e e n s
Finally our it em screen should look like t his:
Th e a dm in ist r a t ion con sole
The adm inist rat ion console consist s of t he pages needed t o keep t he sit e up t o dat e. Adm inist rat ion pages should be developed for each t able in t he dat abase t hat is t o be adm inist ered t hrough t he web. We will present t he developm ent of such a page for t he it em t able.
Th e u se r con t r ols
We w ill develop several cont rols for t his page. These cont rols cont ain specific funct ionalit y and are t he building blocks of our Web Form . The cont r ols ar e t he follow ing:
z
uc_admin_menu.ascx
- Displays a list of cat egories.z
uc_admin_item.ascx
- Displays t he list of it em s for t he select ed cat egory and provides a form t o add new it em s t o t hat cat egory. This w ill be used when we need t o display t he list of it em s and add new it em s. zuc_admin_item_edit.ascx
- Pr ovides a form t o m odify t he infor m at ion for t he select ed it em . This w ill beused w hen w e w ant t o see t he it em 's det ails and m odify t hem .
Th e code be h in d cla sse s
We have a couple of user cont rols t hat handle t he inform at ion for t he it em s in t he st ore. The first displays t he list of subsect ions and t he list of it em s in t he select ed subsect ion. I t allow s us t o add a new it em t o t he st or e. The second user cont rol displays a form w it h t he select ed it em inform at ion t hat allows us t o edit t he inform at ion of t he it em . I t also enables us t o delet e t he it em .
Th e it e m list
of our code is in charge of adding cont ent t o it .
<asp:DataList id="MyProductList" runat="server"
BorderColor="black"
HeaderStyle-BackColor="#aaaadd"
SelectedItemStyle-BackColor="Gainsboro"
RepeatDirection = "Horizontal"
<td width=600 colspan=2><a href='admin_item_mod.aspx?subSectionId=<%# DataBinde
"catalogSubSectionId") %>&itemId=<%# DataBinder.Eval(Container.DataIte
%>'><span class="itemText">Edit / Delete</span></a></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item Id:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemId")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item name:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemName")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item short descripcion:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemShortDescription")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item long descripcion:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemLongDescription")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item small image:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemSmallImage")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item large image:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemLargeImage")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item price:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemPrice")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Item Stock:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemStock")
%></span></td>
</tr>
<tr>
<td width=300><span class="itemTitle">Promote in Category Home:</span></td>
<td width=300><span class="itemText"><%# DataBinder.Eval(Container.DataItem,
"itemPromoteCategory")
%></span></td>
</tr>
<tr>
"itemPromoteSite")
%></span></td>
string SQLQuery = "SELECT * FROM item WHERE catalogSubSectionId=" + subSectionId
+ " ORDER BY catalogSubSectionId, itemName";
String connString = ConfigurationSettings.AppSettings["connString"];
SqlConnection myConnection = new SqlConnection(connString);
SqlDataAdapter myCommand = new SqlDataAdapter(SQLQuery, myConnection);
DataSet ds = new DataSet();
myCommand.Fill(ds, "item");
MyProductList.DataSource = new DataView(ds.Tables[0]);
MyProductList.DataBind();
protected void AddItem_Click(object Source, EventArgs e)
{
if (Request.QueryString["subSectionId"] != null)
{
string strSelect = "SELECT MAX(itemId) AS myId FROM item";
SqlCommand myCommand = new SqlCommand(strSelect, myConnection);
myConnection.Open();
SqlDataReader dr = myCommand.ExecuteReader();
int newId = 0;
string strInsert = "INSERT INTO item(itemId, catalogSubSectionId, itemName, itemSh
itemLongDescription, itemSmallImage, itemLargeImage, itemPrice, itemStock, ite
itemPromoteSite) "
+ "VALUES(" + newId + ", " + Request.QueryString["subSectionId"] + ", '"
+ itemName + "', '" + shortDesc + "', '" + longDesc + "', '" + smallIm
+ "', '" + largeImg + "', " + price + ", " + stock + ", "
+ myPromoteCategory + ", " + myPromoteSite + ")";
myConnection = new SqlConnection(connString);
myCommand = new SqlCommand(strInsert, myConnection);
myConnection.Open();
int queryResult = myCommand.ExecuteNonQuery();
myConnection.Close();
BindProductList(Request.QueryString["subSectionId"]);
}
protected void EditItem_Click(object Source, EventArgs e)
{
}
String connString = ConfigurationSettings.AppSettings["connString"];
SqlConnection myConnection = new SqlConnection(connString);
string strUpdate = "UPDATE item "
+ "SET catalogSubSectionId=" + Request.QueryString["subSectionId"]
+ ", itemName='" + itemName + "', itemShortDescription='" + shortDesc
+ "', itemLongDescription='" + longDesc + "', itemSmallImage='"
+ smallImg + "', itemLargeImage='" + largeImg + "', itemPrice=" + pric
+ ", itemStock=" + stock + ", itemPromoteCategory=" + myPromoteCategor
+ ", itemPromoteSite=" + myPromoteSite + ""
+ "WHERE itemId=" + Request.QueryString["itemId"];
SqlCommand myCommand = new SqlCommand(strUpdate, myConnection);
myConnection.Open();
int queryResult = myCommand.ExecuteNonQuery();
myConnection.Close();
Response.Redirect("admin_item.aspx?subSectionId=" + Request.QueryString["subSectio
Response.End();
protected void DeleteItem_Click(object Source, EventArgs e)
{
if (Request.QueryString["subSectionId"] != null &&
Request.QueryString["itemId"] != null)
{
String connString = ConfigurationSettings.AppSettings["connString"];
SqlConnection myConnection = new SqlConnection(connString);
string strDelete = "DELETE FROM item WHERE itemId=" +
Request.QueryString["itemId"];
SqlCommand myCommand = new SqlCommand(strDelete, myConnection);
myConnection.Open();
int queryResult = myCommand.ExecuteNonQuery();
myConnection.Close();
Response.Redirect ("admin_item.aspx?subSectionId=" +
Request.QueryString["subSectionId"]);
Response.End();
}
Th e fin a l scr e e n s
This is how our adm inist rat ion page looks. We achieve t his final screen by including our user cont rols int o t he Web Form . This process is like bolt ing new equipm ent ont o t he sit e. This m odular design enables us t o r euse pieces of code and m akes t he building process m uch m ore m odular.
This screen ( below) shows t he Web Form m aking use of t he
uc_admin_item.ascx
and t heuc_admin_item.ascx
user cont rols t o display t he list of m enus and t he list of it em s in t he cat egor y, as w ell as t he add new form .The it em list and Add feat ure:
The Edit / Delet e page:
Se t t in g u p se cu r it y for y ou r se r v e r
A very im port ant aspect t hat m ust be solved befor e you expect t o ask for users' privat e infor m at ion is secur ing your server's connect ion t o t he I nt ernet .
As inform at ion t ravels from t he user's com put er t o your server t hrough t he I nt ernet w ires, it is exposed t o m alicious users t hat could " sniff" int o t he dat a and ret rieve som e vit al inform at ion like credit card num bers.
im port ant inform at ion is t r ansm it t ed bet w een t he client and t he host .
For m ore inform at ion on encrypt ion, please see Richard Conw ay's art icle on Crypt ography - part 1 (ht t p: / / w w w .cshar pt oday.com / cont ent / ar t icles/ 20010823.asp) and part 2
(ht t p: / / w w w .cshar pt oday.com / cont ent / ar t icles/ 20010830.asp) .
This diagram show s t he effect s of having an encrypt ed channel t o t ransm it dat a. The sniffer is unable t o ret rieve useful inform at ion from t he w ires bet ween t he server and your client s.
Now t hat w e know how encrypt ion w orks, w e need t o incorporat e t his encrypt ion for our sit e. We get t his encrypt ion key from a t hird part y vendor, for exam ple Verisign (ht t p: / / w ww.verisign.com) . I nst allat ion of t he key is ver y st r aight forw ard, and Ver isign provides com plet e w alkt hroughs at
ht t p: / / w ww.verisign.com / product s/ sit e/ index.ht m l. Once t he key is up and running in your ser ver , you w ill only need t o redirect your Web Form s t o use ht t ps w here vit al inform at ion is t r ansm it t ed.
z Creat e an encrypt ion key for your server.
z Request t he act ivat ion of your encrypt ion key from Verisign. z I nst all t he key int o your server and configure I I S t o m ake use of it .
z Rout e you im port ant inform at ion t hrough ht t ps by m aking your post / get form s go t hrough ht t ps: / / yourser ver.com / t est .aspx, inst ead of j ust ht t p: / / yourserver.com / t est .aspx.
Det ails on t he first t hree st eps are available in t he Ver isign sit e at t he URL pr ovided above. This includes a det ailed st ep by st ep guide t o inst alling a SSL key t o your server.
Re ce iv in g pa y m e n t fr om cu st om e r s
So w e have a nice online st or e, w e have a secur e connect ion t o pr ot ect our cust om ers, but w e ar e st ill m issing t he part t hat lead us t o build an online st ore in t he first place! We need t o receive paym ent for t he product s w e are selling.
There are m any w ays t o do t his. I n t he early days, w e w ould j ust receive t he raw dat a for t he order and process it m anually. This involved shipping and handling t he product , and perform ing a charge t o t he cr edit car d, usually w it h a regular credit card m erchant , by forcing a t ransact ion w it h t he num ber pr ovided by t he client .
Wit h t oday's t echnology, w e have m or e possibilit ies. We w ill discuss a couple of approaches t hat are available from t hird part ies on t he Web. These services can be grouped as follow s:
z Services t hat receive inform at ion from you sit e for processing
z Services t hat provide special API s t o handle t he t ransact ions wit hin your syst em .
Se r v ice s t h a t r e ce iv e in for m a t ion fr om y ou r sit e for pr oce ssin g
These kinds of services provide you wit h access t o a predefined infrast ruct ure w it hin t heir servers. This w orks in a w ay in w hich you send a form w it h specific fields t o t heir servers, and t hey t ake cont rol of t he w hole t ransact ion for you.
Paypal (ht t p: / / w ww.paypal.com) is a t hird part y vendor t hat offers t his service. I t does so by host ing an account w it h t hem , and post ing inform at ion t o t he appropriat e request handlers of t heirs. There you will be present ed wit h a st andard int erface ( for w hich you can alt er t he st yle) for handling t he pay t ransact ion. I f t he t ransact ion went out successfully, t here will be a new it em in your or der s list for you t o ship.
This is a very sim ple solut ion for t he developer , since you are free of im plem ent ing t he checkout syst em for your applicat ion. This is done ent irely on Paypal's servers, w hich m anage t he shipping calculat ion, credit card charge, securit y and order adm inist rat ion. A t our of t he ser vice can be found at t he follow ing URL
(ht t p: / / w ww.paypal.com / cgi- bin/ w ebscr?cm d= p/ xcl/ rec/ sc- out side) where det ails of t he buying process are present ed.
Det ails and price for t his kind of service vary from vendor t o vendor but t he concept is t o fr ee you fr om t he paym ent t rouble, and concent rat e in building a bet t er sit e t o at t r act m or e cust om ers.
Her e ar e t he pr os and cons for t his approach:
Pros:
z Easy t o im plem ent
z Sim ple, easy t o follow process
Cons:
z St andard user int erface
z None or lim it ed cust om izat ion on t he paym ent process
z Usually share servers wit h ot hers which leads t o a lim it ed num ber of t ransact ions and perform ance lim it at ions
Se r v ice s t h a t pr ov ide spe cia l API s t o h a n dle t h e t r a n sa ct ion s w it h in y ou r sy st e m .
Cybercash (ht t p: / / w ww.cybercash.com) is an exam ple of one of t hese services providers. I t gives you a set of API s and docum ent at ion, which you can use t o develop your checkout syst em . This put s t he responsibilit y on t he developm ent t eam , but also gives t hem t he possibilit y t o creat e t he solut ion t hat best fit s t he needs of t he client . For com plet e docum ent at ion on how t o develop a solut ion w it h Cybercash, go t o t his URL
(ht t ps: / / w w w .verisign.com / cgi- bin/ go.cgi?a= b183338890612000) .
Her e ar e t he pr os and cons for t his approach:
Pros:
z Com plex API gives you t he pow er t o develop your ow n solut ion
z Gives you direct int eract ion wit h t he syst em which gives you m uch m or e det ails on t he t r ansact ion. z Can have m ore cont rol over t he inst alled plat form and can scale t o lar ger sit es
Cons:
z You need t o develop t he w hole checkout syst em w hich can be expensiv e and t im e consum ing z Need for ser ver capable of support ing t he API and securit y.
W r a ppin g u p
We have looked at t he t w o basic approaches t hat are offered on t he w eb for paym ent solut ions. One set s you up w it h a pr edefined solut ion, w hich you use out of t he box. The ot her provides you w it h an API for you t o creat e your ow n solut ion.
Paypal is basically a packaged product t hat w orks out of t he box and pr ovides sat isfact ion t o m ost of our needs in a fast non- expensive w ay ( alt hough t here are som e sm all fees involved) . On t he ot her hand, services like Cybercash, w hich provide com plex API s for developm ent , gives us t he freedom of developing a m ore cust om ized solut ion.
The Cybercash t ype of services provides t he com plet e set of t ools needed t o creat e our applicat ion. This is best suit ed for pr oj ect s w here com plex order m anagem ent is required and need t o be developed specifically for t he occasion.
There are m any m ore providers of t his t ype of service out t here. We can see t hat t hey can range from a sim ple solut ion t o m ore robust st at e of t he art API s, so t he decision as t o which service t o choose lies wit hin t he developer's specific needs. You need t o balance t he pros and cons of t he vendor and evaluat e w hich is bet t er.
I n st a llin g t h e n e w v e r sion
Once w e have finished t he second part of our developm ent , we need t o deploy t he changes. We have t w o choices here, an upgrade or a new inst all.
The upgrade pat h will be needed if you int end t o im plem ent t he changes on t op of t he code from part 1 of t his art icle. This w ill have t o be a t ot ally new inst allat ion of t he sit e. Files ar e included for bot h pat hs in t he dow nloadable zip file.
Upgr a de
The st eps needed t o do t he upgrade are t he following:
z Run t he
upgrade.sql
script t o build t he new it em review t able, and add an adm inist rat or user w it h t he usernam e " adm in" and t he passw ord " adm in" .z Copy t he
uc_item_rating.ascx
user cont rol t o t he root folder of your applicat ion t o be w it h t he rest of t he cont rols and Web Form s.z Copy t he adm inist rat ion folder int o your root folder so t he files exist in
http://yourserver/yourapp/admin
.N e w in st a ll
The st eps needed t o do a new inst all are as follow s:
z Once w e have cr eat ed t he dat abase, w e need t o run t he dat abase creat ion scr ipt
newinstall.sql
, which will t o m anage t he inform at ion in our online st ore. We have also discussed som e t hird part y services t o handle real-t im e online real-t ransacreal-t ions and I nreal-t ernereal-t securireal-t y.Never t heless, t here is st ill m uch room for im provem ent .
One of t he coolest feat ures nowadays are cust om er m anagem ent syst em s. These incorporat e ideas present ed before like relat ed it em s, user account s, m ailing list s and adds upon t hem . I t is up t o you t o build t he appr opriat e cust om feat ures t o fit your needs.
As for t echnology, w e should also im plem ent som e best pract ices, like building upon com ponent s t o achieve code reuse, and also t he use of st ored procedures. All t his left out for sim plicit y.
Con clu sion s
This concludes a t w o- part art icle t hat show ed how t o creat e an online shopping cart from scrat ch. We have developed a cat alog / sect ion sit e t o display our product s. This w as furt her enhanced w it h an it em r at ing user cont rol in part t w o, and an adm inist r at ion console w as also developed t o m anage t he inform at ion of t he online st ore. We t hen discussed som e securit y and paym ent issues and analyzed t he resources needed t o solve t hem .
Our applicat ion is now capable of handling real w orld use and w ill provide a valuable fram ew ork for furt her developm ent .
z dat abase t able, m odifying z Dat aList cont rol
z DELETE st at em ent
z UPDATE st
z user cont r o
z VeriSign z w eb form s
H OM E | SI TE M AP | I N D EX | SEARCH | REFEREN CE | FEED BACK | AD V ERTI S
Ecom m erce Perform ance Securit y Sit e Design XML SO
Dat a Access/ ADO.NET Applicat ion
Developm ent Web Services Graphics/ Gam es Mobile Ot her Technologies
C# Today is brought t o you by Wrox Press (w w w .w rox.com) . Please see our t erm s and condit ions and privacy C# Today is opt im ised for Microsoft I nt ernet Explorer 5 brow sers.