-
Published on 03 Jul 2006 from
Well, I must have spent about an hour today trying to figure out something that I assumed would be pretty trivial, in fact it was in the end but you know how it goes.
I was creating a simple registration page for a website which requires that the user agrees to the Terms and Conditions of the site before they can submit their registration details. To begin with, I had a check box that the user would have to tick in order to state that they agreed and only when this check box was checked would the submit button be enabled, however, as I had disabled the submit button on the load of the page, all other required field validators stopped working. I assume as the submit button was disabled, ASP.NET didn't feel the need to continue wiring up the validation code necessary. So I thought that I would use one of the validation controls to ensure that the check box was checked thus no need to disable the submit button.
After a little research, I found that the CustomValidator control would do the job for me, but nearly all of the examples I found seemed to either suggest that you had to write code in your code behind/beside file to register the necessary javascript on the page which I thought was a bit odd, or they just seemed overly complex. After a little playing around with various code snippets, I came up with what I thought was rather simple and not overly complex. Shame I didn't find it in the first place, it would have saved me a fair bit of time.
To test this out, create a new web form file and add a check box to the page named "chkTandCs", then add a CustomValidator control next to it and finally a button. In the source of the web form, add the following javascript function to the head section:
<script language="javascript" type="text/javascript">
function ValidateTandCs(source, args)
{
args.IsValid = document.getElementById('<%= chkTandCs.ClientID %><%= chkTandCs.ClientID %>').checked;
}
< FONT>script>
Now, modify your CustomValidator control so that it reads:
<asp:CustomValidator ID="valTandCs" ClientValidationFunction="ValidateTandCs" runat="server" ErrorMessage="Please accept Terms and Conditions before submitting.">< FONT>asp:CustomValidator>
Note the ClientValidationFunction property is set to the javascript function ValidateTandCs. If the check box is checked then the function in effect returns True and the page is posted, otherwise, the ErrorMessage property of the CustomValidator is displayed and the page is not posted. This works in exactly the same way as a normal RequiredFieldValidator but allows you to validate a check box. In essence, you could use this technique to validate any server side control.
To prove that it definitely worked, I added the following code to the click event of the button:
Response.Write("Page posted back")
Which only writes out to the page once it is posted to the server.
I certainly learnt something new today :)
-
Published on 03 Jul 2006 from
There have been many articles on Attributes, so rather than go through the rigmarole of re-hashing a subject I have will give a quick introduction. After that I have knocked up a quick demo which will hopefully get you moving in the right direction! At the end is a list of useful resources.
What are these attribute tags?
Fig 1.1 Example of Attribute defined on a method:
[Fig 1.1]
[Attribute("argument")]
private void Foo() { }
[/Fig 1.1]
Attributes are a declarative way of defining some functionality associated with a method, types, fields or even properties. Put simply attributes allow a definition of specific meta data against code. The .NET model of compilation model is to take source code and compile it down to Intermediate Language (IL) which is then run by the Common Language Runtime (CLR). For those who have not come across IL before, IL is similar to machine code, but retains extra information about the code, making the IL a damn sight easier to read that x86 assembler!
Enough with the talk, show us some code!
Lab
For this quick introduction we are going to be looking at the conditional attribute. This attribute is defined in the System.Diagnostics namespace.
Looking at code 1.1. we see that there are two methods define in our Program class. FillArray which populates our generic integer list with random integers. The second method called DebugPrint prints out all the items in the list with the items index number and the value that is stored. A very useful little function for debugging an integer list. In the Main method we call the DebugPrint statement twice. Before the list is sorted and afterwards. This is all fine and dandy, until we come till the time when we no longer want to release code with debug statements in, but rather a release build without.
[code 1.1]
class Program
{
internal static void Main(string[] args)
{
List<int> digits = new List<int>();
//Fill array with random digits
FillArray(digits);
//What have we got in the array?
DebugPrint(digits);
//Sort the array
digits.Sort();
//Is it sorted?
DebugPrint(digits);
Console.ReadLine();
}
internal static void FillArray(List<int> digits)
{
Random rand = new Random();
for (int i = 0; i < 10; i++)
{
digits.Add(rand.Next(0, 100));
}
}
internal static void DebugPrint(List<int> digits)
{
Console.WriteLine("[BEGIN Debug Print]");
for (int i = 0; i < digits.Count; i++)
{
Console.WriteLine("{0} \t=>\t {1}",i,digits[i]);
}
Console.WriteLine("[END Debug Print]\n\n");
}
}
[/code 1.1]
Personally coming from the school of C the obvious solution to this problem is to surround the DebugPrint method with a compiler directive (code 1.2). What a simple solution, unfortunately if the code is built the compiler will have a small problem as there are calls to this method, which in the opinion of the compiler, does not exist! To solve this problem every call to DebugPrint() needs to be surrounded by the same compiler directive.
[code 1.2]
#IF DEBUG
internal static void DebugPrint(List<int> digits)
{
Console.WriteLine("[BEGIN Debug Print]");
for (int i = 0; i < digits.Count; i++)
{
Console.WriteLine("{0} \t=>\t {1}",i,digits[i]);
}
Console.WriteLine("[END Debug Print]\n\n");
}
#ENDIF
[/code 1.2]
Far from ideal, in real terms this means remembering to surround all the calls and changing the token that is used to define debugging will require a change in all these compiler directives. From a semantic point of view it also makes our code that little bit harder tounderstand. So does a simpler solution exist? Well if there didn’t I probably wouldn’t be writing this! Cue drum rolls and enter stage right attributes. In the System.Diagnostics there is a class ConditionalAttribute. This class is explained as giving the following functionality, “Indicates to compilers that a method is callable if a specified pre-processing identifier is applied to the method.” Code 1.3 defines this class as a Attribute above the DebugPrint method. The class is passed an argument “DEBUG” which in turn is passed to the ConditionalAttribute constructor. This sets the class up such that if this compiler directive is defined in the correct scope this method is callable otherwise it is not. Note that I have not said that the method is removed, it is merely not callable. Compile this code in debug mode, and everything is fine and dandy with our lovely debug message printing. Drop it into release mode and it compiles first time with the method calls in place, and our DebugMethod is no longer called, compiler directives for free?
[code 1.3]
[Conditional("DEBUG")]
internal static void DebugPrint(List<int> digits)
{
Console.WriteLine("[BEGIN Debug Print]");
for (int i = 0; i < digits.Count; i++)
{
Console.WriteLine("{0} \t=>\t {1}",i,digits[i]);
}
Console.WriteLine("[END Debug Print]\n\n");
}
[/code 1.3]
Let’s try find out what the C# pre-processor is doing here. Time for ILDASM (not used ILDASM before? Click here)! Looking at Fig 1.2 (the debug build) all the methods are in the assembly as they should be. Browsing through the MSIL output of the main function (Code 1.4) the calls to DebugPrint are there. Great! Moving to the release build, open ILDASM something most peculiar has happened, the method DebugPrint is still in the assembly, uh oh. Something must have gone wrong. Before panicking too much let’s take a gander at the Main method (code 1.5) the calls to DebugPrint have been removed. Suddenly it all makes sense. The pre-processor is not removing the function from the class just the ability to call it (removes the calls to the function). “But Mr Ian Saunders”, you all cry, what happens if the function returns a number that is used in another statement, or pass the array using the out key word? For exactly these reasons the Conditional Attribute does not allow the method to return a value or take an out parameter.
[Fig 1.2]

[/Fig 1.2]
[Code 1.4]
.method assembly hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 42 (0x2a)
.maxstack 1
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> digits)
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void Attributes.Program::FillArray(class [mscorlib] System.Collections.Generic.List`1<int32>)
IL_000d: nop
IL_000e: ldloc.0
IL_000f: call void Attributes.Program::DebugPrint(class [mscorlib] System.Collections.Generic.List`1<int32>)
IL_0014: nop
IL_0015: ldloc.0
IL_0016: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Sort()
IL_001b: nop
IL_001c: ldloc.0
IL_001d: call void Attributes.Program::DebugPrint(class [mscorlib] System.Collections.Generic.List`1<int32>)
IL_0022: nop
IL_0023: call string [mscorlib]System.Console::ReadLine()
IL_0028: pop
IL_0029: ret
} // end of method Program::Main
[/Code 1.4]
[Fig 1.3]

[/Fig 1.3]
[Code 1.5]
.method assembly hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 1
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> digits)
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call void Attributes.Program::FillArray(class [mscorlib]
System.Collections.Generic.List`1<int32>)
IL_000c: ldloc.0
IL_000d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Sort()
IL_0012: call string [mscorlib]System.Console::ReadLine()
IL_0017: pop
IL_0018: ret
} // end of method Program::Main
[/Code 1.5]
Summary:
Attributes provide a powerful way of adding extra functionality to your code, in a simple seamless way, covering up the complexity and the constraints applied to the code. The example I have used is a tad contrived, though I daresay will be very useful in university projects when debug code is about 60% of what is written ;). Why stop there the .NET namespaces provides hundreds of built in attributes that can be used straight out of the box? If the provided functionality doesn’t quite float your boat why not create your own attribute? It’s really not as complicated as you think and there is a wealth of knowledge on how to do this on the internet.
Regards,
Ian Saunders
About the resources: As there are so many attributes and all located in varying namespaces in can be difficult to know if there are any attributes that apply to the domain of your problem. In my experience it appears the best way is to crack open your favourite search engine or MSDN and search for either the namespace you are playing with or the general concept you are looking at. Hope that is helpful!
Resources:
The code I used is attached to this article.
MSDN article on Attributes: This article gives a very good and through explanation of attributes using VB .NET as a base language. Also provides an introduction to creating custom Attribute classes.
Thorough introduction to Attributes in VB .NET with an authortive O’Reilly Book
Attributes in VB .NET: An introduction to attributes as well as a step by step guide to creating a custom attribute class.
Definition of System.Attribute namespace from MSDN:
Using Attributes for creating .NET code that can work with COM
Attributes in Business Objects: A great article in VB .NET and C# on how to use attributes in your own custom business objects
Part 1: http://www.spaanjaars.com/QuickDocId.aspx?quickdoc=390
Part 2 :http://www.spaanjaars.com/QuickDocId.aspx?quickdoc=391
Using Attributes for debugging: Invaluable resource for customizing and refining the debugging experience in Visual Studio 2005
Another Slightly in-depth article about using Attributes to improve code debugging:
-
Published on 03 Jul 2006 from
The growth in electronic devices in UK homes is leading to an upsurge in energy usage, a report says.
-
Published on 03 Jul 2006 from
As you might know, I like to keep an eye on my Feedburner / RSS / Aotm / feeds stats.
Neville Hobson has just shared some of his Feedburner stat data and I thought it was interesting how similar some of the trends are compared to mine. Some differences too.
Around 47% of Neville's subscribers are using Bloglines (consistently) and NewsGator at #2 (14%) , while for me only 22% of my subscribers use Bloglines (that is big drop since Jan 06, see below) and Netvibes is number #2 (at 18%).
My reader breakdown (June 26 to July 02 2006):

For my subscribers, Netvibes is really a new entrant - it didn't feature in the previous update I gave.
Firefox Live Bookmarks features in both of our stats (he 6%, me 4%). Unlike Neville, Rojo readers have subscribed to me since I turned on my Feedburner service in September (around the 6-8% mark consistently). The following is a snapshot of same period above. It provides more data than I've highlighted here:

FeedDemon is still there, but not where it used to be for my FB subscribers (I wonder if some FeedDemon users are counted as NewsGator now?...Nick?).
Another difference between Neville's stats and mine in the intial take up of the feed. His has quite a sharp take-up in the first few days, while mine (see below) is much more gradual. I think this is to do with the fact that I haven't been able to include an automatic redirect (where as I think Neville could, am guessing though).
Overall number of subscribers Setp 12 2005 to July 02 2006:

I still can't shut down my other feed or do the redirect, but the proportions are looking a little better now since my plea - I think around 65% of my readers are now sub'd to the FB feed.
This tallies with the 'Share Your OPML' data, which counts my two seperate feeds er, seperately (67 on the old feed, 97 on FB feed, which if counted as one would put me in the top 100, but whatever).
But Bloglines is the big dropper for me. It was a 31% in January, now at 22%.
I haven't seen any aggregate data reports from Feedburner, and would like to compare on trends.
According to Kevin O'Keefe, who spoke to Rick Klau, VP of Biz Dev at Feedburner, FB is adding around 1,200 feeds from 800 to 1000 new publishers a day. That's a lot of data...a lot of readers and lot of publishers...
-
Published on 03 Jul 2006 from
So, we have an announcement from Microsoft of the latest member to join the SQL Server
2005 stable. The new 'everywhere' edition is similar to Express, yet it fills a place
so obvious that it makes great sense.
The everywhere edition, is a small footprint version of SQL Server. In fact this version
can be, and was meant to be, embedded in an application. So, it's the 2005 edition
of SQL Server Mobile.
Where SQL Server runs as a service and provides multi-user functionality, SQL Server
Everywhere runs 'in process' so it provides relational DB support to the application
that it's embedded inside. So, ideal for mobile yet also ideal for those applications
that need some database ability, but not so much to warrant a full blown Express edition.
More good stuff here http://www.microsoft.com/sql/ctp_sqleverywhere.mspx
-
Published on 03 Jul 2006 from
It’s probably worth mentioning that the Code Generation Network, which I edit, is running a book competition in July.
The winner will receive a copy of each of the following books donated by Pearson Education:
Visual Studio Tools for Office - Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath
A Developer’s Guide to SQL Server 2005
The .NET [...]
-
Published on 03 Jul 2006 from
I believe a business plan needs to be agile and constantly tuned by the team, and I’m trying a new experiment (new for me, at least): I’m writing and tuning my business plan on SharePoint 2007’s new wiki feature. Now the team can wiki collaborate on it. I’ll let you know how it goes...

-
Published on 03 Jul 2006 from
I believe a business plan needs to be agile and constantly tuned by the team, and I’m trying a new experiment (new for me, at least): I’m writing and tuning my business plan on SharePoint 2007’s new wiki feature. Now the team can wiki collaborate on it. I’ll let you know how it goes...

-
Published on 03 Jul 2006 from
I’m still alive, and very, very impressed with Vista (build 5456), and seeing build 5469 on David's machine (Product manager for Vista) makes me want more!
Vista did a sterling job of running Media Center over the weekend with no crashes and no pains, even though the toughest of punishment that my out-laws threw at it.
I can’t spell this out enough: with Windows Media Center Edition 2005, you really had to be a geek to get it installed yourself, hence why we only sold MCE via computer manufacturers, but Vista Ultimate (that includes MCE) is so good, instead of spending days to get all 100 drivers installed in the right sequence with the required reboots and tweaks to make MCE work, Vista just worked!
And England... they played well, and I’m proud of ‘em. (Ag, shame man, as we would say in South Africa. Ja Nee (Yes, No), what can I say?)
So – to celebrate the new [financial] year and the goal for Vista, David gave me three original Vista Beta 2 sealed DVD cases to give to you. (Thanks David!) The first three emailing me with your *UK* postal address, will get one throug