<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0MFR3s-eSp7ImA9WhVRE0w.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868</id><updated>2012-03-21T00:36:56.551-07:00</updated><category term="C#" /><category term="vs.net" /><category term="PHP" /><category term="android" /><category term="appengine" /><category term="javascript" /><category term="windowsmobile" /><category term="java" /><category term="sso" /><category term="development" /><category term="webdesign" /><category term="asp.net" /><category term="codecharge studio" /><category term="dojo/dijit" /><category term="learning" /><category term="RSS/Atom" /><category term="WinForms" /><title>Developer's Corner</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.developer-corner.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.developer-corner.com/" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/developer-corner/mhSH" /><feedburner:info uri="developer-corner/mhsh" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;AkYGQn07fyp7ImA9WhZbEkk.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-3051489982311484200</id><published>2011-06-16T11:06:00.001-07:00</published><updated>2011-06-16T11:15:23.307-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-16T11:15:23.307-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="android" /><category scheme="http://www.blogger.com/atom/ns#" term="appengine" /><title>MyEclipseG: simplifying AppEngine and Android development</title><content type="html">&lt;p&gt;&lt;a href="http://www.myeclipseide.com" target="_blank"&gt;&lt;a href="http://lh3.ggpht.com/-3u6Ybvg0kVM/TfpIDebLdZI/AAAAAAAAC-0/Qz-4q81QPMk/s1600-h/myeclipseg%25255B2%25255D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 7px 12px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="myeclipseg" border="0" alt="myeclipseg" align="left" src="http://lh6.ggpht.com/-KTML07N4h1w/TfpIDx1oyyI/AAAAAAAAC-4/pM50UMc74hg/myeclipseg_thumb.jpg?imgmax=800" width="244" height="59"&gt;&lt;/a&gt;MyEclipseIDE&lt;/a&gt; is a commercial Eclipse plugin providing a rich set of features, which enables Java developers to write JSF, JEE, Struts, Ajax, Spring applications more easily, by providing wizards, helpers, tools and editors. The (very long) list of features is available &lt;a href="http://www.myeclipseide.com/module-htmlpages-display-pid-1.html" target="_blank"&gt;here&lt;/a&gt;.&lt;a href="http://www.myeclipseide.com" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 7px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="android" border="0" alt="android" align="right" src="http://lh6.ggpht.com/-qNRtkWrf-SU/TfpIESXiiWI/AAAAAAAAC-8/taJR8njSEOU/android%25255B3%25255D.jpg?imgmax=800" width="104" height="104"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Genuitec, the company behind MyEclipse, is currently working on a brand new product targeted to AppEngine and Android developers, that on paper looks very interesting, and featuring:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;GWT code generation &lt;/li&gt; &lt;li&gt;Native Android application generation &lt;/li&gt; &lt;li&gt;AppEngine persistence generation &lt;/li&gt; &lt;li&gt;Generation of a complete web application from an AppEngine data store &lt;/li&gt; &lt;li&gt;Integration with &lt;a href="http://code.google.com/p/google-guice/" target="_blank"&gt;Guice&lt;/a&gt; (lightweight and open source dependency injection framework, powered by Google) &lt;/li&gt; &lt;li&gt;Annotation editor for Objectify &amp;amp; JPA &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;and much more.&lt;a href="http://lh3.ggpht.com/-frCmd3y8Fhs/TfpIFE6I8uI/AAAAAAAAC_A/qYEPq-eA0p0/s1600-h/google_appengine%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 7px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="google_appengine" border="0" alt="google_appengine" align="right" src="http://lh5.ggpht.com/-9Vm4ba7iqiI/TfpIFjWYGzI/AAAAAAAAC_E/PR52D2w2mVw/google_appengine_thumb%25255B1%25255D.png?imgmax=800" width="104" height="104"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The plugin is still under development, and not publicly available, but anyone can register for the early access program, currently with limited availability. For more information, take a peek at the &lt;a href="http://www.myeclipseg.com/" target="_blank"&gt;MyEclipseG&lt;/a&gt; website.&lt;/p&gt; &lt;p&gt;A “Get Your Apps on the Google Cloud” webinar will also be available soon at &lt;a href="http://www.myeclipseide.com/module-htmlpages-display-pid-352.html?name=webinars" target="_blank"&gt;this page&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-3051489982311484200?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/IpjKzAo2l_IcPIQMrRUMAtJGoIU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IpjKzAo2l_IcPIQMrRUMAtJGoIU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/IpjKzAo2l_IcPIQMrRUMAtJGoIU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IpjKzAo2l_IcPIQMrRUMAtJGoIU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/fgKT9o7k2G4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/3051489982311484200/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2011/06/myeclipseg-simplifying-appengine-and.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3051489982311484200?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3051489982311484200?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/fgKT9o7k2G4/myeclipseg-simplifying-appengine-and.html" title="MyEclipseG: simplifying AppEngine and Android development" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-KTML07N4h1w/TfpIDx1oyyI/AAAAAAAAC-4/pM50UMc74hg/s72-c/myeclipseg_thumb.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2011/06/myeclipseg-simplifying-appengine-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YHSHo4eyp7ImA9WhZUFU0.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-1862016569494432190</id><published>2011-06-06T02:41:00.001-07:00</published><updated>2011-06-07T21:58:59.433-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-07T21:58:59.433-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="dojo/dijit" /><title>Cloning Dijit widgets</title><content type="html">&lt;p&gt;Dojox and Dijit widgets are undoubtedly cool, bringing a richer user experience to your web site.&lt;/p&gt; &lt;p&gt;One of their drawback though is that they are not easily cloneable. A typical example is for instance a table with a set of controls per row and a “Add new row” button, allowing to add a new row to the table.&lt;/p&gt; &lt;p&gt;This article provides a simple solution to clone a table row containing dijit widgets.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt; &lt;h3&gt;The problem&lt;/h3&gt; &lt;p&gt;I've recently started using dojo and dijit to provide some cool user interface experience on a project I am working on.&lt;/p&gt; &lt;p&gt;During implementation I've faced with a problem: I have a table with a set of widgets on each row, initially with a single row, but with the user able to add as many rows as he needs. Unfortunately&lt;em&gt; there is no (native) way to clone a dijit widget&lt;/em&gt;, so I had to find a different solution.&lt;/p&gt;I am using the declarative approach of creating dijit widgets, by adding some dijit related attributes to input controls and let the dojo parser convert them from normal input controls to dijit widgets. For instance, the following input textbox: &lt;pre class="brush: c-sharp; toolbar: false"&gt;&amp;lt;input type='text' dojoType='dijit.form.ValidationTextBox' /&amp;gt;&lt;/pre&gt;
&lt;p&gt;is parsed by dojo and converted into a ValidationTextBox widget like this:&lt;/p&gt;&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;div
	class="dijit dijitReset dijitInlineTable dijitLeft dijitTextBox dijitValidationTextBox"
	id="widget_dijit_form_ValidationTextBox_0" role="presentation"
	dir="ltr" widgetid="dijit_form_ValidationTextBox_0"&amp;gt;
	&amp;lt;div class="dijitReset dijitValidationContainer"&amp;gt;
		&amp;lt;input
			class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner"
			value="Χ" type="text" tabindex="-1" readonly="readonly"
			role="presentation"&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div class="dijitReset dijitInputField dijitInputContainer"&amp;gt;
		&amp;lt;input class="dijitReset dijitInputInner"
			dojoattachpoint="textbox,focusNode" autocomplete="off" type="text"
			id="dijit_form_ValidationTextBox_0" tabindex="0" value=""&amp;gt;
	&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;Conversion from html control to dijit widget can be performed either automatically, by specifying the &lt;code&gt;djconfig='parseOnLoad:true'&lt;/code&gt; parameter when loading the dojo script:&lt;/p&gt;&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js' djconfig='parseOnLoad:true'&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;or manually, by calling the &lt;code&gt;dojo.parser.parse()&lt;/code&gt; function, most likely in &lt;code&gt;addOnLoad()&lt;/code&gt;. 
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;The solution&lt;/h3&gt;
&lt;p&gt;The idea behind the solution I’ve found out can be summarized as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;read the table row &lt;strong&gt;before&lt;/strong&gt; conversion from input control to dijit widget occurs and save its html code in a safe place 
&lt;li&gt;reuse the table row as a template to clone new table rows, and apply the dojo parsing on it for input to widget conversions&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;In order to work, row cloning must be done &lt;em&gt;before&lt;/em&gt; the dojo parsing occurs.&lt;/p&gt;
&lt;p&gt;This is the raw html form we’ll work on:&lt;/p&gt;&lt;pre class="brush: xhtml"&gt;&amp;lt;form dojoType='dijit.form.Form' id='form'&amp;gt;
	&amp;lt;input type='hidden' value='1' id='hRowsCounter' /&amp;gt;

	&amp;lt;input type='button' id='btnAddNewRow' value='Add new row'  label='Add new row' dojoType='dijit.form.Button' /&amp;gt;
	
	&amp;lt;table id='table'&amp;gt;
		&amp;lt;thead&amp;gt;
			&amp;lt;tr&amp;gt;
				&amp;lt;td&amp;gt;Quantity&amp;lt;/td&amp;gt;
				&amp;lt;td&amp;gt;Unit Price&amp;lt;/td&amp;gt;
		&amp;lt;/thead&amp;gt;
		&amp;lt;tbody&amp;gt;
			&amp;lt;tr id="row-1"&amp;gt;
				&amp;lt;td&amp;gt;&amp;lt;input type='text'  id='editQuantity1' dojoType='dijit.form.NumberSpinner' required='true' /&amp;gt;&amp;lt;/td&amp;gt;
				&amp;lt;td&amp;gt;&amp;lt;input type='text'  id='editUnitPrice1' dojoType='dijit.form.CurrencyTextBox' required='true' /&amp;gt;&amp;lt;/td&amp;gt;
			&amp;lt;/tr&amp;gt;
		&amp;lt;/tbody&amp;gt;
	&amp;lt;/table&amp;gt;
	&amp;lt;input type='submit' value='Submit' label='Submit' dojoType='dijit.form.Button'  /&amp;gt;
&amp;lt;/form&amp;gt;&lt;/pre&gt;
&lt;p&gt;The hidden field is used to keep track of the total number of rows, used both locally to generate the identifiers of the cloned controls and at server side, to let the web application know in advance how many rows to process.&lt;/p&gt;
&lt;p&gt;The table row is made up of 2 dijit widgets, NumberSpinner and CurrencyTextBox,&amp;nbsp; but of course the same principle applies to any other dijit or dojox widget.&lt;/p&gt;
&lt;p&gt;This form “as is” is rendered by the browser as a standard html form, not powered by dijit yet, and it should look like the following:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-h8jYxhfAhAI/TezHKNnXlZI/AAAAAAAACxc/XwUvGA2t7GE/s1600-h/standard%252520form%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="standard form" border="0" alt="standard form" src="http://lh5.ggpht.com/-ciYpSaZ2WGI/TezHK-LJHTI/AAAAAAAACxg/bBJ9UF98k2g/standard%252520form_thumb%25255B1%25255D.png?imgmax=800" width="345" height="116"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In order to perform the enhancement, we need some javascript code. First of all, we need to load the dojo library in the &amp;lt;head&amp;gt; section, along with jquery, which I’m going to use as I feel more familiar with:&lt;/p&gt;&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;head&amp;gt;
	&amp;lt;script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js' djconfig='parseOnLoad:false'&amp;gt;&amp;lt;/script&amp;gt;
	&amp;lt;script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;&lt;/pre&gt;
&lt;p&gt;Notice the parseOnLoad parameter explicitly set to false, to prevent automatic dojo parsing of the body, precondition needed for the solution to work. Following the javascript code to enhance the standard html form into a widget based dijit form.&lt;/p&gt;&lt;pre class="brush: javascript"&gt;&amp;lt;script type='text/javascript'&amp;gt;
	dojo.require('dijit.form.Form');
	dojo.require('dijit.form.Button');
	dojo.require('dijit.form.CurrencyTextBox');
	dojo.require('dijit.form.NumberSpinner');

	dojo.addOnLoad(function() {

		// Parse the body to convert input controls into dojox/dijit widgets
		dojo.parser.parse(dojo.body());
		
		dojo.connect(dijit.byId('btnSubmit'), 'onClick', function(e) {
			dijit.byId('form').submit();
		});
		
		dojo.connect(dijit.byId('form'), 'onSubmit', function(e) {
			return this.validate();
		});
	});	
&amp;lt;/script&amp;gt;&lt;/pre&gt;
&lt;p&gt;After adding the above code to our page, the form is now visibly different:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-OVzno-msBEA/TezHLUTFe6I/AAAAAAAACxk/F1fLL8Mn6m0/s1600-h/enhanced%252520form%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="enhanced form" border="0" alt="enhanced form" src="http://lh3.ggpht.com/-KfSLivy-XkM/TezHMJ7WPMI/AAAAAAAACxo/8BVnzFetXc0/enhanced%252520form_thumb%25255B1%25255D.png?imgmax=800" width="513" height="128"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The final step is to implement the row addition. First we need to save the row template in the addOnLoad() event, prior to dojo parsing:&lt;/p&gt;&lt;pre class="brush: javascript; toolbar: false; highlight: [1, 5, 6]"&gt;var rowTemplate = null;

dojo.addOnLoad(function() {

	// Save the row template
	rowTemplate = $('#row-1').clone();
	
	// Parse the body to convert input controls into dojox/dijit widgets
	dojo.parser.parse(dojo.body());

	...
});	&lt;/pre&gt;
&lt;p&gt;Next we have to attach a click handler to the “Add new row” button:&lt;/p&gt;&lt;pre class="brush: javascript; toolbar: false; highlight: [19,20,21]"&gt;var rowTemplate = null;
	
dojo.addOnLoad(function() {

	// Save the row template
	rowTemplate = $('#row-1').clone();
		
	// Parse the body to convert input controls into dojox/dijit widgets
	dojo.parser.parse(dojo.body());
		
	dojo.connect(dijit.byId('btnSubmit'), 'onClick', function(e) {
		dijit.byId('form').submit();
	});
	
	dojo.connect(dijit.byId('form'), 'onSubmit', function(e) {
		return this.validate();
	});
		
	dojo.connect(dijit.byId('btnAddNewRow'), 'onClick', function(e) {
		addTableRow();
	});
});	&lt;/pre&gt;
&lt;p&gt;Last, the missing piece is the actual addTableRow() implementation:&lt;/p&gt;&lt;pre class="brush: javascript; highlight: [12,15,16,17,18,19,20]"&gt;function addTableRow() {
	// Retrieve the rows counter hidden control
	var hRowsCounter = $('#hRowsCounter');
	
	// Calculate the next row index
	var index = parseInt(hRowsCounter.val()) + 1;
	
	// Set the new row id
	var newRowId = 'row-' + index;

	// Clone the table row from the previously saved template
	var newRow = rowTemplate.clone().attr('id', newRowId);
	
	// Replace the id of each input control
	newRow.find('input').each(function() {
		var newId = $(this).attr('id').replace(/[\d]+$/g, index);
		$(this).val('');
		$(this).attr('id', newId)
		$(this).attr('name', newId);
	}).end().appendTo('#table');
	
	// Update the number of rows
	hRowsCounter.val(index);
	
	// Force a dojo parsing of hte newly created row 
	dojo.parser.parse(dojo.byId(newRowId));
}
&lt;/pre&gt;
&lt;p&gt;The actual row cloning is done at line 12, with contextual update of the row id.&lt;/p&gt;
&lt;p&gt;Lines 15 to 20 are used to locate all &amp;lt;input&amp;gt; controls in the newly created row and for each one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;calculate a unique control id (line 16) 
&lt;li&gt;reset the control value (line 17) 
&lt;li&gt;set the new control id (line 18) 
&lt;li&gt;set the control name (line 19)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The new control id is calculated by replacing the ending numbers in the control id with the row number, using a regular expression. If you look at the html form code, you’ll see that each control in the table has an id made up of a descriptive text (editQuantity) and a number, identifying the row. The regular expression locates the ending number, so it can be replaced with the new row number. Needless to say, this process is required to ensure that each control in the table has a unique id.&lt;/p&gt;
&lt;p&gt;Here is the final form, with some rows manually added to the table:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-I2bynjpDJmA/TezQAqlDVNI/AAAAAAAACxs/7sSHVOkUCtQ/s1600-h/enhanced%252520form%252520with%252520multiple%252520rows%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="enhanced form with multiple rows" border="0" alt="enhanced form with multiple rows" src="http://lh4.ggpht.com/-8dC3mUNo1zs/TezQBMaHloI/AAAAAAAACxw/RcOUDrsnSwc/enhanced%252520form%252520with%252520multiple%252520rows_thumb%25255B1%25255D.png?imgmax=800" width="507" height="185"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-1862016569494432190?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/DuksLKRmzSak7J4niRZV1ls5s3Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DuksLKRmzSak7J4niRZV1ls5s3Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/DuksLKRmzSak7J4niRZV1ls5s3Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DuksLKRmzSak7J4niRZV1ls5s3Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/8mfhLELtVss" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/1862016569494432190/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2011/06/cloning-dijit-widgets.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/1862016569494432190?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/1862016569494432190?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/8mfhLELtVss/cloning-dijit-widgets.html" title="Cloning Dijit widgets" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-ciYpSaZ2WGI/TezHK-LJHTI/AAAAAAAACxg/bBJ9UF98k2g/s72-c/standard%252520form_thumb%25255B1%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2011/06/cloning-dijit-widgets.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcERno4eyp7ImA9WhZUFUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-2322827306547869734</id><published>2009-07-27T22:05:00.000-07:00</published><updated>2011-06-07T22:13:27.433-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-07T22:13:27.433-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="windowsmobile" /><category scheme="http://www.blogger.com/atom/ns#" term="vs.net" /><title>Platform Verification Task leading to slow builds on compact framework projects</title><content type="html">&lt;p&gt;I've been experiencing an extremely high build time on a windows mobile project targeted to compact framework 2.0 before finding out what was responsible of such slowness. Fortunately solving this problem is as easy as adding a line to a configuration file.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;In a Windows Mobile project I'm currently working on I experienced a very slow compilation, and I've been struggling with this problem for weeks, until I found a very simple solution.&lt;/p&gt; &lt;p&gt;The project is an order entry application targeted for compact framework 2.0. As of now, it is a solution made up of 7 projects, 2 of which are executables and the other ones are libraries. The first thing I noticed is that slowness occurred on one project only: the data layer. I am using &lt;a title="LLBLGen Pro" href="http://www.llblgen.com/"&gt;LLBLGen Pro&lt;/a&gt;, a powerful O/R mapper that simplifies data layer development taking advantage of its visual designer and code generator. The complete list of assemblies referenced by my project is shown below:&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-1MpObBc4Ak4/Te8DSxPPaUI/AAAAAAAAC0c/x6JXxMZR80Y/s1600-h/image16.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="Project References" src="http://lh5.ggpht.com/-I188Qa7Upuo/Te8DTdCUhEI/AAAAAAAAC0g/bWne-O7E_Lo/image_thumb12.png?imgmax=800" width="321" height="203"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;I'm not sure whether the slowness is caused by the LLBLGen Pro or either of the System.Data.* assemblies, or maybe both. I just know that the same issue happened on Windows XP, Vista 64, using either Visual Studio 2005 and 2008. I've just reinstalled Vista Ultimate on my T61p yesterday, and at the first full build it took 30 to 60 seconds, whereas it should take just a few seconds. Fortunately I already know how to solve this issue, but I hope anyone having the same issue can find the solution here.&lt;/p&gt; &lt;p&gt;The most important hint came after enabling diagnostic build output (&lt;em&gt;Tools&lt;/em&gt; menu, &lt;em&gt;Options&lt;/em&gt;, &lt;em&gt;Projects and Solutions&lt;/em&gt;, &lt;em&gt;Build and Run&lt;/em&gt;, &lt;em&gt;MSBuild project build output verbosity&lt;/em&gt; option). After setting this property to Diagnostic, on next build I found the following statistics:&lt;/p&gt;&lt;pre&gt;Task Performance Summary:
        0 ms  RemoveDuplicates                           2 calls
        0 ms  GetDeviceFrameworkPath                     1 calls
        0 ms  Message                                    5 calls
        0 ms  AssignCulture                              1 calls
        0 ms  FindAppConfigFile                          1 calls
        0 ms  AssignTargetPath                          10 calls
        0 ms  MakeDir                                    1 calls
        0 ms  ResolveNonMSBuildProjectOutput             1 calls
        0 ms  GetFrameworkPath                           1 calls
        0 ms  Delete                                     1 calls
        1 ms  CreateProperty                             1 calls
        1 ms  ConvertToAbsolutePath                      1 calls
        1 ms  ReadLinesFromFile                          1 calls
       12 ms  Copy                                       6 calls
       20 ms  FindUnderPath                              5 calls
       32 ms  Csc                                        1 calls
       47 ms  MSBuild                                    3 calls
      110 ms  ResolveAssemblyReference                   1 calls
    18382 ms  PlatformVerificationTask                   1 calls

Build succeeded.

Time Elapsed 00:00:18.64&lt;/pre&gt;
&lt;p&gt;So it looks like the build spends 18 seconds on the "&lt;em&gt;Platform Verification Task&lt;/em&gt;". A good explanation about what this task is can be found in &lt;a title="Platform Verification Task" href="http://blogs.msdn.com/vsdteam/archive/2006/09/15/756400.aspx"&gt;this blog post&lt;/a&gt;, along with the solution (although I came to this blog post &lt;strong&gt;after&lt;/strong&gt; I found the solution elsewhere). In fact I simply need to disable the platform verification task, by editing the Microsoft.CompactFramework.common.targets file in the C:\Windows\Microsoft.NET\Framework\v3.5 folder. Once the file is opened using your favorite text editor (mine is &lt;a title="Notepad++" href="http://notepad-plus.sourceforge.net/"&gt;Notepad++&lt;/a&gt;), locate the &amp;lt;target&amp;gt; tag having the name attribute set to PlatformVerificationTask&lt;/p&gt;&lt;pre class="brush: xhtml"&gt;&amp;lt;Target
    Name="PlatformVerificationTask"&amp;gt;
    &amp;lt;PlatformVerificationTask
        PlatformFamilyName="$(PlatformFamilyName)"
        PlatformID="$(PlatformID)"
        SourceAssembly="@(IntermediateAssembly)"
        ReferencePath="@(ReferencePath)"
        TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
        PlatformVersion="$(TargetFrameworkVersion)"/&amp;gt;
&amp;lt;/Target&amp;gt;&lt;/pre&gt;
&lt;/span&gt;

&lt;p&gt;then add the Condition attribute to the PlatformVerificationTask tag as follows (the added line is the no. 4):&lt;/p&gt;&lt;pre class="brush: xhtml; highlight: [4]"&gt;&amp;lt;Target  
    Name="PlatformVerificationTask"&amp;gt;  
    &amp;lt;PlatformVerificationTask  
		Condition="'$(DoPlatformVerificationTask)'=='true'" &amp;lt;!-- Added --&amp;gt;
        PlatformFamilyName="$(PlatformFamilyName)"  
        PlatformID="$(PlatformID)"  
        SourceAssembly="@(IntermediateAssembly)"  
        ReferencePath="@(ReferencePath)"  
        TreatWarningsAsErrors="$(TreatWarningsAsErrors)"  
        PlatformVersion="$(TargetFrameworkVersion)"/&amp;gt;  
&amp;lt;/Target&amp;gt;&lt;/pre&gt;
&lt;p&gt;Last, save and restart Visual Studio. Now the PlatformVerificationTask is not reported in the build log any longer, but most important, a normal build takes less than a second and a rebuild just a couple of seconds.&lt;/p&gt;&lt;/span&gt;&lt;pre&gt;Task Performance Summary:
        0 ms  CreateProperty                             1 calls
        0 ms  ResolveNonMSBuildProjectOutput             1 calls
        0 ms  AssignTargetPath                          10 calls
        0 ms  ConvertToAbsolutePath                      1 calls
        0 ms  AssignCulture                              1 calls
        0 ms  FindAppConfigFile                          1 calls
        0 ms  Message                                    5 calls
        0 ms  RemoveDuplicates                           2 calls
        0 ms  Delete                                     1 calls
        0 ms  MakeDir                                    1 calls
        1 ms  GetDeviceFrameworkPath                     1 calls
        1 ms  GetFrameworkPath                           1 calls
        3 ms  Copy                                       6 calls
        6 ms  ReadLinesFromFile                          1 calls
       11 ms  FindUnderPath                              5 calls
       33 ms  Csc                                        1 calls
       53 ms  MSBuild                                    3 calls
       75 ms  ResolveAssemblyReference                   1 calls

Build succeeded.

Time Elapsed 00:00:00.22&lt;/pre&gt;
&lt;h4&gt;References&lt;/h4&gt;
&lt;p&gt;Visual Studio For Devices blog: &lt;a title="Platform Verification Task" href="http://blogs.msdn.com/vsdteam/archive/2006/09/15/756400.aspx"&gt;Platform Verification Task&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-2322827306547869734?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UaauVKJLTsvwIc1wiWpFZCguz_Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UaauVKJLTsvwIc1wiWpFZCguz_Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UaauVKJLTsvwIc1wiWpFZCguz_Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UaauVKJLTsvwIc1wiWpFZCguz_Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/dvSlRpVCfBU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/2322827306547869734/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2009/07/platform-verification-task-leading-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/2322827306547869734?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/2322827306547869734?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/dvSlRpVCfBU/platform-verification-task-leading-to.html" title="Platform Verification Task leading to slow builds on compact framework projects" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-I188Qa7Upuo/Te8DTdCUhEI/AAAAAAAAC0g/bWne-O7E_Lo/s72-c/image_thumb12.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2009/07/platform-verification-task-leading-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkACSXk9fyp7ImA9WhZUFk8.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-3514727814398560420</id><published>2009-06-30T21:59:00.000-07:00</published><updated>2011-06-09T04:59:28.767-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-09T04:59:28.767-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Casting from a base class to a derived class</title><content type="html">&lt;p&gt;Today a friend of mine asked me how to cast from List&amp;lt;&amp;gt; to a custom MyCollection class, where MyCollection is derived from List&amp;lt;&amp;gt;. Is this possible?&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;This morning a friend of mine asked me how to cast a &lt;a class="zem_slink" title="Generic programming" href="http://en.wikipedia.org/wiki/Generic_programming" rel="wikipedia"&gt;generic&lt;/a&gt; list to a custom class inherited from the generic list.&lt;/p&gt; &lt;p&gt;Let’s suppose we have the following class:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyClass
{
    ...
}&lt;/pre&gt;
&lt;p&gt;and we need a collection of instances of this class, for example using the generic List&amp;lt;&amp;gt; class&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;List&amp;lt;MyClass&amp;gt; myCollection;
&lt;/pre&gt;
&lt;p&gt;In order to improve readability, but also save time when writing code, we are often tempted to create a non-generic class implementing the list we need – even if we usually don’t really need such class&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyCollection : List&amp;lt;MyClass&amp;gt;
{
}&lt;/pre&gt;
&lt;p&gt;The problem arises when we use both the generic version and the custom version of the list in our code, and more specifically when we create an instance using the generic list and we need to pass this instance to a method expecting the custom version of the list:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;// This is the method we need to call
public void DoSomething(MyCollection myCollection)
{
	...
}

List&amp;lt;MyClass&amp;gt; myClass = new List&amp;lt;MyClass&amp;gt;();
DoSomething(myClass);							// This doesn't work&lt;/pre&gt;&lt;/span&gt;
&lt;p&gt;The code above generates an error during compilation, whereas a direct cast from List&amp;lt;MyClass&amp;gt; to MyCollection generates a runtime exception:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;List&amp;lt;MyClass&amp;gt; myList;
MyCollection myCollection;

myList = new List&amp;lt;MyClass&amp;gt;();
myCollection = (MyCollection) myList;	// This generates a runtime exception&lt;/pre&gt;
&lt;p&gt;The problem is that List&amp;lt;MyClass&amp;gt; is a base class and MyCollection is a derived class, hence there is no way to explicitly perform the cast.&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;p&gt;Let’s forget about lists and generics for a moment. We have to classes:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyBaseClass
{
    ...
}
 
 
public class MyDerivedClass : MyBaseClass
{
    ...
}&lt;/pre&gt;
&lt;p&gt;If I write the following code:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;MyBaseClass myBaseClass;
MyDerivedClass myDerivedClass;
 
myBaseClass = new MyBaseClass();
 
myDerivedClass = (MyDerivedClass) myBaseClass;    // This generates a runtime exception&lt;/pre&gt;
&lt;p&gt;The last statement obviously causes a runtime exception, as a downcast from a base class to a derived class cannot be done.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="code"&gt;&lt;code&gt;Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'MyBaseClass' to type 'MyDerivedClass'.&lt;br&gt;at Program.Main() &lt;/code&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;The reason is that a derived class (usually) extends the base class by adding more state objects (i.e. data members). When we create an instance of a base class, its data members are allocated in the memory, but of course data members of inherited classes are not allocated. So, downcasting from a base to a derived class is not possible because data members of the inherited class are not allocated.&lt;/p&gt;
&lt;p&gt;But if we instantiate MyBaseClass as MyDerivedClass the cast is allowed – in other words downcasting is allowed only when the object to be cast is of the same type it’s being cast to:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;myBaseClass = new MyDerivedClass();
 
myDerivedClass = (MyDerivedClass) myBaseClass;&lt;/pre&gt;
&lt;p&gt;This because myBaseClass, although being a variable of type MyBaseClass, is a reference to an instance of MyDerivedClass.&lt;/p&gt;
&lt;p&gt;In our problem, MyBaseClass is List&amp;lt;MyClass&amp;gt; and MyDerivedClass is MyCollection, so we are trying to cast an instance of a base class to an instance of a derived class. It’s evident why the cast we want to do is not allowed.&lt;/p&gt;
&lt;p&gt;So, is there a solution? If we think in terms of casting, the answer is &lt;strong&gt;NO&lt;/strong&gt;. What we can do is a conversion.&lt;/p&gt;
&lt;p&gt;The difference between cast and conversion is that the cast operates on the same object instance, whereas a conversion creates a new copy.&lt;/p&gt;
&lt;p&gt;We might think about implementing a conversion operator, either implicit or explicit, for instance:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyCollection : List&amp;lt;MyClass&amp;gt;
{
    public static implicit operator MyCollection(List&amp;lt;MyClass&amp;gt; myClass)
    {
        ...
    }
    ...
}
&lt;/pre&gt;
&lt;p&gt;but it won’t work, as the compiler generates a CS0553 error&lt;/p&gt;
&lt;blockquote&gt;'conversion routine' : user defined conversion to/from base class&lt;br&gt;User-defined conversions to values of a base class are not allowed; you do not need such an operator&lt;/blockquote&gt;
&lt;p&gt;The reason why the compiler denies such conversion is that the explicit &lt;em&gt;cast operator &lt;/em&gt;from a base to an derived class is automatically generated, and we can’t override it with a new &lt;em&gt;conversion operator&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The only viable solutions are either defining a copy constructor or implementing a method in the derived class which converts the base class to an instance of the derived class:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyCollection : List&amp;lt;MyClass&amp;gt;   
{   
    // Copy constructor   
    public MyCollection(List&amp;lt;MyClass&amp;gt; myList) : base (myList)   
    {   
        ...   
    }   
       
    // Conversion method   
    public static MyCollection ToMyCollection(List&amp;lt;MyClass&amp;gt; myList)   
    {   
        ...   
    }   
}  &lt;/pre&gt;
&lt;p&gt;In both cases, anyway, the conversion implies the creation of a new instance of the object to be converted.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-3514727814398560420?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HDchQq7QQ3vzHBkbvG5f9ds96Ck/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HDchQq7QQ3vzHBkbvG5f9ds96Ck/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HDchQq7QQ3vzHBkbvG5f9ds96Ck/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HDchQq7QQ3vzHBkbvG5f9ds96Ck/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/-Y03jocrtwM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/3514727814398560420/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2009/06/casting-from-base-class-to-derived.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3514727814398560420?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3514727814398560420?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/-Y03jocrtwM/casting-from-base-class-to-derived.html" title="Casting from a base class to a derived class" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2009/06/casting-from-base-class-to-derived.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMER3c6cCp7ImA9WhZUF0o.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-8544312609619057567</id><published>2009-02-07T07:26:00.000-08:00</published><updated>2011-06-10T23:40:06.918-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-10T23:40:06.918-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="webdesign" /><title>Choosing a web color scheme</title><content type="html">&lt;div align="left"&gt;&lt;/div&gt;When designing a web site, on of the problems I face with is how to choose colors. Usually I choose a base color, which is the predominant color used in the web design, but how to choose other colors, such as background, headings, panels, borders and so on?&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;My favorite tools for web design are Photoshop and Expression Design 2, plus Expression Web 2 and TopStyle for CSS/HTML editing. Topstyle has a nice feature in its color picker: given a color it suggests the complementary color&lt;br /&gt;
&lt;a href="http://lh5.ggpht.com/-d7Oa53yBO_4/Te79GHhCrGI/AAAAAAAACx0/UhEnj_tjfdk/s1600-h/image112.png"&gt;&lt;img alt="TopStyle - Complementary color." border="0" height="372" src="http://lh3.ggpht.com/-MW8b5VFTGAU/Te79HNEgxFI/AAAAAAAACx4/3nGUQzWgHEw/image11_thumb1.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="397" /&gt;&lt;/a&gt;&lt;br /&gt;
and the harmonious colors:&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-0W-o7HALwxI/Te79HgLvvBI/AAAAAAAACx8/j3A30an-XEg/s1600-h/image171.png"&gt;&lt;img alt="Topstyle - Harmonious colors" border="0" height="372" src="http://lh3.ggpht.com/-5rHebPPQ3yY/Te79IJl0S1I/AAAAAAAACyA/OmdJIYo4Wsg/image_thumb711.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="393" /&gt;&lt;/a&gt;&amp;nbsp; &lt;br /&gt;
&lt;h2&gt;Basics of color theory&lt;/h2&gt;The &lt;strong&gt;opposite &lt;/strong&gt;or &lt;strong&gt;complementary color &lt;/strong&gt;is defined in wikipedia as "&lt;em&gt;the color that is of opposite hue in some color model&lt;/em&gt;". Given a color wheel, and chosen a color, the opposite color is the one at the opposite side of the wheel. For example, the opposite color of the red in the following wheel is the green:&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/--kIIv3Q1jSg/Te79I3KMLzI/AAAAAAAACyE/MssoEXvjMxc/s1600-h/image22.png"&gt;&lt;img alt="The color wheel" border="0" height="339" src="http://lh4.ggpht.com/-Xzk1I_WLyoY/Te79JmbvLnI/AAAAAAAACyI/gc1qltydz78/image_thumb10.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="343" /&gt;&lt;/a&gt; &lt;br /&gt;
If you are wondering what a color wheel is, it's a set of colors hues around a circle. The nice thing about the color wheel is that theoretically any set of colors chosen from the color wheel "will look good together". &lt;strong&gt;Harmonious colors&lt;/strong&gt; are colors having a fixed relation in the color wheel. For instance, a &lt;em&gt;square color harmony &lt;/em&gt;is made up of four colors equally spaced in the color wheel:&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/-ZrJzFzfOVW4/Te79Jxyw-oI/AAAAAAAACyM/7tS2TMzzyXc/s1600-h/image26.png"&gt;&lt;img alt="Square color scheme" border="0" height="333" src="http://lh5.ggpht.com/-FrdgwedrC6Q/Te79KurIpHI/AAAAAAAACyQ/V-KhOZMxkmA/image_thumb12.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="333" /&gt;&lt;/a&gt; &lt;br /&gt;
There are several other color schemas, such as complementary, triadic and rectangular.&lt;br /&gt;
I don't want to discuss further on color theory as honestly I don't feel an expert in this area. There are better resources to look for more info, just google for "color theory" and you will get several valuable introductions.&lt;br /&gt;
&lt;h2&gt;Back to TopStyle and introduction to color schemer tools&lt;/h2&gt;After this very brief introduction to color theory, let's get back to TopStyle, the CSS/HTML editor. While using it, I wondered: &lt;em&gt;isn't there any tool to help me choose a good color scheme&lt;/em&gt;? The answer is, of course, yes. There are several tools, most of them are web based and free, others are downloadable and installable products, usually commercial products. As a matter of preference, I like to work with tools installed on my workstation, even if I have to pay a price, and if the tool is worth the price I pay for. So, after googling, trying and discarding several products, I came to the one I currently use.&lt;br /&gt;
Its name is &lt;a href="http://www.tigercolor.com/ColorImpact.asp" target="_blank" title="ColorImpact"&gt;ColorImpact&lt;/a&gt;, a features-rich application providing a color wheel to choose the colors from, plus a set of other useful tools I'm going to describe.&lt;br /&gt;
At program startup the main window displays a set op options to start with, including a useful set of links about color theory. The left sidebar contains the &lt;strong&gt;color chooser&lt;/strong&gt; and the right sidebar contains the &lt;strong&gt;color palette&lt;/strong&gt;, where we are able to save the colors we choose. At bottom right there is a &lt;strong&gt;color inspector&lt;/strong&gt;, displaying info about the color currently under the mouse cursor in any of the application tools.&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-WtBEtOfha7U/Te79Lg2nZaI/AAAAAAAACyU/9jYJWad8jak/s1600-h/image2.png"&gt;&lt;img alt="Main window" border="0" height="484" src="http://lh6.ggpht.com/-B-DvYUN7cYo/Te79M8XYU9I/AAAAAAAACyY/PC4lyvfM88U/image_thumb1.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="612" /&gt;&lt;/a&gt; &lt;br /&gt;
The largest toolbar at top of the window contains a set of buttons to quickly access all tools, such as the color wheel, a color variations tool, and so on.&lt;br /&gt;
&lt;h3&gt;The Color Wheel&lt;/h3&gt;The color wheel is used to select a color harmony. But first a base color should be chosen. ColorImpact provides three different tools to select a color: a wheel, a rectangle and a web safe palette. &lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-Bm4sPaIU9GA/Te79Nw0S2VI/AAAAAAAACyc/yKKLjyniNHM/s1600-h/image6.png"&gt;&lt;img alt="The color wheel" border="0" height="221" src="http://lh6.ggpht.com/-dyGxTMeoP0g/Te79Ol4dmQI/AAAAAAAACyg/uXJ2Et24R4Q/image_thumb21.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="196" /&gt;&lt;/a&gt;&amp;nbsp; &lt;a href="http://lh4.ggpht.com/-2DriRHDW_Bc/Te79PIFFW9I/AAAAAAAACyk/5qhjGZFXPxU/s1600-h/image9.png"&gt;&lt;img alt="The color rectangle" border="0" height="159" src="http://lh5.ggpht.com/-GmV-e5NHf24/Te79PhOwGGI/AAAAAAAACyo/1197H0LlkO4/image_thumb31.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="198" /&gt;&lt;/a&gt;&amp;nbsp; &lt;a href="http://lh6.ggpht.com/-aowOLRxWpf8/Te79QPH_SYI/AAAAAAAACys/zxgH8DD2a-0/s1600-h/image12.png"&gt;&lt;img alt="The web safe palette" border="0" height="169" src="http://lh3.ggpht.com/-tI4m5S4L03Y/Te79Qg3CaCI/AAAAAAAACyw/nFlHyF9SV90/image_thumb41.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="200" /&gt;&lt;/a&gt; &lt;br /&gt;
The one I like more is the &lt;strong&gt;interactive color wheel&lt;/strong&gt;: by simply clicking the small circle and dragging around the wheel we can select a select a color, and by moving along the radius we can choose a different graduation. During the process of color selection, the color wheel displays the chosen color along with the harmonic colors. Once we're satisfied with our base color, we can choose a color harmony schema selecting from a list available at the bottom center.&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-bq0qlG8kRAI/Te79RBn9EXI/AAAAAAAACy0/MQ_AwRxP8b0/s1600-h/image4.png"&gt;&lt;img alt="Color Harmonies" border="0" height="196" src="http://lh5.ggpht.com/-M0GPPX5cyHQ/Te79RuI0dUI/AAAAAAAACy4/qbA7m-sbFks/image_thumb111.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="354" /&gt;&lt;/a&gt; &lt;br /&gt;
If, for instance, we choose the Square color harmony, we'll see the four equally spaced colors in the color wheel highlighted.&lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/-K9M3oT4Ev8g/Te79TDVcz7I/AAAAAAAACy8/zOJ8gJr4a8w/s1600-h/image3111.png"&gt;&lt;img alt="Color Harmonies tool" border="0" height="484" src="http://lh3.ggpht.com/-WOm19tYsBxs/Te79UTe35fI/AAAAAAAACzA/hiyftkXCrRY/image311_thumb.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="542" /&gt;&lt;/a&gt; &lt;br /&gt;
Colors displayed in the wheel, as well as in any of the tools described below, can be saved in the &lt;strong&gt;color palette &lt;/strong&gt;toolbox docked at the right side of the main window, either by double clicking a color on the tool currently in use or dragging a color and dropping into the palette . We have the option of creating multiple palettes, if we need to organize colors in different sets.&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/-Ta0FWP8StTc/Te79U-K4PaI/AAAAAAAACzE/BGFzzQW-UME/s1600-h/image5.png"&gt;&lt;img alt="Color palette" border="0" height="244" src="http://lh3.ggpht.com/-8gLFQ4gnpYo/Te79Vdgv3nI/AAAAAAAACzI/taLQSRO7ROo/image_thumb2.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="174" /&gt;&lt;/a&gt; &lt;br /&gt;
&lt;h3&gt;Other tools&lt;/h3&gt;ColorImpact provides not just a color wheel and the ability to choose a color harmony schema, but several other useful tools which greatly helps in the process of selecting colors and variations.&lt;br /&gt;
The &lt;strong&gt;Advanced Color Wheel &lt;/strong&gt;displays a color wheel similar to the one displayed in the Color Harmonies tool, but in addition it provides different hues in inner circles of the wheel. It's possible to configure the wheel to display variations from dark to light and vice versa, and from current hues to either darker or lighter variations, more or less saturated, cooler and warmer.&lt;br /&gt;
&lt;h3&gt;&lt;/h3&gt;&lt;a href="http://lh6.ggpht.com/-Z5dmstRckcM/Te79Wvcd6ZI/AAAAAAAACzM/2ix8ijruiVw/s1600-h/image915.png"&gt;&lt;img alt="Advanced Color Wheel tool" border="0" height="484" src="http://lh4.ggpht.com/-cYEUNRT5-PE/Te79XxdyxsI/AAAAAAAACzQ/txYSM8-K6WU/image91_thumb4.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="542" /&gt;&lt;/a&gt; &lt;br /&gt;
The &lt;strong&gt;Color Formulae&lt;/strong&gt; provides a list of colors based on a predefined formula selectable from a list of 30 in the drop down list at bottom of the tool page. For each formula a brief description helps us figuring out what's the relation among colors displayed by the tool. Examples of formulas are different hues variations, monochromatic variations, geometrical variations (such as square, rectangle), complementary, and so on.&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-CJJLjOCQURw/Te79ZKBpICI/AAAAAAAACzU/tVFNs5SvZV8/s1600-h/image1212.png"&gt;&lt;img alt="Color Formulae tool" border="0" height="484" src="http://lh3.ggpht.com/-CcbSipcddtA/Te79aXpPbxI/AAAAAAAACzY/bUYk9ix_75I/image121_thumb1.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="542" /&gt;&lt;/a&gt; &lt;br /&gt;
Using the &lt;strong&gt;Color Variations&lt;/strong&gt; tool we are able to display different color variations, such as darker and lighter, from dark to light and vice versa, more or less saturated, and other combinations.&lt;br /&gt;
&lt;a href="http://lh5.ggpht.com/-Dsf61ZaB9Ug/Te79bT6h1NI/AAAAAAAACzc/yAb0osQWtZk/s1600-h/image151.png"&gt;&lt;img alt="Color Variations tool" border="0" height="484" src="http://lh5.ggpht.com/-_SuMMsRLQc0/Te79cwHj1dI/AAAAAAAACzg/ioScVJr8rjk/image15_thumb.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="642" /&gt;&lt;/a&gt; &lt;br /&gt;
The &lt;strong&gt;Color Blender,&lt;/strong&gt; as it name implies, provides a list of variations of a color blending into another. Starting and ending colors can be chosen by either using the wheel tool (or any of the color picker tools) or by dragging a color from the palette and dropping into one of the ends&lt;br /&gt;
&lt;a href="http://lh5.ggpht.com/-_h4Bw7_UKPA/Te79eA_ObfI/AAAAAAAACzk/3t-tR0wGzm4/s1600-h/image18114.png"&gt;&lt;img alt="Color Blender tool" border="0" height="484" src="http://lh4.ggpht.com/-N9qKpZVPBUs/Te79s2pqsOI/AAAAAAAACzo/AjYIqeEPjtc/image1811_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="642" /&gt;&lt;/a&gt; &lt;br /&gt;
The last tool is the &lt;strong&gt;Test Pattern&lt;/strong&gt;, an undoubtedly useful way of previewing our color palettes and see how colors look when mixed together. There are several test patterns our colors can be tested with, and probably the most interesting to web designers is the &lt;em&gt;Web Page&lt;/em&gt; pattern, available in 2 different variations.&lt;br /&gt;
&lt;a href="http://lh5.ggpht.com/-ElP_XT3Kiwg/Te79uTCxCWI/AAAAAAAACzs/VdnKahVUQv4/s1600-h/image2111.png"&gt;&lt;img alt="Web test pattern" border="0" height="484" src="http://lh3.ggpht.com/-eb6vktTMnX4/Te79wOf0LMI/AAAAAAAACzw/yVQB6_h2rwc/image211_thumb.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="612" /&gt;&lt;/a&gt; &lt;br /&gt;
Using the Test Pattern tool we are able to drag colors from the palette and drop into any of the web page elements. Once we have applied our colors, we can see how our color schema looks like. There are several other test patterns, such as Fashion (displayed below), type designs, shapes and circles.&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/-Wb1DwQdgZP0/Te79xQRuPHI/AAAAAAAACz0/OlU00SBeSa0/s1600-h/image111.png"&gt;&lt;img alt="Fashion test pattern" border="0" height="484" src="http://lh4.ggpht.com/-9kXITbSEXUk/Te79y2OqsbI/AAAAAAAACz4/s2cJu6jZlkk/image11_thumb.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="612" /&gt;&lt;/a&gt; &lt;br /&gt;
One of the coolest things about test patterns is that we can create our own, using Flash MX. On the website there is a brief tutorial describing how to create a custom test pattern and adding it to the list of test patterns.&lt;br /&gt;
&lt;h2&gt;Import and Export&lt;/h2&gt;I can's say that a tool like ColorImpact is useless without import and export features, because I'd still benefit from using it even manually copying color values. But having such features is a plus (other than a must for most people). Although import is limited to XML and &lt;a href="http://www.colorschemer.com/" target="_blank" title="Color Schemer"&gt;Color Schemer&lt;/a&gt; (a similar tool for choosing color schemes), ColorImpact is able to export into any of the following formats:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Image containing the list of colors along with their hexadecimal values (gif, bmp, jpg, png, windows metafile and enhanced metafile)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Text file, listing all color names and values&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;HTML Spec Sheet, an html page displaying colors and color values&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;CSS&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;ACT Color Table&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Paint Shop Pro palette&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Photoshop color palette&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Illustrator color palette&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Freehand ACF palette&lt;/li&gt;

&lt;/ul&gt;&lt;h2&gt;&lt;/h2&gt;&lt;a href="http://lh3.ggpht.com/-0fp5Jqi5RnY/Te79ztnG4dI/AAAAAAAACz8/ER_I-KjEwWo/s1600-h/image193.png"&gt;&lt;img alt="image" border="0" height="484" src="http://lh4.ggpht.com/-p_7KGk8Dd7A/Te790kZvR8I/AAAAAAAAC0A/W5dWNA5p480/image19_thumb2.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="470" /&gt;&lt;/a&gt;&lt;br /&gt;
&amp;nbsp;&lt;a href="http://lh5.ggpht.com/-vK4nAjCjBFc/Te791cvlx9I/AAAAAAAAC0E/lL_EhQeRTJU/s1600-h/image164.png"&gt;&lt;img alt="image" border="0" height="475" src="http://lh3.ggpht.com/-92jjNBLIyOk/Te792eVzeYI/AAAAAAAAC0I/6C1WGylUzRc/image16_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="644" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Additional tools&lt;/h2&gt;Other than the important tools described so far, there are some other minor features making life easier when selecting colors. With the &lt;strong&gt;eye dropper tool&lt;/strong&gt; we can select a color from any point of the desktop or any open window, with the additional ability to get either the exact color or an average of its surrounding area&lt;br /&gt;
&amp;nbsp;&lt;a href="http://lh5.ggpht.com/-KleZ3OPd-74/Te792yPfC-I/AAAAAAAAC0M/-SNMPp5WjGU/s1600-h/image1511.png"&gt;&lt;img alt="image" border="0" height="196" src="http://lh5.ggpht.com/-ODpYYM19sqo/Te793WpJAnI/AAAAAAAAC0Q/XWH8AdtDmQY/image_thumb51.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="244" /&gt;&lt;/a&gt;&lt;br /&gt;
With the &lt;strong&gt;color blindness simulation&lt;/strong&gt; we can simulate how our colors set will be seen by color blindness people.&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-5mvRXShVKes/Te8BwOOs6uI/AAAAAAAAC0U/k9kyh4WYa2E/s1600-h/image33.png"&gt;&lt;img alt="image" border="0" height="175" src="http://lh5.ggpht.com/-RZQ5EdT14_I/Te8Bw-fuPYI/AAAAAAAAC0Y/X69US0AHxu0/image_thumb11.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px;" width="244" /&gt;&lt;/a&gt; &lt;br /&gt;
The &lt;strong&gt;random color &lt;/strong&gt;tool simply generates a random color.&lt;br /&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;As mentioned earlier, once I realized that there are tools specifically targeted to simplify color schemes selection, I have tried several tools. In the process of selecting the most appropriate tool I took into account several aspects, such as user friendliness, number of features, exporting capabilities. The tool at the 2nd place of my personal favorite list is Color Schemer, which I didn't like for just one thing, very important to me: it runs on a fixed sized window, too small in my opinion, also considering that I'm used to work with high resolution monitors, such as my 15,4" 1920x1200 laptop display.&lt;br /&gt;
ColorImpact implements all the features required to easily and quickly choose web color schemes, also providing unique features I haven't seen in other applications. So, I can't do anything else than suggesting to whoever reads this blog post to give it a try - you'll like it. A 15 days trial version can be downloaded at the following address:&lt;br /&gt;
&lt;a href="http://www.tigercolor.com/Download/Default.htm" title="Color Impact Trial"&gt;http://www.tigercolor.com/Download/Default.htm&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-8544312609619057567?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CRGhByLoxmWM_KuhXWBDrb8adxA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CRGhByLoxmWM_KuhXWBDrb8adxA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CRGhByLoxmWM_KuhXWBDrb8adxA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CRGhByLoxmWM_KuhXWBDrb8adxA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/E4GljmQ2-lU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/8544312609619057567/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2009/02/choosing-web-color-scheme.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8544312609619057567?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8544312609619057567?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/E4GljmQ2-lU/choosing-web-color-scheme.html" title="Choosing a web color scheme" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-MW8b5VFTGAU/Te79HNEgxFI/AAAAAAAACx4/3nGUQzWgHEw/s72-c/image11_thumb1.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2009/02/choosing-web-color-scheme.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMBRH08fCp7ImA9WhZUF0o.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-5240449366914540078</id><published>2008-11-01T11:19:00.000-07:00</published><updated>2011-06-10T23:40:55.374-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-10T23:40:55.374-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Data integrity check using hashing</title><content type="html">When data is moved across a network, the recipient might require a verification to ensure that data has not been modified after send. For example, in a client/server scenario where a client application sends some updates to a remote database via a web service, the web service might need to verify whether the data has not been modified while travelling across the network, either due to corruption or because somebody changed them. A simple way to implement such kind of verification is utilizing &lt;strong&gt;hashing&lt;/strong&gt;.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;h2&gt;Introduction&lt;/h2&gt;When data is moved across a network, the recipient might require a verification to ensure that data has not been modified after send. For example, in a client/server scenario where a client application sends some updates to a remote database via a web service, the web service might need to verify whether the data has not been modified while travelling across the network, either due to corruption or because somebody changed them. A simple way to implement such kind of verification is utilizing &lt;strong&gt;hashing&lt;/strong&gt;.&lt;br /&gt;
&lt;h2&gt;How Hashing works&lt;/h2&gt;The idea behind hashing is to generate a (ideally) &lt;strong&gt;unique &lt;/strong&gt;and &lt;strong&gt;non–reversible code&lt;/strong&gt; generated from the data being sent. &lt;em&gt;Unique &lt;/em&gt;means that the codes generated for 2 different sets of data must differ each other, even if each set of data has a size of 1 Mb and they differ by 1 byte only. &lt;em&gt;Non-reversible &lt;/em&gt;means that the hash code cannot be used to recreate the original data.&lt;br /&gt;
For the purpose of signing data to check for modification, the non-reversibility feature is unnecessary, as the hash code travels with the data, but there are other cases where it is undoubtedly useful. For example, one of the easiest way to prevent passwords from being stored in a database is to store a hash code rather than the password. This way when a user is authenticating the password is used to generate an hash key, which is compared to the hash key stored in the database (previously generated when the user account has been created, or the last time the user has changed his password) – if&amp;nbsp; they match, authentication succeeds. The drawback of this method is that a “recall password” feature cannot be implemented, as the password is not stored anywhere, and the non reversibility property of the hash code prevents it from being used to recreate the original data – in such case a “reset password” feature is more appropriate.&lt;br /&gt;
&lt;h2&gt;Hashing and Salting&lt;/h2&gt;Using the model described above data is protected against corruption but not against changes. In fact, whereas a corruption is immediately detected once the recipient verifies that the &lt;a class="zem_slink" href="http://en.wikipedia.org/wiki/Hash_function" rel="wikipedia" title="Hash function"&gt;hash codes&lt;/a&gt; don’t match, an hacker attempting to modify the data simply has to create a new hash code. Since this code is sent with the data, and since the hashing algorithm is deterministic, whoever wants to modify the data has all ingredients to do so, with no risk of being detected.&lt;br /&gt;
So hashing is not enough to guarantee data integrity. One common practice is to use a random or predefined string, which is appended to the data before calculating the hash code. This additional string is known as &lt;strong&gt;&lt;a class="zem_slink" href="http://en.wikipedia.org/wiki/Salt_%28cryptography%29" rel="wikipedia" title="Salt (cryptography)"&gt;salt&lt;/a&gt;&lt;/strong&gt;. If the salt is known by sender and recipient only, an hacker has no way to generate an hash code that won’t be immediately detected by the recipient during hash verification.&lt;br /&gt;
In this scenario the salt can be thought as a private key shared between sender and recipient.&lt;br /&gt;
For improved security, it’s better if the salt is not 100% static – for example, a dynamic string depending from the date and/or time can be mixed to the static salt in order to generate a dynamic salt, harder for an hacker to guess. For this method to work both sender and recipient must generate the same salt in a wide enough time window. For example, supposing that sender and recipient have their clocks synchronized, if the salt is composed by current hour and minute, the widest time window is 60 seconds – but the recipient could generate a different salt just 1 second after the sender generated the salt code, if this occurs, for example, at 10:20:59. In this case the sender use 10:20 to generate the salt – if the recipient receives the message at least 1 second later, it will use 10:21 to generate the salt. And this obviously leads to a completely different hash code.&lt;br /&gt;
&lt;h2&gt;Implementing a data integrity check&lt;/h2&gt;There are several algorithms that can be use to generate hash codes. One of them is &lt;a class="zem_slink" href="http://en.wikipedia.org/wiki/MD5" rel="wikipedia" title="MD5"&gt;MD5&lt;/a&gt;, implementable as follows:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;using System;
using System.Security.Cryptography;
using System.Text;

namespace Hash
{
 public class HashGenerator
 {
  public static string GenerateMd5Hash(string salt, string data)
  {
   byte[] buffer;
   byte[] binaryHash;
   string stringHash;
   MD5 md5;

   md5 = MD5.Create();
      
   // Combine salt + data and convert to array of bytes
   buffer = Encoding.Unicode.GetBytes(salt + data);

   // Create the hash code from salt + data
   binaryHash = md5.ComputeHash(buffer);

   // The hash code is in binary format - convert
   // it in readable string
   stringHash = Convert.ToBase64String(binaryHash);

   return stringHash;
  }
 }
}&lt;/pre&gt;The code is pretty simple: salt + data are combined together and converted to array of bytes, then the ComputeHash method of the MD5 instance creates the hash code given the array of bytes. Last, since the hash generated by ComputeHash is in binary format, it is converted to string and returned. To test this code we can create a simple console application like the following one:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;using System;
using Hash;

namespace HashSample
{
 public class Program
 {
  static void Main(string[] args)
  {
   string test;
   string hash;
   string salt;

   test = "This is a sample data";
   salt = "FTSA74D71KSAP";

   hash = HashGenerator.GenerateMd5Hash(salt, test);

   Console.Out.WriteLine(
    "The hash code for string '{0}' and salt '{1}' is:\n\t{2}",
    test, salt, hash
   );

   Console.In.Read();
  }
 }
}&lt;/pre&gt;The output produced by this application is the following:&lt;br /&gt;
&lt;code&gt;The hash code for string 'This is a sample data' and salt 'FTSA74D71KSAP' is: &lt;br /&gt;
&lt;br /&gt;
s2gxEi9C3QSRGFy+cZheWA== &lt;/code&gt;&lt;br /&gt;
To prove how the hash code changes by simply changing 1 byte in the original data, let’s see what happens if we slightly change the test string to “This is &lt;strong&gt;b&lt;/strong&gt; sample data”:&lt;br /&gt;
&lt;code&gt;The hash code for string 'This is b sample data' and salt 'FTSA74D71KSAP' is: &lt;br /&gt;
&lt;br /&gt;
FJr7RUcSYJMJBdfCg6DCXQ== &lt;/code&gt;&lt;br /&gt;
We can see that these 2 hashes are completely different.&lt;br /&gt;
&lt;h2&gt;IHashable interface&lt;/h2&gt;If we need to generate an hash code on instances of a class, why don’t we define a proper interface? This way we can just implement the interface and write a single function to generate the hash code. The interface name is, of course, IHashable:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public interface IHashable
{
    string GetHashableRepresentation();
    string GenerateSalt();
}&lt;/pre&gt;and consists of 2 methods: GetHashableRepresentation and GenerateSalt. The latter should be implemented in order to generate a proper salt code, whereas the former should return a representation of the class instance in a string format suitable for hashing - for example, a simple string concatenation of all data members.&lt;br /&gt;
As I mentioned earlier, there are several algorithms usable for hashing. Following a comprehensive implementation of the hash generation, which allows the caller to choose which algorithm to use:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public enum HashingAlgorithm
{
    Md5,
    Sha1,
    Sha256,
    Sha384,
    Sha512,
    RipeMd160
}

public static string GenerateHash(HashingAlgorithm alg, IHashable hashable)
{
    HashAlgorithm algorithm;

    algorithm = CreateHashAlgorithm(alg);

    byte[] buffer;
    byte[] binaryHash;
    string stringHash;

    // Combine salt + data and convert to array of bytes
    buffer = Encoding.Unicode.GetBytes(hashable.GetHashableRepresentation() + hashable.GenerateSalt());

    // Create the hash code from salt + data
    binaryHash = algorithm.ComputeHash(buffer);

    // The hash code is in binary format - convert
    // it in readable string
    stringHash = Convert.ToBase64String(binaryHash);

    return stringHash;
}

private static HashAlgorithm CreateHashAlgorithm(HashingAlgorithm alg)
{
    HashAlgorithm algorithm;

    switch (alg)
    {
        default:
        case HashingAlgorithm.Md5:
            algorithm = MD5.Create();
            break;

        case HashingAlgorithm.Sha1:
            algorithm = SHA1.Create();
            break;

        case HashingAlgorithm.Sha256:
            algorithm = SHA256.Create();
            break;

        case HashingAlgorithm.Sha384:
            algorithm = SHA384.Create();
            break;

        case HashingAlgorithm.Sha512:
            algorithm = SHA512.Create();
            break;

        case HashingAlgorithm.RipeMd160:
            algorithm = RIPEMD160.Create();
            break;
    }

    return algorithm;
}&lt;/pre&gt;The GenerateHash method requires 2 parameters: the algorithm to use and an instance of IHashable. In return, the method provides an hash code generated using the specified algorithm.&lt;br /&gt;
Last thing to mention, a helpful method to compare an hash code with an IHashable instance – its implementation is really very simple:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public static bool CompareHashes(HashingAlgorithm alg, string hash, IHashable hashable)
{
    return GenerateHash(alg, hashable).Equals(hash);
}&lt;/pre&gt;&lt;h2&gt;Digital signature&lt;/h2&gt;When used alone, hashing is good but it’s not the best. There are better ways, out of the scope of this article – but I want to spend a few words about them.&lt;br /&gt;
The safest and more secure way to sign data is using &lt;a class="zem_slink" href="http://en.wikipedia.org/wiki/Digital_signature" rel="wikipedia" title="Digital signature"&gt;digital signature&lt;/a&gt;, which make use of asymmetric cryptography (also known as &lt;a class="zem_slink" href="http://en.wikipedia.org/wiki/Public-key_cryptography" rel="wikipedia" title="Public-key cryptography"&gt;public key cryptography&lt;/a&gt;). The idea is to encrypt the hash code so that it cannot be modified.&lt;br /&gt;
In cryptography a key is used to encrypt and decrypt data – it’s not an algorithm, but a secret data used for encryption: using a different key different encrypted data is generated. A (very simple) example of key is the salt we’ve seen earlier: changing the salt will produce a different hash code.&lt;br /&gt;
Keys are usually used to encrypt and decrypt data. In symmetric cryptography the same key is used to encrypt and decrypt data. This is the biggest limitation, as the key must be owned by both parties involved in the encryption and decryption process, or sent along with the encrypted data if the recipient doesn’t have the key.&lt;br /&gt;
In public key cryptography a key is composed by a public key and a private key. The private key, as the name implies, is private and should never be sent to anybody. On the other hand, the public key can be published and made available to anybody. The key owner uses his private key to encrypt data – anybody can decrypt the data using the public key, but the cool feature is that the public key can be used to decrypt data encrypted by the corresponding private key only. This means that who is decrypting is sure that data has been encrypted by the owner of the private key only. Keys can also be used in the opposite way: data encrypted with the public key can only be decrypted by the corresponding private key. This way whoever encrypts data using the public key is sure that data will be available to the owner of the corresponding private key only.&lt;br /&gt;
In our hashing problem, if the sender encrypts the hash code using his private key, the recipient is able to detect any unauthorized data modification:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;if the data gets corrupted or changed, the hash code calculated from the data won’t match with the encrypted hash code provided with the data&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;if the encrypted hash code provided with the data is modified, it won’t match with the hash code calculated from the data &lt;/li&gt;

&lt;/ul&gt;&lt;br /&gt;
&lt;div class="zemanta-pixie"&gt;&lt;a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/de66927d-6964-4cc6-b3bf-67f49fa55c44/" title="Zemified by Zemanta"&gt;&lt;img alt="Reblog this post [with Zemanta]" class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_e.png?x-id=de66927d-6964-4cc6-b3bf-67f49fa55c44" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-5240449366914540078?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AThk_1W5vL9DwWGxTvTRBxUJJ8s/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AThk_1W5vL9DwWGxTvTRBxUJJ8s/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AThk_1W5vL9DwWGxTvTRBxUJJ8s/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AThk_1W5vL9DwWGxTvTRBxUJJ8s/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/8Dgw-dm3XbI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/5240449366914540078/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2008/10/data-integrity-check-using-hashing_31.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/5240449366914540078?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/5240449366914540078?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/8Dgw-dm3XbI/data-integrity-check-using-hashing_31.html" title="Data integrity check using hashing" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2008/10/data-integrity-check-using-hashing_31.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMMSXc4eSp7ImA9WhZUF0o.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-8556427019526943449</id><published>2008-10-02T20:50:00.000-07:00</published><updated>2011-06-10T23:41:28.931-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-10T23:41:28.931-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Mark a C# class data member as readonly when it’s read only</title><content type="html">2009.01.30 - Updated in order to clarify about immutability.&lt;br /&gt;
The &lt;strong&gt;readonly&lt;/strong&gt; modifier is used to declare an instance-specific constant data member which can be initialized in the class constructor and is not limited to compiler-time constants only.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;The &lt;strong&gt;readonly &lt;/strong&gt;modifier is used to declare a constant data member in a class, but providing more flexibility than using the &lt;strong&gt;const &lt;/strong&gt;modifier. The const modifier implicitly defines the data member as static, and must be initialized along with its declaration, as follows:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public const int myConst = 5;&lt;/pre&gt;If the const is not initialized along with the declaration, the compiler will generate an error.&lt;br /&gt;
Moreover, a const data member must be initialized with a compile-time constant – in other words there is no way to initialize a constant using a runtime value. For instance, the following code doesn’t compile:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyClass
{
 public static string nonConstValue = "This is a variable initialized at runtime";
 public const string constValue = nonConstValue;  // Compilation error
 ...
}&lt;/pre&gt;as the compiler will inform that “The expression being assigned to 'MyClass.constValue' must be constant”.&lt;br /&gt;
The advantage of defining a data member as &lt;strong&gt;const &lt;/strong&gt;is that it cannot be changed – the drawback being the inability to initialize the field in a different place other than the declaration.&lt;br /&gt;
On the other hands, the &lt;strong&gt;readonly&lt;/strong&gt; modifier extends the const modifier by allowing the data member to be initialized &lt;em&gt;in any class constructor&lt;/em&gt;. This allows a data member to be initialized when a class is being instantiated, preventing it from being modified in any other class method – in other words, once the const data member is initialized it never changes during the class instance lifetime. As opposed to the const modifier, the readonly modifier creates an instance-specific data member, so each class instance will have its own readonly data member instances. This doesn’t mean that a readonly data member cannot be static – simply it must explicitly be declared as such.&lt;br /&gt;
All the following declarations and initializations are valid:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyClass
{
 public readonly int _myIntField = 5; // Allowed
 public readonly string _myStringField; // Allowed

 public MyClass()
 {
  _myIntField = 8;         // Allowed
  _myStringField = "Initialized in the constructor"; // Allowed
 }

 public static void Main()
 {
  MyClass myClass;
  
  myClass = new MyClass();
  
  System.Console.Out.WriteLine(string.Format("myIntField = {0}", myClass._myIntField));
  System.Console.Out.WriteLine(string.Format("myStringField = {0}", myClass._myStringField));
 }
}&lt;/pre&gt;The member declared at line 4 is initialized in the constructor with a string constant, whereas the int member declared at line 3 is initialized both in the declaration and in the constructor. In this case, the constructor initialization takes precedence, as it is executed after the data member instantiation.&lt;br /&gt;
The following case instead is not valid&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyClass
{
 public readonly string _myStringField; // Allowed

 public MyClass()
 {
  Init();
 }

 private void Init()
 {
  _myStringField = "Cannot be initialized here";  // Compilation error
 }
 
 ... 
}&lt;/pre&gt;That’s because the readonly member is initialized in a class member which is not a constructor, even if this method is called from the constructor. The reason why this is not allowed is that the Init() method can be called from anywhere within the class, or even outside if it is protected, internal or public rather than private.&lt;br /&gt;
Another advantage of the readonly modifier is that it can be initialized with a runtime value or an expression evaluated at runtime, for instance:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyClass
{
 public readonly int  _myIntField; // Allowed

 public MyClass(int runtimeValue)
 {
  _myIntField = 10 * runtimeValue;
 }

 
 public static void Main()
 {
  MyClass myClass;
  
  myClass = new MyClass(5);
  
  System.Console.Out.WriteLine(string.Format("myIntField = {0}", myClass._myIntField));
 }
}&lt;/pre&gt;As we can expect, the _myIntField readonly data member will be initialized to 10 * 5 = 50.&lt;br /&gt;
Readonly data members are not limited to basic data types – it can be used for class instances. For example, when writing a database accessor class we might want to provide a database connection:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyDatabaseAccessor
{
 private readonly SqlConnection _connection;
 
 public MyDatabaseAccessor (SqlConnection connection)
 {
  _connection = connection;
  ...
 }
 
 ...

}

public class MyApp
{
 public static void Main()
 {
  SqlConnection connection = new SqlConnection();
  
  // Initialize the connection
  ...
  
  MyDatabaseAccessor myAccessor = new MyDatabaseAccessor(connection);
  
  // Do something
  ...
 }
}

&lt;/pre&gt;The above code would work without declaring the _connection data member as readonly – but in such case the connection can be changed anywhere in the class.&lt;br /&gt;
It’s important to keep in mind that when a readonly data member is of a reference type (i.e. instance of a class and not either a struct or a base data type) the reference is constant, but the instance it points to is not. So the internal status of a readonly instance can change and can be changed, as proven by the following sample:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;// Class with a data member
public class MyClassType
{
 private string _internalStatus;
 
 public string InternalStatus {
  get {return _internalStatus;} 
  set {_internalStatus = value;}
 }
}

// Class with a readonly data member
public class MyClassWithReadonlyMember
{
 private readonly MyClassType _readonlyInstance;
 
 public MyClassWithReadonlyMember(string value)
 {
  _readonlyInstance = new MyClassType();
  _readonlyInstance.InternalStatus = value;
 }
 
 public void SetStatus(string message)
 {
  _readonlyInstance.InternalStatus = message;
 }
 
 public void OutputStatus()
 {
  System.Console.Out.WriteLine(string.Format(
    @"Internal status = '{0}'", _readonlyInstance.InternalStatus));
 }
}

public class MyApp
{
 public static void Main()
 {
  MyClassWithReadonlyMember classInstance;
  
  // Create an instance of MyClassWithReadOnlyMember class
  // The instance of MyClassType is initialized to the default 
  // value provided in the constructor
  classInstance = new MyClassWithReadonlyMember("Initial value");
  classInstance.OutputStatus();
  
  // The internal status of the readonly data member of 
  // MyClassWithReadonlyMember is changed
  classInstance.SetStatus("New Value");
  classInstance.OutputStatus();  
 }
}
&lt;/pre&gt;If this code is compiled and run. it will generate the following output:&lt;br /&gt;
&lt;blockquote&gt;Internal status = 'Initial value'&lt;br /&gt;
Internal status = 'New Value'&lt;/blockquote&gt;&lt;br /&gt;
&lt;h2&gt;2009.01.30 Addendum&lt;/h2&gt;Thanks to what Chris Marisic highlighted in his comments below, I need to clarify a few points to prevent some misleading assumptions.&lt;br /&gt;
&lt;strong&gt;#1&lt;/strong&gt; - readonly members can be modified using reflection. The readonly modifier is a compiler directive, so any attempt to modify a readonly data member is detected during compilation. A consequence is that using reflection it's possible to modify a readonly data member&lt;br /&gt;
&lt;strong&gt;#2 - &lt;/strong&gt;I wrote above that the const modifier "&lt;em&gt;allows a data member to be initialized when a class is being instantiated, preventing it from being modified in any other class method&lt;/em&gt;". This statement doesn't mean that the data member is immutable, at least not always. .NET supports two kinds of data types: &lt;strong&gt;value types&lt;/strong&gt; and &lt;strong&gt;reference types&lt;/strong&gt;.:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;value types are allocated on the thread's stack and they hold the actual value&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;reference types are allocated on the thread's stack and they hold a pointer to an object allocated in the managed heap&lt;/li&gt;

&lt;/ul&gt;In both cases variables are allocated on the thread's stack, the difference being that a value type holds the actual value (for example, an integer, a struct), whereas the reference type holds a pointer to the memory area where the actual value is stored (for example, an instance of a StringBuilder class). &lt;br /&gt;
When a value type is declared as readonly, its value is immutable, meaning that once assigned it cannot be modified outside constructors.&lt;br /&gt;
When a reference type is declared as readonly, the pointer is immutable, but not the object it points to. This means that:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;a reference type data member can be initialized in order to point to an instance of a class, but once this is done it's not possible to make it point to another instance of a class outside of constructors&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;the readonly modifier has no effect on the object the readonly data member points to. &lt;/li&gt;

&lt;/ul&gt;Maybe a real example helps to better understand the difference. Let's create a simple class and a simple struct. They have one int data member only.&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyClass
{
 public int IntField;
}

public struct MyStruct
{
 public int IntField;
}&lt;/pre&gt;Now let's use them in a test class:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyTestClass
{
 private readonly MyClass _myClass;
 private readonly MyStruct _myStruct;

 public MyTestClass()
 {
  _myClass = new MyClass();
  _myClass.IntField = 4;

  _myStruct.IntField = 5;
 }
}&lt;/pre&gt;The _myClass data member is a reference type, so it must be initialized by allocating a new instance of MyClass and assigning its pointer, as seen at line 8. On the other hand, the _myStruct data member is a value type, meaning that it is already an instance of MyStruct. Initialization of their respective fields are done at lines 9 and 11.&lt;br /&gt;
Let's add a method to the MyTestClass class.&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class MyTestClass
{
 private readonly MyClass _myClass;
 private readonly MyStruct _myStruct;

 public MyTestClass()
 {
  _myClass = new MyClass();
  _myClass.IntField = 4;

  _myStruct.IntField = 5;
 }

 public void TestReadonly()
 {
  _myClass.IntField = 7;  // Valid statement
  _myStruct.IntField = 10; // Error: _myStruct is readonly
  _myClass = null;   // Error: _myClass is readonly
 }
}&lt;/pre&gt;If we try to compile this code, we get 2 errors:&lt;br /&gt;
&lt;blockquote&gt;MyTest.cs(26,3): error CS1648: Members of readonly field 'MyTestClass._myStruct'  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cannot be modified (except in a constructor or a variable initializer)&lt;br /&gt;
MyTest.cs(27,3): error CS0191: A readonly field cannot be assigned to (except in &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a constructor or a variable initializer)&lt;/blockquote&gt;&lt;span style="font-family: 'Lucida Console';"&gt;&lt;/span&gt;&lt;br /&gt;
MyStruct is a struct, hence a value type; _myStruct is immutable since declared as readonly, so any of its data members cannot be modified outside of a constructor.&lt;br /&gt;
MyClass is a class, hence a reference type; _myClass is immutable since declared as readonly, so it cannot be modified in order to point to another instance of a class (or to null) outside of a constructor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-8556427019526943449?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2vczoyNWvig_5F32tTUiR3Ga9-8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2vczoyNWvig_5F32tTUiR3Ga9-8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2vczoyNWvig_5F32tTUiR3Ga9-8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2vczoyNWvig_5F32tTUiR3Ga9-8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/fqf4nG5bxvM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/8556427019526943449/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2009/01/mark-c-class-data-member-as-readonly.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8556427019526943449?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8556427019526943449?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/fqf4nG5bxvM/mark-c-class-data-member-as-readonly.html" title="Mark a C# class data member as readonly when it’s read only" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2009/01/mark-c-class-data-member-as-readonly.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkENQnw8fyp7ImA9WhdUEkw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-8092880497961902231</id><published>2007-07-18T23:49:00.000-07:00</published><updated>2011-09-28T04:51:33.277-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-28T04:51:33.277-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WinForms" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>DataGridView: how to bind nested objects</title><content type="html">The WinForms DatagridView control is not capable of handling nested properties, as it works with base data types only. But implementing such feature is not complicated. Let’s see how.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;h3&gt;
The Problem&lt;/h3&gt;
A DataGridView can be bound to a collection of objects to display any of its base data type (i.e. string, int, and so on) properties. For example, a collection of instances of the following class:&lt;br /&gt;
&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class Customer
{
  public string FirstName { get; set;}
  public string LastName { get; set;}
  public string Street { get; set;}
  public string PostalCode { get; set;}
  public string City { get; set;}
} &lt;/pre&gt;
can be used to display any of the &lt;span class="inline-code"&gt;Customer&lt;/span&gt; class properties in the DataGridView.&lt;br /&gt;
But what happens when the class exposes other objects which are not base data type? If an &lt;span class="inline-code"&gt;Address&lt;/span&gt; class is created and used as a property of the &lt;span class="inline-code"&gt;Customer&lt;/span&gt; class:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;public class Address
{
  public string Street { get; set;}
  public string PostalCode { get; set;}
  public string City { get; set;}
}

public class Customer
{
  public string FirstName { get; set;}
  public string LastName { get; set;}
  public Address Address { get; set;}
}&lt;/pre&gt;
a DataGridView bound to a collection of &lt;span class="inline-code"&gt;Customer&lt;/span&gt; instances is not able to display any of the &lt;span class="inline-code"&gt;Address&lt;/span&gt; properties. In such cases the displayed cells are empty.&lt;br /&gt;
&lt;h3&gt;
The Solution&lt;/h3&gt;
In order to enable the DataGridView to display properties exposed by class members, some custom development is required. The first step is to implement the DataGridView's &lt;span class="inline-code"&gt;CellFormatting&lt;/span&gt; event handler&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private void gridCustomers_CellFormatting(
  object sender, 
  DataGridViewCellFormattingEventArgs e)
{
  ...
}&lt;/pre&gt;
The &lt;span class="inline-code"&gt;CellFormatting &lt;/span&gt;event handler needs to differentiate whether the field to be displayed is one of the base data type or an object exposing its own properties. This is achieved by looking for the dot character &lt;span class="inline-code"&gt;'.'&lt;/span&gt; in the &lt;span class="inline-code"&gt;Column&lt;/span&gt;'s &lt;span class="inline-code"&gt;DataPropertyName&lt;/span&gt; field:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private void gridCustomers_CellFormatting(
  object sender, 
  DataGridViewCellFormattingEventArgs e)
{
  if ((gridCustomers.Rows[e.RowIndex].DataBoundItem != null) &amp;amp;&amp;amp; 
      (gridCustomers.Columns[e.ColumnIndex].DataPropertyName.Contains(".")))
  {
    ...
  }
}&lt;/pre&gt;
If the DataPropertyName field doesn't contain a dot character, then the actual value of the base data type property must be displayed - in this case no action is required, since it is already filled in &lt;span class="inline-code"&gt;e.Value&lt;/span&gt;.&lt;br /&gt;
On the other hand, if the &lt;span class="inline-code"&gt;DataPropertyName&lt;/span&gt; field contains one or more dot characters, then it points to a property exposed by one of the bound class properties. For example, Address.Street contains the dot character, and it points to the Street property of the Address property inside a Customer's instance.&lt;br /&gt;
To handle this cases,&amp;nbsp; a recursive function &lt;span class="inline-code"&gt;BindProperty&lt;/span&gt; is used:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private void gridCustomers_CellFormatting(
  object sender, 
  DataGridViewCellFormattingEventArgs e)
{
  if ((gridCustomers.Rows[e.RowIndex].DataBoundItem != null) &amp;amp;&amp;amp; 
      (gridCustomers.Columns[e.ColumnIndex].DataPropertyName.Contains(".")))
  {
	e.Value = BindProperty(
                gridCustomers.Rows[e.RowIndex].DataBoundItem,
                gridCustomers.Columns[e.ColumnIndex].DataPropertyName
              );
  }
}&lt;/pre&gt;
The &lt;span class="inline-code"&gt;BindProperty &lt;/span&gt;function resolves the data property name and provides the actual value to be displayed in the grid cell by using reflection and (if required) recursion. Two arguments are passed to the &lt;span class="inline-code"&gt;BindProperty&lt;/span&gt; function: the class property value (which is an instance of a class, in the above example an instance of the &lt;span class="inline-code"&gt;Address&lt;/span&gt; class) and the &lt;span class="inline-code"&gt;DataPropertyName:&lt;/span&gt;&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private string BindProperty(object property, string propertyName)
{
  ...
}&lt;/pre&gt;
The first thing to check is whether the property name contains the dot character - although this never happen when called directly from the &lt;span class="inline-code"&gt;CellFormatting&lt;/span&gt; event handler, since the &lt;span class="inline-code"&gt;if&lt;/span&gt; statement prevent this, it may happen when &lt;span class="inline-code"&gt;BindProperty&lt;/span&gt; calls itself recursively.&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private string BindProperty(object property, string propertyName)
{
  if (propertyName.Contains("."))
  {
    ...
  }
  else
  {
    ...
  }
}&lt;/pre&gt;
If the property name doesn't contain any dot character, then the &lt;span class="inline-code"&gt;propertyName&lt;/span&gt; variable contains the name of the &lt;span class="inline-code"&gt;property&lt;/span&gt; object to be displayed in the grid. Reflection is used to read the property value, obtained by retrieving the &lt;span class="inline-code"&gt;PropertyInfo&lt;/span&gt; from the &lt;span class="inline-code"&gt;property&lt;/span&gt; variable, and then getting the property value by calling the &lt;span class="inline-code"&gt;GetValue()&lt;/span&gt; method of the &lt;span class="inline-code"&gt;PropertyInfo&lt;/span&gt; instance:&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private string BindProperty(object property, string propertyName)
{
  string retValue = "";
  
  if (propertyName.Contains("."))
  {
    ...
  }
  else
  {
    Type propertyType;
    PropertyInfo propertyInfo;

    propertyType = property.GetType();
    propertyInfo = propertyType.GetProperty(propertyName);
    retValue = propertyInfo.GetValue(property, null).ToString();
  }
}&lt;/pre&gt;
This completes the else branch. As for the if branch, it is executed when the property name contains at least one dot character. In this case, still using reflection, the &lt;span class="inline-code"&gt;PropertyInfo&lt;/span&gt; of the desired property is retrieved, and using recursion, passed to the same &lt;span class="inline-code"&gt;BindProperty&lt;/span&gt; function.&lt;br /&gt;
&lt;pre class="brush: c-sharp"&gt;private string BindProperty(object property, string propertyName)
{
  string retValue = "";

  if (propertyName.Contains("."))
  {
    PropertyInfo[] arrayProperties;
    string leftPropertyName;

    leftPropertyName = propertyName.Substring(0, propertyName.IndexOf("."));
    arrayProperties = property.GetType().GetProperties();

    foreach (PropertyInfo propertyInfo in arrayProperties)
    {
      if (propertyInfo.Name == leftPropertyName)
      {
        retValue = BindProperty(
          propertyInfo.GetValue(property, null), 
          propertyName.Substring(propertyName.IndexOf(".") + 1));
        break;
      }
    }
  }
  else
  {
    Type propertyType;
    PropertyInfo propertyInfo;

    propertyType = property.GetType();
    propertyInfo = propertyType.GetProperty(propertyName);
    retValue = propertyInfo.GetValue(property, null).ToString();
  }

  return retValue;
}&lt;/pre&gt;
The &lt;span class="inline-code"&gt;leftPropertyName&lt;/span&gt; variable holds the name of the leftmost property, for instance if &lt;span class="inline-code"&gt;propertyName&lt;/span&gt; is Address.Street, it is filled in with &lt;span class="inline-code"&gt;Address&lt;/span&gt;. By looping through the array of &lt;span class="inline-code"&gt;PropertyInfo&lt;/span&gt; of the &lt;span class="inline-code"&gt;property&lt;/span&gt; object, the &lt;span class="inline-code"&gt;PropertyInfo&lt;/span&gt; instance of the &lt;span class="inline-code"&gt;leftPropertyName&lt;/span&gt; property is retrieved. Then, &lt;span class="inline-code"&gt;BindProperty&lt;/span&gt; is called again, passing the instance of the &lt;span class="inline-code"&gt;leftPropertyName&lt;/span&gt; property and the right part of &lt;span class="inline-code"&gt;propertyName&lt;/span&gt; (for instance, for &lt;span class="inline-code"&gt;Address.Street&lt;/span&gt; the provided property name is &lt;span class="inline-code"&gt;Street&lt;/span&gt;).&lt;br /&gt;
&lt;br /&gt;
Souce code available at github:&amp;nbsp;&lt;a href="https://github.com/jeden/DataGridViewSample"&gt;DataGridViewSample&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-8092880497961902231?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5rBStie910L160CEYX_dIAsg03M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5rBStie910L160CEYX_dIAsg03M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5rBStie910L160CEYX_dIAsg03M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5rBStie910L160CEYX_dIAsg03M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/3caqhsrZQEM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/8092880497961902231/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2007/07/datagridview-how-to-bind-nested-objects_18.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8092880497961902231?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/8092880497961902231?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/3caqhsrZQEM/datagridview-how-to-bind-nested-objects_18.html" title="DataGridView: how to bind nested objects" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.developer-corner.com/2007/07/datagridview-how-to-bind-nested-objects_18.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8DQ3s5eyp7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-6373444997559365153</id><published>2006-09-30T22:42:00.000-07:00</published><updated>2011-06-14T22:47:52.523-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:47:52.523-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="sso" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Single Sign On across multiple ASP.NET applications</title><content type="html">&lt;div style="padding-bottom: 5px; background-color: #eee; padding-left: 5px; width: 300px; padding-right: 5px; float: right; padding-top: 10px" class="focus-right"&gt; &lt;h3&gt;Machine Key&lt;/h3&gt; &lt;p&gt;The &lt;span class="inline-code"&gt;machineKey&lt;/span&gt; element of the web.config file is used to specify keys for encryption and decryption of forms authentication cookies and view state data, and also when dealing with out of process session state. &lt;br&gt;The default configuration uses auto generated decryption key and validation key, and SHA1 encryption type. &lt;br&gt;Using the default configuration, different web applications have different decryption and validation key, since they are randomly generated. To force 2 applications to use the same keys, they must be explicitly defined i&lt;span class="style1"&gt;n the web.config file&lt;/span&gt; &lt;br&gt;A complete description of the &lt;span class="inline-code"&gt;machineKey&lt;/span&gt; element is available &lt;a href="http://msdn2.microsoft.com/en-us/library/w8h3skw9.aspx" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/div&gt; &lt;h3&gt;Single Sign On&lt;/h3&gt; &lt;p&gt;&lt;span class="highlight"&gt;Single Sign On (SSO)&lt;/span&gt; is a term used to indicate when a pool of applications need a centralized authentication, so that users login once and access to any application.&lt;/p&gt; &lt;p&gt;Implementing a single sign on is quite simple, and can be done by configuring the applications using the web.config file.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;A default configuration for forms authentication is defined as follows:&lt;/p&gt;&lt;pre class="brush: xhtml"&gt;&amp;lt;configuration&amp;gt; 
  ... 
  &amp;lt;system.web&amp;gt; 
    ... 
    &amp;lt;authentication mode="Forms"&amp;gt; 
      &amp;lt;forms name=".cookiename" 
             loginUrl="~/Login.aspx" 
             timeout="30" 
             path="/" /&amp;gt; 
    &amp;lt;/authentication&amp;gt; 
    ... 
  &amp;lt;/system.web&amp;gt; 
  ... 
&amp;lt;/configuration&amp;gt; &lt;/pre&gt;
&lt;div style="padding-bottom: 5px; background-color: #eee; padding-left: 5px; width: 300px; padding-right: 5px; float: right; padding-top: 10px" class="focus-right"&gt;
&lt;h3&gt;Form Authentication&lt;/h3&gt;
&lt;p&gt;Forms Authentication uses an authentication ticket stored in either a cookie or embedded i&lt;span class="style1"&gt;n the url. &lt;br&gt;&lt;br&gt;When used in cookie mode, the c&lt;/span&gt;ookie contains authentication data, encrypted so that data can be read by the application who has created the cookie.&lt;/p&gt;
&lt;p&gt;Cookies are associated to 2nd level domains (example.com), and can be accessed from any 3rd level domain (www.example.com, test.example.com, and so on).&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;where &lt;code class="inline-code"&gt;.cookiename, by default, is&lt;/code&gt; &lt;code class="inline-code"&gt;.ASPXFORMSAUTH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In order for authentication data to be recognized across multiple applications, each application must be configured to use the same values for cookie name, protection and path attributes. But this isn't enough - in fact, they must also have the same machine key values (see the side box for more info about the &lt;span class="inline-code"&gt;machineKey&lt;/span&gt; element). These information are used to encrypt the forms authentication cookie, as mentioned in the "Forms Authentication" side box.&lt;/p&gt;
&lt;p&gt;Below a sample web.config excerpt which must be added to each application we want single sign on enabled. In this sample, the validationKey and encryptionKey attributes must be replaced with unique values you have to generate for your applications pool.&lt;/p&gt;&lt;pre class="brush: xhtml"&gt;&amp;lt;configuration&amp;gt; 
  ... 
  &amp;lt;system.web&amp;gt; 
    ... 
    &amp;lt;authentication mode="Forms"&amp;gt; 
      &amp;lt;forms name=".cookiename" 
             loginUrl="~/Login.aspx" 
             timeout="30" 
             path="/" 
      /&amp;gt; 
    &amp;lt;/authentication&amp;gt; 
    ... 
    &amp;lt;machineKey 
       validationKey= 
         "F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902" 
      encryptionKey= 
         "F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC" 
      validation="SHA1" 
    /&amp;gt; 
    ... 
  &amp;lt;/system.web&amp;gt; 
  ... 
&amp;lt;/configuration&amp;gt; &lt;/pre&gt;
&lt;h3&gt;Second and third level domains&lt;/h3&gt;
&lt;p&gt;If the cooperating applications are installed under the same 2nd and 3rd level domain, but on different virtual folders, then no additional code is required.&lt;/p&gt;
&lt;p&gt;If applications are installed on different second level domains (www.domain1.com and www.domain2.com), the SSO method described in this article won't work, since cookies cannot be read by applications under different second level domains. For example, if application A in domain1.com issues a cookie, the cookie may be read by A itself and any application hosted under &lt;a href="http://www.domain1.com"&gt;www.domain1.com&lt;/a&gt; and any other 3rd level domain (test.domain1.com, beta.domain1.com, and so on). Application B in domain2.com isn't able to read the cookie, since it is hosted under a different second level domain.&lt;/p&gt;
&lt;p&gt;If cooperating applications are installed on different third level domains, then we need to add some code in order to make SSO work. The code simply has to add the domain name to the authentication cookie, as outlined below&lt;/p&gt;&lt;pre class="brush: c-sharp"&gt;protected void Login (string strUserName, ...) 
{ 
  ... 
  System.Web.HttpCookie cookie; 

  cookie = FormsAuthentication.GetAuthCookie(strUserName, False); 
  cookie.Domain = "domain1.com"; 
  cookie.Expires = DateTime.Now.AddDays (-1); 
  Response.AppendCookie (cookie); 
  ... 
} &lt;/pre&gt;
&lt;h3&gt;Cookie Expiration&lt;/h3&gt;
&lt;p&gt;If different applications set different cookie expirations, the actual expiration value is the one set by the application which issued it. So if application A is configured to set an expiration of 1 hour and application B 2 hours, and the user signs in using application B, then the cookie expiration is set to 2 hours.&lt;/p&gt;
&lt;h3&gt;Logging out&lt;/h3&gt;
&lt;p&gt;Usually, in order to log out a user, a call to the &lt;span class="inline-code"&gt;Authentication.SignOut()&lt;/span&gt; method is used - this isn't enough when using SSO. In order to perform a single sign out, the quickest way is to set the cookie expiration to a past date - this ensures that the cookie won't be used by any application for authentication.&lt;/p&gt;&lt;pre class="brush: c-sharp"&gt;protected void Logout (string strUserName) 
{ 
  System.Web.HttpCookie cookie; 

  cookie = FormsAuthentication.GetAuthCookie(strUserName, false); 
  cookie.Domain = "domain1.com"; 
  cookie.Expires = DateTime.Now.AddDays (-1); 
  Response.AppendCookie (cookie); 
}&lt;/pre&gt;
&lt;h3&gt;Integrating Web Applications&lt;/h3&gt;
&lt;p&gt;What said so far is valid if applications use the same database to store user profiles. But what if 2 applications use each one their own database?&lt;/p&gt;
&lt;p&gt;In this case, the SSO works, but sooner or later one of the applications will throw exceptions due to missing data in its database. If a user registers in application A, once he signs in he can access to application B - but he never registered in application B, so application B doesn't have this user in its database.&lt;/p&gt;
&lt;p&gt;This is the case when, for example, we have to integrate 2 existing applications, which already have their own authentication and registration implemented.&lt;/p&gt;
&lt;p&gt;To solve this problem, we have 2 choices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;modify both application in order to use a single authentication and registration process, and having a shared user profile repository 
&lt;li&gt;choose one application as the master application, and remove the authentication and registration process from the other application (the slave application) &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;We'll focus on the second solution.&lt;/p&gt;
&lt;p&gt;This method requires that the database used by slave applications is accessible by the master application. This can be achieved by either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a single database which holds both application databases. In this case it would be good to use different prefixes for database entities to avoid naming conflicts - this could happen if both databases have a &lt;span class="inline-code"&gt;Users &lt;/span&gt;table. If we choose &lt;span class="inline-code"&gt;mst &lt;/span&gt;and &lt;span class="inline-code"&gt;slv &lt;/span&gt;as prefixes, we should rename the &lt;span class="inline-code"&gt;Users &lt;/span&gt;table to &lt;span class="inline-code"&gt;mst_Users &lt;/span&gt;for the master database and &lt;span class="inline-code"&gt;slv_Users &lt;/span&gt;for the slave database. This requires that we modify the source code and stored procedures. 
&lt;li&gt;Use 2 different databases, but the master application must be able to access to the slave's database. &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Authentication should be performed in the following way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The user accesses to the master application, and signs in 
&lt;li&gt;The master application verifies the user's credentials 
&lt;li&gt;The master application verifies whether the logged user is defined in the slave database - if not, accesses to the slave's database and creates the new user 
&lt;li&gt;The master application calls (if existing) a slave's stored procedure which performs post-authentication processing (such as setting a "logged in" field, inserting a new row in a history table, and so on) 
&lt;li&gt;The master application generates the SSO cookie &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;User profile creation on the slave database requires that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the master application is able to access to the slave's database 
&lt;li&gt;the slave's database exposes a stored procedure which handles user registration (we may need to write it by ourselves) &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The second requirement isn't mandatory, since it could also be achieved by using inline SQL - but I usually prefer the stored procedure solution.&lt;/p&gt;
&lt;h3&gt;Final touch&lt;/h3&gt;
&lt;p&gt;There would be a few final things to do on the slave application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removal of all login links 
&lt;li&gt;Replacement of logout links with a "Back to the Master application" link 
&lt;li&gt;Replacement of all "User's profile" links to point to the master application user's profile page &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;These steps ensure that navigation is consistent with integration - we're supposing that all user's info (credentials, profile, user's preferences) are handled by the master application, so we need to modify the slave application accordingly. It is responsibility of the master application to update user's profile in the slave application.&lt;/p&gt;
&lt;h3&gt;What if different cookies are used?&lt;/h3&gt;
&lt;p&gt;There may be cases where we want to keep authentication cookies separated from master and slaves applications. In this case we can't share the authentication cookie among cooperating applications.&lt;/p&gt;
&lt;p&gt;In this case the solution is to create an authentication cookie for the slave application from within the master application.&lt;/p&gt;
&lt;p&gt;The code below creates an authentication cookie from the slave application:&lt;/p&gt;&lt;pre class="brush: c-sharp; toolbar: false"&gt;FormsAuthenticationTicket ticket; 
HttpCookie cookie; 
string cookiestr; 

ticket = new FormsAuthenticationTicket( 
                       1, 
                       userId, 
                       DateTime.Now, 
                       DateTime.Now.AddYears (120), 
                       true, 
                       "User Data", 
                       "cookie_path" 
           ); 

cookiestr = FormsAuthentication.Encrypt(ticket); 
cookie = new HttpCookie("cookie_name", cookiestr); 
cookie.Expires = ticket.Expiration; 
cookie.Path = "cookie_path"; 

Response.Cookies.Add(cookie); &lt;/pre&gt;
&lt;div style="padding-bottom: 5px; background-color: #eee; padding-left: 5px; width: 300px; padding-right: 5px; float: right; padding-top: 10px" class="focus-right"&gt;
&lt;h3&gt;Forms Authentication Ticket&lt;/h3&gt;
&lt;p&gt;The &lt;code class="inline-code"&gt;FormsAuthenticationTicket&lt;/code&gt; class is used to create and read the values of a forms authentication cookie identifying an authenticated user.&lt;/p&gt;
&lt;p&gt;Forms authentication tickets must be encrypted using the &lt;span class="inline-code"&gt;FormsAuthentication.Encrypt()&lt;/span&gt; method before being issued as a cookie.&lt;/p&gt;
&lt;p&gt;More information about the&amp;nbsp; &lt;span class="inline-code"&gt;FormsAuthenticationTicket &lt;/span&gt;class can be found &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class="inline-code"&gt;FormsAuthenticationTicket&lt;/code&gt;, as its name says, is a class used to generate authentication tickets (see the side box for more details). The code sample above shows that the following parameters are used to create the ticket:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ticket version number 
&lt;li&gt;user id 
&lt;li&gt;date and time at which the ticket was generated 
&lt;li&gt;ticket expiration 
&lt;li&gt;whether creating a persistent cookie or limited to the current browser's session 
&lt;li&gt;user specific data to be stored in the ticket (for example, this could be a user class) 
&lt;li&gt;cookie path &lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/w8h3skw9.aspx"&gt;MSDN - machineKey element&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.aspx"&gt;MSDN - FormsAuthenticationTicket class&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-6373444997559365153?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qjB2GVASNa609tnGMw92kfVhRyI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qjB2GVASNa609tnGMw92kfVhRyI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qjB2GVASNa609tnGMw92kfVhRyI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qjB2GVASNa609tnGMw92kfVhRyI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/nDnl1BdQIIA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/6373444997559365153/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2006/09/single-sign-on-across-multiple-aspnet.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/6373444997559365153?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/6373444997559365153?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/nDnl1BdQIIA/single-sign-on-across-multiple-aspnet.html" title="Single Sign On across multiple ASP.NET applications" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2006/09/single-sign-on-across-multiple-aspnet.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ABR388eCp7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-6138731001966106748</id><published>2006-07-27T22:28:00.000-07:00</published><updated>2011-06-14T22:29:16.170-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:29:16.170-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="RSS/Atom" /><title>Quickly add feed capabilities to your PHP application</title><content type="html">&lt;p&gt;Although feeds aren't a new invention, lately they are getting more popular. Using feeds, we have an easy and convenient way to publish content, either news or any other sources (blogs, articles, etc.)&lt;/p&gt; &lt;p&gt;I had to implement feeding capabilities to a PHP application I'm working on, and I've been suggested to use &lt;a href="http://www.bitfolge.de/rsscreator-en.html" target="_blank"&gt;FeedCreator&lt;/a&gt;, an open source library written, by Kai Blankenhorn, which provides support for the following feeds:&lt;/p&gt; &lt;div class="hint-right"&gt;&lt;/div&gt; &lt;ul&gt; &lt;li&gt;RSS (0.91, 1.0, 2.0)  &lt;li&gt;PIE (0.1)  &lt;li&gt;MBOX  &lt;li&gt;OPML  &lt;li&gt;ATOM  &lt;li&gt;HTML  &lt;li&gt;JS &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The most diffused are undoubtedly RSS and Atom, but if you need less known format you can.&lt;/p&gt; &lt;p&gt;Adding feeds to your application is as simple as writing the following code (taken from the library documentation):&lt;/p&gt;&lt;pre class="brush: php"&gt;include("feedcreator.class.php"); 

$rss = new UniversalFeedCreator(); 
$rss-&amp;gt;useCached(); // use cached version if age&amp;lt;1 hour 
$rss-&amp;gt;title = "PHP news"; 
$rss-&amp;gt;description = "daily news from the PHP scripting world"; 

//optional 
$rss-&amp;gt;descriptionTruncSize = 500; 
$rss-&amp;gt;descriptionHtmlSyndicated = true; 

$rss-&amp;gt;link = "http://www.dailyphp.net/news"; 
$rss-&amp;gt;syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; 

$image = new FeedImage(); 
$image-&amp;gt;title = "dailyphp.net logo"; 
$image-&amp;gt;url = "http://www.dailyphp.net/images/logo.gif"; 
$image-&amp;gt;link = "http://www.dailyphp.net"; 
$image-&amp;gt;description = "Feed provided by dailyphp.net. Click to visit."; 

//optional 
$image-&amp;gt;descriptionTruncSize = 500; 
$image-&amp;gt;descriptionHtmlSyndicated = true; 

$rss-&amp;gt;image = $image; 

// get your news items from somewhere, e.g. your database: 
mysql_select_db($dbHost, $dbUser, $dbPass); 
$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); 
while ($data = mysql_fetch_object($res)) { 
$item = new FeedItem(); 
$item-&amp;gt;title = $data-&amp;gt;title; 
$item-&amp;gt;link = $data-&amp;gt;url; 
$item-&amp;gt;description = $data-&amp;gt;short; 

//optional 
item-&amp;gt;descriptionTruncSize = 500; 
item-&amp;gt;descriptionHtmlSyndicated = true; 

$item-&amp;gt;date = $data-&amp;gt;newsdate; 
$item-&amp;gt;source = "http://www.dailyphp.net"; 
$item-&amp;gt;author = "John Doe"; 

$rss-&amp;gt;addItem($item); 
} 

// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), 
// MBOX, OPML, ATOM, ATOM0.3, HTML, JS 
echo $rss-&amp;gt;saveFeed("RSS1.0", "news/feed.xml");&lt;/pre&gt;
&lt;p&gt;What makes it so special is that it is really simple to use.&lt;/p&gt;
&lt;p&gt;The libray is open source, released under the LGPL license.&lt;/p&gt;
&lt;p&gt;For more information and to download the library, click &lt;a href="http://www.bitfolge.de/rsscreator-en.html" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-6138731001966106748?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/NQ9Mj7zv2oLywCyurZxtvZp-JG0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NQ9Mj7zv2oLywCyurZxtvZp-JG0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/NQ9Mj7zv2oLywCyurZxtvZp-JG0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NQ9Mj7zv2oLywCyurZxtvZp-JG0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/rFjc4hdmotw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/6138731001966106748/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2006/07/quickly-add-feed-capabilities-to-your_27.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/6138731001966106748?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/6138731001966106748?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/rFjc4hdmotw/quickly-add-feed-capabilities-to-your_27.html" title="Quickly add feed capabilities to your PHP application" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2006/07/quickly-add-feed-capabilities-to-your_27.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04NQHY-cSp7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-1271887539031867053</id><published>2006-07-11T22:31:00.000-07:00</published><updated>2011-06-14T22:33:11.859-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:33:11.859-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="codecharge studio" /><title>How to prevent validation errors from being displayed in CodeCharge Studio</title><content type="html">&lt;p&gt;I have a registration form which uses 2 dependent list boxes Country and State, where State is populated basing on the Country selection.&lt;/p&gt; &lt;p&gt;To dynamically load the State list box I had to add a client &lt;span class="inline-code"&gt;OnChange&lt;/span&gt; event to the Country list box, which submits the form. But at this point the form displays all errors (mostly missing fields) and I don't want this to happen.&lt;/p&gt; &lt;p&gt;This is the solution I found, which uses client side JavaScript:&lt;/p&gt; &lt;p&gt;The name of my form is &lt;span class="inline-code"&gt;RegisteredUser&lt;/span&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;I have added a hidden field to the form, with name  &lt;div class="inline-code"&gt;Validation, Control Source Type = "&lt;span class="inline-code"&gt;Code Expression&lt;/span&gt;", type &lt;span class="inline-code"&gt;Boolean &lt;/span&gt;and default value = &lt;span class="inline-code"&gt;True &lt;/span&gt;&lt;/div&gt; &lt;li&gt;I've added a client &lt;span class="inline-code"&gt;OnChange&lt;/span&gt; event to the Country list box, with the following code:  &lt;div class="embedded-code-boxed"&gt;document.forms["RegisteredUser"].Validation.value = "No"; &lt;br&gt;document.forms["RegisteredUser"].submit(); &lt;/div&gt; &lt;li&gt;In the HTML code, I've located the &lt;span class="inline-code"&gt;{Errors}&lt;/span&gt; row, and set the &lt;span class="inline-code"&gt;id &lt;/span&gt;and &lt;span class="inline-code"&gt;name &lt;/span&gt;attributes to &lt;span class="inline-code"&gt;phErrors&lt;/span&gt; - it should look like: &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;!-- BEGIN Error --&amp;gt; 
&amp;lt;tr class="Error" id="phErrors" name="phErrors"&amp;gt; 
  &amp;lt;td colspan="2"&amp;gt;{Error}&amp;lt;/td&amp;gt; 
&amp;lt;/tr&amp;gt; 
&amp;lt;!-- END Error --&amp;gt; &lt;/pre&gt;
&lt;li&gt;I've added a client &lt;span class="inline-code"&gt;OnLoad &lt;/span&gt;event to the form, with the following code: 
&lt;div class="embedded-code-boxed"&gt;var phErrors = document.getElementById ("phErrors"); &lt;pre class="brush: php"&gt;if (phErrors != null) 
{ 
  if (document.forms["RegisteredUser"].Validation.value == "No") 
  { 
    document.forms["RegisteredUser"].Validation.value = "Yes"; 
    phErrors.style.visibility = "hidden"; 
    phErrors.style.position = "absolute"; 
  } 
  else 
  { 
    phErrors.style.visibility = "visible"; 
    phErrors.style.position = "relative"; 
  } 
} 
&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;This code reads the value of the &lt;span class="inline-code"&gt;Validation&lt;/span&gt; hidden field: if the value is &lt;span class="inline-code"&gt;No&lt;/span&gt;, the &lt;span class="inline-code"&gt;phErrors &lt;/span&gt;row is hidden, otherwise it is shown.&lt;/p&gt;
&lt;p&gt;It seems to work correctly, and also it shouldn't add the row to the database, because the validation occurs at server side, but it isn't displayed at client side (although included in the HTML).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-1271887539031867053?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Uo81wPN4fCb41cVEoeWQBL5YP8Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Uo81wPN4fCb41cVEoeWQBL5YP8Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Uo81wPN4fCb41cVEoeWQBL5YP8Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Uo81wPN4fCb41cVEoeWQBL5YP8Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/bDtJBj5K0x0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/1271887539031867053/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2006/07/how-to-prevent-validation-errors-from_11.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/1271887539031867053?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/1271887539031867053?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/bDtJBj5K0x0/how-to-prevent-validation-errors-from_11.html" title="How to prevent validation errors from being displayed in CodeCharge Studio" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2006/07/how-to-prevent-validation-errors-from_11.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYGRXkyfip7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-3596068608455764071</id><published>2006-07-10T22:34:00.000-07:00</published><updated>2011-06-14T22:35:24.796-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:35:24.796-07:00</app:edited><title>How to fight against spamming</title><content type="html">&lt;p&gt;I receive about 20 spam messages in my mailbox every day. I know this can be considered a low number, since I know of users receiving hundreds of spam, with a variety of subjects, ranging from porn sites to viagra, medicines, casino, software, etc.&lt;/p&gt; &lt;div class="hint-left"&gt;SpamCop parses reported email, sending warning information to the internet service provider responsible for hosting the services used by the spammer&lt;/div&gt; &lt;p&gt;I wonder how can these spammers think that I'm so stupid to use my credit card to buy their products - but indeed I'm afraid that if they persist in their illegal business is because there are people who buy from them.&lt;/p&gt; &lt;p&gt;Anyway, what can we do to fight against them? There are several services which detect messages and prevent them from reaching our mail client, and mail client add-ons which move suspect messages into a spam folder, so that we don't have to waste time reading messages we aren't interested in. But is this a good way to fight spammers? Do they prevent spammers from sending you emails if you don't buy from them? Unfortunately I don't think so.&lt;/p&gt; &lt;p&gt;What can we do? Report spam.&lt;/p&gt; &lt;p&gt;Since Internet has no country borders, it's quite unlikely that recurring to law leads to a result, although I think this could be done - but unfortunately it doesn't happen.&lt;/p&gt; &lt;p&gt;The only thing I can do is to repay them with the same money: making them waste time.&lt;/p&gt; &lt;div class="right-box"&gt;&lt;script type=text/javascript&gt;&lt;!--
google_ad_client = "pub-5133511524656449";
google_ad_width = 250;
google_ad_height = 250;
google_ad_format = "250x250_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "F59191";
google_color_bg = "FFFFFF";
google_color_link = "0000FF";
google_color_text = "000000";
google_color_url = "008000";
//--&gt;&lt;/script&gt; &lt;p&gt;How? I started my "war" by locating, for each spam email:&lt;/p&gt;&lt;/div&gt; &lt;ul&gt; &lt;li&gt;the ISP used by the spammer to send the email  &lt;li&gt;the web hosting company which hosts the site referenced in the spam email &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The next step was to write a complain email to both recipients, asking for the spammer's account to be suspended. This way, the spammer needs to change ISP and move its website to another hosting provider. This is a cost of their business, and I'm sure spammers have planned it - and I also want to be sure to keep this cost high for them.&lt;/p&gt; &lt;p&gt;I was used to perform these actions manually, by reading the email header, and using tools such as nslookup to find what I needed, but this is undoubtedly a time consuming process, and I did it while the number of spams was less than 10 per day.&lt;/p&gt; &lt;p&gt;But there is a better way: a service where you simply have to report the mail body and headers, and it will take care of reverse-engineering the information required, automatically fill in complaint reports and send them to the proper recipients. Its name is SpamCop, and their website is &lt;a href="http://www.spamcop.net"&gt;www.spamcop.net&lt;/a&gt;. Although the service requires a subscription (quite low, since it is about 1$ for each Mbyte of reported spam), it can also be used for free, in this case with a delay screen which reminds about subscribing - about 10 seconds to wait before completing the spam email analysis.&lt;/p&gt; &lt;p&gt;This of course doesn't guarantee that actions are taken against spammers. There are ISP which themselves fight against spammers, and once they receive reports they verify, and if required take their actions, which can range from deactivating the spammer's accounts to charge them and using legal ways (but this last one is the least used - unfortunately).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-3596068608455764071?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YePLibohTXEXMb5pvC4OQRbFpMg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YePLibohTXEXMb5pvC4OQRbFpMg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YePLibohTXEXMb5pvC4OQRbFpMg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YePLibohTXEXMb5pvC4OQRbFpMg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/TkWXhX6J0oU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/3596068608455764071/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2006/07/how-to-fight-against-spamming_10.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3596068608455764071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3596068608455764071?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/TkWXhX6J0oU/how-to-fight-against-spamming_10.html" title="How to fight against spamming" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2006/07/how-to-fight-against-spamming_10.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQFQnw5eyp7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-78936403505762774</id><published>2006-07-03T22:37:00.000-07:00</published><updated>2011-06-14T22:38:33.223-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:38:33.223-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>How to better appreciate your most preferred language</title><content type="html">&lt;h3&gt;The universal technology&lt;/h3&gt; &lt;p&gt;I've seen a lot of developers telling that Linux is better than Windows, C# is better than Java, Delphi is better than VC++, and so on. But if you ask them if they know the other language they are comparing with, they say no.&lt;/p&gt; &lt;p&gt;I was one of them, since I believed that the best IDE was Delphi, the best platform was Windows, and the best language was C++. At least, until I started working on "real projects" and not on applications made just for fun. When I had to learn Java and use it to develop server applications on Sun platforms, I started to appreciate the language and the Unix-like environments.... and I started to believe that these technologies were better than those I thought were the best. Soon I realized that every technology is the best, depending on where it is applied.&lt;/p&gt; &lt;blockquote&gt; &lt;div class="hint-left"&gt;There is no universal technology or language which solves all problems&lt;/div&gt;&lt;/blockquote&gt; &lt;p&gt;Now I don't believe anymore that there is the universal technology or language which solves all problems. Every time I start a new project, if the customer doesn't have a specific preference, I always spend some time trying to understand what are the best tools to implement the project - and the result depends from the project itself. In web development my favorite preference is the .NET technology, for several reasons - but this is not a choice that can be done every time for every project. For example, if one of the requirements is that the application must run on open source environments, .NET wouldn’t be the proper choice.&lt;/p&gt; &lt;h3&gt;The proper tools&lt;/h3&gt; &lt;p&gt;During my professional experience I've tried to learn as many languages as possible. If I get confident knowledge of each language, I'm able to choose the best solution for every problem, from both the developer point of view (how simple or hard is the development using a specific language) as well as from the customer/project point of view (what are the benefits if I choose a technology instead of another). When I learned Java, I appreciated how life is easier with a memory manager which automatically disposes objects no longer referenced. When I learned C#, I appreciated the integration with the .NET technology, the foreach statement, but I also noticed how exception handling was better in Java, since exceptions must be explicitly handled within each method or the method itself must be declared to throw those exceptions which aren't handled in its body. I also, and still, like the C++ philosophy: "The developer always knows what he's doing". This is the reason why C++ offers more power with pointers and access to memory. It's irrelevant that it's not always true the developer always knows what he is doing :-) The key point is that you have the power to do almost everything, although at a price (usually more attention when dealing with pointers and dynamically allocated memory, and more debugging....)&lt;/p&gt; &lt;h3&gt;PHP Revolution&lt;/h3&gt; &lt;p&gt;Lately I've appreciated a language I've used in the past, and which I didn't like: PHP. The reason why I don't like PHP is that I prefer strongly typed variables, variable declarations, as well as to know from the compiler if I wrote something wrong in my code, such as the name of a variable (a common mistake in PHP which leads to unpredictable results) or a function call (which usually leads to a run-time error). But I have to say that it's extremely practical the ability to save your PHP code and test it immediately without the need of recompilation, deployment, etc. - a perfect solution for the project I'm currently working on. And I wouldn't had chosen it if the customer hadn't explicitly asked for it. &lt;strong&gt;We never stop learning&lt;/strong&gt;!! Now I'll definitively choose it again in the future, if the prerequisites for its usage are good, and the project will benefit from its usage.&lt;/p&gt; &lt;h3&gt;Can I say that C# is better than Java?&lt;/h3&gt; &lt;p&gt;Yes and no. It depends. As outlined above, in order to state that a language or technology is better than another, I need to:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;have proficient knowledge of both  &lt;li&gt;compare pro and cons applied to a specific project &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;But the result of the comparison is limited to the project - on a different project, the choice could be different:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;if I need to care about speed, maybe the best solution would be C++, but not for web applications  &lt;li&gt;if I need portability, Java is best - but I wouldn't choose it if the application has a user interface  &lt;li&gt;if I need modularity and easy of development on a web application, my choice would fall on ASP.NET  &lt;li&gt;if I need low licenses cost, the choice could be PHP, Java/JSP, or Ruby On Rails &lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Your opinion&lt;/h3&gt; &lt;p&gt;How do you choose the technologies and languages on your projects? Do you focus on a single technology, and use others only when the customer explicitly asks for them?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-78936403505762774?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/TdoJqCDFLhpOE0TOdXKcnM5slNA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TdoJqCDFLhpOE0TOdXKcnM5slNA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/TdoJqCDFLhpOE0TOdXKcnM5slNA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TdoJqCDFLhpOE0TOdXKcnM5slNA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/z2xAs0lnmkk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/78936403505762774/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2011/06/how-to-better-appreciate-your-most.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/78936403505762774?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/78936403505762774?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/z2xAs0lnmkk/how-to-better-appreciate-your-most.html" title="How to better appreciate your most preferred language" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2011/06/how-to-better-appreciate-your-most.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMHQnczfip7ImA9WhZbEUw.&quot;"><id>tag:blogger.com,1999:blog-5624102086037960868.post-3312979473029608868</id><published>2006-07-01T22:39:00.000-07:00</published><updated>2011-06-14T22:40:33.986-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-14T22:40:33.986-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="learning" /><title>Learning by using</title><content type="html">&lt;h3&gt;The first computer&lt;/h3&gt; &lt;p&gt;I started dealing with development when I was 12, after I convinced my parents to buy me a computer. My choice fell on a Commodore Vic 20, a computer with a 1MHz CPU, 3582 bytes (bytes!!) of RAM memory, embedded basic language, and external memory storage based on a tape recorder.&lt;/p&gt; &lt;p&gt;I learned the computer principles, the way it works, the Basic language, the assembler language, how to deal with limited resources (such as memory) and how to develop software. I wrote a few games, just for fun - too young to think about how to make money with them :). Since then, I have ever learned, learned and learned, and almost all of what I know I learned by myself.&lt;/p&gt; &lt;h3&gt;The first job&lt;/h3&gt; &lt;p&gt;When I've been contacted by a company for my first "serious" job, I've been subject to a 2 weeks test to implement some new features on an existing FoxPro application before getting a contract. Never worked with FoxPro before, nor had experience with its scripting language and more generally with database development (just a few theorical concepts).&lt;/p&gt; &lt;p&gt;So, during these 2 weeks, I studied and learned FoxPro, its language, and how to use databases. Life isn't so easy, so 2 days before the end of my test period I had an HD failure, and of course I didn't have any backup - all work was lost. Since it was a new HD, we brought it to the support center, asking to repair it but preserving the data, if possible - after 1 hour, a technician get back to us telling "The hard disk is working so well that we've also formatted it". Panic.&lt;/p&gt; &lt;p&gt;Fortunately I've been able to recover all lost data by using an unformatting utility - with compliments of my boss, who told me "I don't know why, but I thought you were a database expert - I've just read your resume again, and I have no idea why I thought so. Anyway I like the way you work, so the job is yours".&lt;/p&gt; &lt;p&gt;My next task was a feasibility study about a QuickTime application running on a Mac to be used to display and record data retrieved from medical equipments - once again, I had no previous experience with QuickTime and Mac - nevertheless, this has been not only the first but also the last experience with a Mac :-). In 1 week, the time given to complete this task, I provided the results of the feasibility study - which were positive.&lt;/p&gt; &lt;h3&gt;Learning by Using&lt;/h3&gt; &lt;p&gt;What do I want to say?&lt;/p&gt; &lt;p&gt;Sometimes we have to learn a new language or technology, but we have no time to learn it since we also have to apply it in the project we have to work on, and which, surprisingly, must be completed within yesterday.&lt;/p&gt; &lt;p&gt;I'm used to learn everything I need in my work by myself. This is undoubtedly a great advantage, since I don't need to attend courses or use other forms of slow "formal learning".&lt;/p&gt; &lt;p&gt;What I mostly like is the ability to learn a new language or technology by using it on a real project. Of course this can't be done without having a proficient knowledge of the area being explored. If somebody has never developed or learned a programming language, it's extremely unlikely he will be able to learn using this learning pattern.&lt;/p&gt; &lt;p&gt;But if, for instance, you have done web development before, using ASP.NET, it wouldn't be difficult to move on PHP. Once you've acquired what web development means, what you expect to do and what tools you have to use and you are allowed to use, you're able to transpose this knowledge on the new language - it's just a matter of translating what you already know in a new context. You expect that, independently from the language you use, there is a way to handle sessions and cookies, to access to a database, to handle data submitted in a form, etc.&lt;/p&gt; &lt;p&gt;This is the reason why I like to learn new languages and technologies. I like the challenge of starting from a virtually unknown area, performing analysis and design on a real project basing on a few information I read here and there, and starting the development phase while starting the learning process at the same time. This process undoubtedly slows the development at beginning, to proceed at increased speed from day to day. And while proceeding with the learning process you also realize what you've made wrong - this sometimes requires re-working on the work made in the past days, but this way you better understand what you did wrong and you (hopefully) won't do it again.&lt;/p&gt; &lt;h3&gt;Formal learning&lt;/h3&gt; &lt;div class="hint-left"&gt;Actual knowledge is not as important as the ability to acquire that knowledge&lt;/div&gt; &lt;p&gt;Of course the "learning by using" pattern cannot be considered better than formal learning paths. Attending a course has its advantages, since who is teaching has proficient knowledge (or at least we hope he has :-)) and he can better show the key points and focus on the most important things to know, as well as explain best practices, things to know, things to avoid, and so on.&lt;/p&gt; &lt;p&gt;Also, reading a good book and doing practice, following code, examples and exercises, helps to get knowledge. Anyway I usually skip all of these extra activities, since I prefer to focus on understanding what the writer want to expose, catching the key points, just to know that "they exist" - when I need to use a specific feature, I know it is there, and I just have to browse the documentation to know how to use it.&lt;/p&gt; &lt;h3&gt;Knowledge or Pointers?&lt;/h3&gt; &lt;div class="hint-right"&gt;Ability to find pointers to knowledge is more important than actual knowledge&lt;/div&gt; &lt;p&gt;What I've just written above points me to the following consideration.&lt;/p&gt; &lt;p&gt;I strongly believe that actual knowledge is not as important as the ability to acquire that knowledge. Long time ago I've been told "it's not important if you have a specific knowledge - I care more if you are able to find the pointers to that knowledge".&lt;/p&gt; &lt;h3&gt;Conclusions&lt;/h3&gt; &lt;p&gt;Traditional learning (either school, courses, and so on) is important. But it isn't enough. Being able to self-learn helps when you have no time to use the traditional learning paths. Being able to learn while applying what you're learning is an extra gear. Being able to update your knowledge "on demand" is a double extra gear.&lt;/p&gt; &lt;p&gt;What are your learning methodologies? Do you want to add any comment, suggestion, or extend this discussion? Just write below...&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5624102086037960868-3312979473029608868?l=www.developer-corner.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/hF90x1p1IvyMt6JW3Wv7dloHefo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/hF90x1p1IvyMt6JW3Wv7dloHefo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/hF90x1p1IvyMt6JW3Wv7dloHefo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/hF90x1p1IvyMt6JW3Wv7dloHefo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/developer-corner/mhSH/~4/kYbZ15sfz0s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.developer-corner.com/feeds/3312979473029608868/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.developer-corner.com/2006/07/learning-by-using_01.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3312979473029608868?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5624102086037960868/posts/default/3312979473029608868?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/developer-corner/mhSH/~3/kYbZ15sfz0s/learning-by-using_01.html" title="Learning by using" /><author><name>Antonio Bello</name><uri>http://www.blogger.com/profile/18122584359572781154</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.developer-corner.com/2006/07/learning-by-using_01.html</feedburner:origLink></entry></feed>

