Archives

Archives / 2006
  • Developers harness the power of Google Code Search... and look up dirty words

    Google has unleashed its latest free search product onto the unsuspecting public: Google Code Search. What new wonders will come from combining this powerful new tool with the software development community? Will we use our knowledge to spot hidden bugs in one another’s software, eliminating software crashes and possibly saving the lives of those that depend on our programs? Or will coders around the world enter a new era of greater collaboration, creating amazing new software that transforms the the way people live?

    Or we could, you know, look up dirty words in each others code: Fucks per programming language and license. [:)]

    According to Google Code Search PHP developers are the most profane while Python, Java and C# (my language of choice) come out the cleanest. C# ends up winning (or losing depending on your perspective) by a nose. Take that fuckers.

    More seriously, I don't see Google Code Search changing the world when it comes to the reuse of existing code. Expressing what you are looking for in a class or library in a regex that searches over code is something that strikes me as being very hard to do. I believe the majority of the time you would be better off using plain old English in Google's regular search to find what you’re looking for.

    Google Code Search isn't without merit however. A place where I can see it being quite useful is when working with an API for the first time. If you're unsure of the way a specific property or method works, and the code example in the MSDN reference isn't any help, Google Code Search provides a means to get a list of real world examples to learn from.

    Finally, and I guess since it is Google I shouldn't be surprised, but Google Code Search has managed to find and include the code I've written and made public on this site, despite being zipped! If anyone deserves a P/E of 60, it's Google.

  • Starting at Intergen

     

    As alluded to earlier I have have shifted jobs, and have started at a place called Intergen. It is a bit of a culture shock going from 5 people working on one project to over 100 people working on more things than I can count.

    So far the highlight at Intergen for me has definitely been the people. Besides all being very nice and a lot of fun to work with, Intergen has many of the best .NET developers in the country, including two MVPs and one of New Zealand's Microsoft Regional Directors.

    Intergenite cast:

    • John-Daniel Trask - New Zealand .NET Blog of the Year winner. Also known for crazy antics.
    • Jeremy Norman - EPiServer expert and a very good Halo 2 player. I'm (currently) very bad so we often end up on the same team [:)]
    • Trey Guinn - When we first met, for a second there, he had me believing that we were long lost friends. Americans!
    • Nick Urry - Intergen developer and content management expert extraordinaire.
    • Jeremy Boyd - New Zealand Microsoft Regional Director and MVP for SQL Server 2005.
    • John Lewis - Part of the Intergen creative studio.

    And many more who have not yet hopped on the blogging bandwagon. Thanks for making me feel welcome [:)]

  • How to increase traffic to your blog - the Spolsky way

    Although I don't always agree with some of his opinions on programming, Joel Spolsky's marketing skills have to be admired. In his most recent post Language Wars, Joel argues that when it comes to picking a computer language for a project you are best off picking the mainstream language you know best. Nothing revolutionary there.

    Along the way however he slams LISP and criticizes Ruby for not being suitable for commercial programming, citing failed projects, maturity and performance. As probably anyone who reads this knows, programmers can become extremely devoted to their language of choice (which is silly because .NET is obviously the best) and so they tend to get very fired up when their beloved is insulted. The beauty of Joel's post is he then cleverly baits those that he has annoyed by saying that his company has created its own in house language, something that runs completely against picking a safe choice he argued earlier. Subtle tongue in cheek most likely (at least I hope), but at the same time not entirely impossible. Either way Joel doesn't try to explain or justify this paradox in his post and so combines the aggrieved LISP and Ruby developers with ammunition to counter-attack, creating a feeding frenzy of posts, links and hits.

    I've come across a number of posts listing ways to increase traffic to a blog recently but none have described anything like this. Joel, I salute you! [Y]

    Update:

    Update Part Deux:

  • Oracle Peeves

    I'm changing jobs soon and after nearly 3 years of working with Oracle, and little chance of my using it in the near future, I'd like to share (vent) some of my top Oracle peeves.

    I'd like to state up front that I don't hate Oracle, and I haven't had enough experience with other databases to know exactly how good or bad Oracle is in comparison. These are just some little things (hopefully valid) that have irked me over the years [:)]

    30 character name limits

    I'm not a fan of Hungarian notation or most abbreviations (we spend far more time reading code than writing it so any time saved typing will be lost deciphering, besides auto-complete anyone?) so Oracles 30 character limit on names has annoyed me to no end. It usually isn't a problem with table or column names but when you have a foreign key naming standard that is comprised of the table the key is coming from and going to, things start to get hairy:

    E_S_SEC_E_PROC_SUB_TYPE_FK1 [^o)]

    select * from dual

    Why Oracle why?

    To be honest I've always found the dual table kind of facinating although Oracle's limitation does make some do crazy things.

    SQL statements automatically handling no_data_found

    In PL/SQL when you want to populate a variable with a value from a table you use "select into". The select into statement has to return one row. If none are returned then you get a no_data_found exception. If more than one is returned then you get an aptly named too_many_rows exception. Sound fairly simple? The gotcha is that if the exception is thrown by a function being used inside a SQL statement then it is automatically caught. The hows and whys of this behavior confused the bejesus out of me until I came across this Ask Tom question.

    Varchar2

    A general grab-bag of aggravating issues around strings in Oracle:

    • Apparently Oracle promotes the use of varchar2, rather than varchar, because it wants to avoid problems if the SQL standard is ever changed so that possible new varchar behavior doesn't cause bugs in existing code. DBAs are big on backwards compatibility so a change like that seems a pretty big if to me. Personally I think Oracle should have just stuck with varchar. If the standard ever changed in a way that caused bugs with existing code either used a database flag to turn it on or off or at that point introduce a varchar2 with the new behavior.
    • By default the length on a varchar2 column specifies byte length, not the number of characters. Most commonly used English text is single byte but it can be a bug lying in waiting if you are unaware of it.
    • Empty strings are considered null. '' = ''? Not in Oracle!
    • The string concatenation operator in Oracle is ||. Yuck. To be fair to Oracle this is the operator specified in the ANSI SQL standard.

    Memory UsageOracle likes it's RAM. Having a dedicated database machine (at least if you're writing, running and debugging .NET applications from Visual Studio) is pretty much compulsory. Oracle having Java embedded inside it can't help.

    Select Into

    In PL/SQL you can't use the result from a select in an expression. Instead you have to declare the variable, select into the variable (don't forget no_data_found and too_many_rows error handling!) and only then use the variable in an if test or whatever. Painful.

    Package Headers

    Packages are a Good Thing™ and I have a feeling I'll miss them in SQL Server land but separate headers to control external visibility is so 1990. Having to modify the header signature along with the body is annoying.

    Declaring all variables at the top of a procedure/function

    Woah. Sixth Form Certificate programming class Pascal flashback.

    Installing Oracle on Linux

    10g or 9i? R1 or R2? x86 or x86-64? Redhat Enterprise Linux, Fedora Core, SUSE Enterprise Linux or something else?

    There are a lot of permutations and luckily for you there are instructions for all of them because Oracle installs on each of them differently. Hurrah!

    When you do find the guide you are looking for don't worry, you are halfway there! Only 21 pages of instructions to follow...

    Oracle .NET client size

    209 megabytes. Compressed.

    Update:

    To be fair to Oracle, its quirks and WTFs can't compare with the silly things some developers do with it.

  • Adios 2.0

    I upgraded to Community Server 2.1 last night and I have to say that the experience was surprisingly painless, even for someone like myself who is not use to SQL Server's heathen ways.

    Apart from the SQL upgrade script balking because of an old record missing from the cs_SchemaVersion table (I just added it manually) the updating the database went without incident. Upgrading the web application was slightly more time consuming as I had to merge my changes to the *.config files with the new versions but after that I just copied my custom theme directory across and then uploaded it to the server.

    Now I just need to find a new blog feature in Community Server 2.1 that I will actually use to make the upgrade worth it [:)]

    Update:

    The admin area is much improved. Most the rough edges around the post editor and post grid have been smoothed out. Also the new "named" URLs are much better than the old number system. I went through and updated all of the previous posts to use them (the old URL still works).

    Overall I give 2.1 two thumbs up [Y] [Y] (did I mention the smilies in blog posts? [:)])

  • WebRequestDetailedErrorEvent

    Download DetailedErrorEvent - DetailedErrorEvent dll and C# source code

    One of the least talked about new ASP.NET 2.0 features, and one of my favorites, is the health monitoring system. Designed to help you monitor the status of a deployed website, the ASP.NET health monitoring system makes what could potentially be a chore easy. With just a few lines in your site’s web.config you can automatically log a variety of events to a file, a database or even send an email to an email address.

    While overall health monitoring it is a great new feature for ASP.NET, the WebRequestErrorEvent class provides disappointingly small amount of information. Raised when an unhandled exception is thrown during a web request, only basic information about the request that caused the error is provided such as the URL, the user host address and the authenticated user. Vital information like the request headers, form values, cookies and server variables are missing, making debugging the error more difficult than it needs to be.

    WebRequestDetailedErrorEvent

    The WebRequestDetailedErrorEvent class inherits from WebRequestErrorEvent and includes the information that the base class is missing.

    One interesting aspect of the health monitoring events is that they are written asynchronously. While this allows them to be buffered and written without impacting performance, it also means that a copy of the request details need to be taken as HttpContext.Current will be null when the FormatCustomEventDetails method is called.

    private void Init(Exception exception)
    {
        // FormatCustomEventDetails is called outside of a web request
        // need to take a copies of all the web request information to log
        HttpContext context = HttpContext.Current;
     
        if (context != null)
        {
            HttpRequest request = context.Request;
     
            _cookies = new HttpCookie[request.Cookies.Count];
            request.Cookies.CopyTo(_cookies, 0);
     
            _httpHeaders = new NameValueCollection(request.Headers);
            _form = new NameValueCollection(request.Form);
            _queryString = new NameValueCollection(request.QueryString);
            _serverVariables = new NameValueCollection(request.ServerVariables);
        }
        else
        {
            _cookies = new HttpCookie[0];
            _httpHeaders = new NameValueCollection();
            _form = new NameValueCollection();
            _queryString = new NameValueCollection();
            _serverVariables = new NameValueCollection();
        }
    }

    WebRequestDetailedErrorModule

    Unfortunately there is no seamless way to automatically raise the new web request error event instead old so a new HttpModule is required to do it for us. WebRequestDetailedErrorModule attaches a method to the Error event of the HttpApplication object and then raises WebRequestDetailedErrorEvent when a web request exception goes unhandled. Not all exceptions raised the default event so some logic is required to filter them out.

    private void RaiseErrorEvent(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;
        Exception exception = context.Error;
     
        // unwrap exception if top exception is an HttpUnhandledException
        if (exception is HttpUnhandledException && exception.InnerException != null)
            exception = exception.InnerException;
     
        HttpException httpException = exception as HttpException;
     
        // don't log file not found exceptions
        if (httpException != null && httpException.GetHttpCode() == 404)
            return;
     
        // viewstate exceptions raise a WebViewStateFailureAuditEvent, not an exception event
        if (httpException != null && httpException.InnerException is ViewStateException)
            return;
     
        WebBaseEvent.Raise(new WebRequestDetailedErrorEvent("An unhandled exception has occurred.", this, WebEventCodes.WebExtendedBase + 3005, 0, exception));
    }

    The old event will still be raised so if you may want to modify your web.config to not log events numbered 3005.

    Usage

    To use the WebRequestDetailedErrorEvent simply add the module to your website’s httpModule section.

    <httpModules>
        <add name="WebRequestDetailedErrorModule" type="Newtonsoft.DetailedErrorEvent.WebRequestDetailedErrorModule, Newtonsoft.DetailedErrorEvent"/>
    </httpModules>

    And that’s it. The new error event is now raised whenever an unhandled exception is thrown from a web request. Note that if you haven’t already setup ASP.NET to log health monitor events you can find out how here.

    Download DetailedErrorEvent - DetailedErrorEvent dll and C# source code

  • Well I think it's funny - .NET Edition

    .NET Pickup Lines via K. Scott Allen

    If I were a generic collection, I'd be strongly typed for you.

    You must be the latest version, because I've been checking you out.

    I have a small problem. I put an object in a Dictionary, but I lost the key! Can you come back to my place and help me look for it?

    A TypeConverter just returned my heart, and it's ready to assign to you.

    Let's turn off option strict and do some late night binding.

    So, what's your hash code?

    And some of my own:

    The moment I saw you I knew my singleton days were over.

    There is nothing IDisposable about my love for you.

    I've been reflecting on your Attributes and I like what I see.

    Oh dear.

  • Well I think it's funny

    Made by the students of the Columbia Business School, this hilarious spoof "Every Change of Rate" features a man lamenting missing out on the Chairmanship of the Federal Reserve to the tune of "Every breath you take". Glenn Hubbard, Dean of the Columbia Business School, was rumored to be on the shortlist for the position which makes the whole thing even better. Here's a sample:

    "First you move your lips

    And hike a few more BiPS.

    When demand then dips And the yield curve flips,

    I'll be watching you."

    Brilliant.

  • WebDialog 1.1 released

    WebDialog 1.1 has been released.

    Much improved support for Atlas is the primary feature of this WebDialog release.

    What's New:

    • New Feature - Improved Atlas support in Internet Explorer and Opera.
    • Bug Fix - Fixed validators nested inside a dialog with client script enabled not displaying their error message when they failed.
  • Json.NET 1.1 released

    Thanks again to the people that have tried out Json.NET and have reported bugs or offered suggestions. This release addresses all the issues that you've reported and that I'm aware of. 1.1 also adds a few new features.

    • New feature - XmlNodeConverter class provides a means to easy convert between Xml and JSON text. SerializeXmlNode and DeserializeXmlNode helper methods have also been added.
    • New feature - Handles parsing JavaScript constructor calls (i.e. new Date(1234)).
    • New feature - Improved date serializing and deserializing.
    • Change - Rewritten JavaScript string escape method.
    • Bug fix - Lots of little fixes to JsonSerializer.

    Converting between XML and JSON

    The big new feature added in Json.NET 1.1 is a converter class for XML. By using XmlNodeConverter (or the newly added helper methods) it is now extremely simple to convert JSON to XML and vice versa in .NET.

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(@"<?xml version=""1.0"" standalone=""no""?>
    <root>
      <person id=""1"">
        <name>Alan</name>
        <url>http://www.google.com</url>
      </person>
      <person id=""2"">
        <name>Louis</name>
        <url>http://www.yahoo.com</url>
      </person>
    </root>");
     
    string jsonText = JavaScriptConvert.SerializeXmlNode(doc);
    //{
    //  "?xml": {
    //    "@version": "1.0",
    //    "@standalone": "no"
    //  },
    //  "root": {
    //    "person": [
    //      {
    //        "@id": "1",
    //        "name": "Alan",
    //        "url": "http://www.google.com"
    //      },
    //      {
    //        "@id": "2",
    //        "name": "Louis",
    //        "url": "http://www.yahoo.com"
    //      }
    //    ]
    //  }
    //}
     
    XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
     
    Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);

    Elements, attributes, text, comments, character data, processing instructions, namespaces and the XML declaration are all preserved when converting between the two. The only caveat is that it is possible to lose the order of differently named nodes at the same level when they are grouped together into an array.

    A Brief Guide

    • Elements remain unchanged.
    • Attributes are prefixed with an @.
    • Single child text nodes are a value directly against an element, otherwise they are accessed via #text.
    • The XML declaration and processing instructions are prefixed with ?.
    • Charater data, comments, whitespace and significate whitespace nodes are accessed via #cdata-section, #comment, #whitespace and #significate-whitespace respectively.
    • Multiple nodes with the same name at the same level are grouped together into an array.
    • Empty elements are null.

    Json.NET 1.1 can be downloaded here.

  • Json.NET 1.0.1 released

    Changes in this version:

    • Bug Fix - JsonSerializer no longer errors when deserializing certain .NET objects.
    • Change - The JsonWriter QuoteChar property now defaults to double quotes and QuoteName is now true. This has been done to make the JSON output follow the json.org specification.
    • New Feature - JsonSerializer will attempt to use a classes TypeConverter to convert the JSON value to a members if the two do not match.

    The new 1.0.1 version can been found on the download page.

    Thank you to the people who have tried out Json.NET and given feedback.

  • Newton King - No Relation

    When growing up from time to time when I gave my name to someone I was often asked if I had any any relation to the Newton King of Taranaki. Apart from knowing that someone of importance must have lived there, I never had any idea what they were talking about. After yet again being asked about the subject yesterday I bit the bullet and googled the name.

    It turns out a man called Newton King (first name Newton, last name King) was born around 150 years ago and was quite a successful in business, running a company of the same name. Apparently prior to World War I, Newton King (the business) was the largest privately owned company in the Southern Hemisphere. Quite remarkable considering the small size of New Zealand.

    This picture made me laugh:

    And although the Newton King company went out of business during the 1987 stockmarket crash, there is still the Newton King Tanker Terminal at Port Taranaki today:

    Thanks to the Puke Ariki museum for their great article on him.It feels good to put one of lifes puzzles to bed, kind of like learning why the sky is blue or why you should avoid virtual methods calls from a constructor. Now the next time someone inquires about my last name I can talk about the subject without looking like a total burk :)

  • Json.NET - Simplifying .NET <-> JavaScript communication

    JSON (JavaScript Object Notation) is lightweight data interchange format. In recent times JSON has achieved widespread use due to the ease of which it can be parsed and then the data accessed from within JavaScript compared to alternatives like XML.

    While many JavaScript libraries exist for converting JSON text to and from a JavaScript object, working with JSON in .NET has been much more problematic. Correctly escaping strings and building up objects when writing JSON text can be difficult and error prone, while parsing values back out of JSON text is harder still.

    Json.NET

    Json.NET is a JSON .NET API for simply and safely reading and writing valid JSON text. At the core of Json.NET, similar to the .NET XML APIs, are two classes: JsonReader and JsonWriter. Also like XML in .NET, Json.NET includes a JsonSerializer class.

    Reading JSON

    JsonReader is a fast, forward only, readonly cursor. Like XmlTextReader it works over the top of a TextReader and maximizes performance while minimizing memory use.

    The following code is a brief example of how to read a JSON object.

    string jsonText = "['JSON!',1,true,{property:'value'}]";
     
    JsonReader reader = new JsonReader(new StringReader(jsonText));
     
    Console.WriteLine("TokenType\t\tValueType\t\tValue");
     
    while (reader.Read())
    {
        Console.WriteLine(reader.TokenType + "\t\t" + WriteValue(reader.ValueType) + "\t\t" + WriteValue(reader.Value))
    }

    Resulting in...

    TokenTypeValueTypeValue
    StartArray null null
    String System.String JSON!
    Integer System.Int32 1
    Boolean System.Boolean True
    StartObject null null
    PropertyName System.String property
    String System.String value
    EndObject null null
    EndArray null null

    Writing JSON

    JsonWriter is also forward only, and writes JSON text to a TextWriter. It handles formatting numbers, escaping strings and validating that the object is valid.

    The following code is a brief example of how to write a JSON object.

    StringWriter sw = new StringWriter();
    JsonWriter writer = new JsonWriter(sw);
     
    writer.WriteStartArray();
    writer.WriteValue("JSON!");
    writer.WriteValue(1);
    writer.WriteValue(true);
    writer.WriteStartObject();
    writer.WritePropertyName("property");
    writer.WriteValue("value");
    writer.WriteEndObject();
    writer.WriteEndArray();
     
    writer.Flush();
     
    string jsonText = sw.GetStringBuilder().ToString();
     
    Console.WriteLine(jsonText);
    // ['JSON!',1,true,{property:'value'}]

    Which prints out: ['JSON!',1,true,{property:'value'}].

    Serializing and deserializing JSON and .NET objects

    JsonSerializer, similar to XML serialization, provides a hassle free way to automatically convert .NET objects to and from JSON text.

    The following code is a brief example of how to serialize and deserialize JSON and .NET objects.

    string jsonText = "['JSON!',1,true,{property:'value'}]";
     
    JsonSerializer serializer = new JsonSerializer();
     
    JavaScriptArray jsArray = (JavaScriptArray) serializer.Deserialize(new JsonReader(new StringReader(jsonText)));
     
    Console.WriteLine(jsArray[0]);
    // JSON!
     
    JavaScriptObject jsObject = (JavaScriptObject)jsArray[3];
     
    Console.WriteLine(jsObject["property"]);
    // value
     
    StringWriter sw = new StringWriter();
     
    using (JsonWriter jsonWriter = new JsonWriter(sw))
    {
        serializer.Serialize(sw, jsArray);
    }
     
    Console.WriteLine(sw.GetStringBuilder().ToString());
    // ['JSON!',1,true,{property:'value'}]

    Json.NET - Json.NET Homepage

  • Getting into WinFX... sorry .NET 3.0

    Beta 2 of WinFX was released a couple of weeks ago. Even though I've been quite excited about what Microsoft has been doing with WinFX, I've learn't to stear clear of Microsoft community previews and the beta 1 release. APIs are too volatile, there is little support out on the web for when you run into problems (which you will) and chances are that even when a more stable version does get released something from a previous version will cause problems. CTP Madness indeed.

    Strangely, even before I'd managed to install WinFX it ceased to exist. A name changed was announced, with WinFX now a part of .NET. Although there has been much nashing of teeth and rendering of clothing both from the usual suspects and some Microsoft developers, I believe the name change was a good move. One name are one download will be less confusing for users and to most developers. All they need to know is that to run or develop an application they need a specific version of .NET. Having to worry about X version of .NET, Y version of WinFX, plus whatever else comes out in the next couple of years is too much for most and really, 99% of the public don't need to know. One download, one name. KISS.

    Back on task; first .NET 3.0 impression:

    Hmmm, this may take a while.

  • Preventing Spam With An ASP.NET CAPTCHA Control

    The source and dll for the project can be downloaded here: CaptchaControl.zip About A CAPTCHA image displays text that is readable to humans, but not to computers. The concept is useful because it provides a means to filter out automated programs while allowing real users to pass through. Bots for example, which spam comments on weblogs and other dynamic websites, are a fairly pervasive problem and even a regularly new and low traffic blog like this was getting dozens of spam comments every day. CAPTCHA is a means to stop them while still allowing real users to post.CaptchaControl is an ASP.NET server control that is designed to start working by just being dropping onto the page, without any modification. This version is based off Michael Trefry’s implementation, which is in turn based off Dan Burke’s. My update fixes a couple of issues around storing the code in a browser cookie and adds features like client validation. CatchaControl OverviewThe CaptchaControl class is a composite control and encapsulates the CAPTCHA image, a textbox for capturing the result and a validator for verifying the correct code was entered. It handles hooking all the controls together, pointing the image src towards the image handler and maintaining the state of the code, which is stored encrypted in a hidden form field and then decrypted on postback.

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
     
        RegenerateCode();
     
        Page.ClientScript.RegisterHiddenField(ClientID + "__hidden", _encryptedCode);
        Page.RegisterRequiresPostBack(this);
     
        SetChildProperties();
    }
     
    bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        _encryptedCode = postCollection[ClientID + "__hidden"];
        _code = Encryptor.Decrypt(_encryptedCode, GetKey(), GetIV());
     
        return true;
    }

    CaptchaControl has a number of properties for modifying its behavior such as the text of the error message, whether to display for authenticated users and whether the code should be validated on the client with JavaScript (note that the unencrypted code will be included with the page if this is enabled). It also an optional LayoutTemplate property of ITemplate that allows the encapsulated controls layout to be customized.Generating the CAPTCHA ImageThe CAPTCHA image is generated by CaptchaHandler, a HttpModule. Parameters in the querystring, including the encrypted code data, are passed to a class than handles generating the image, which is then rendered to the response.

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;
     
        string encryptedCode = request.QueryString["code"];
        string code = Encryptor.Decrypt(encryptedCode, CaptchaControl.GetKey(), CaptchaControl.GetIV());
     
        int width = Convert.ToInt32(request.QueryString["width"]);
        int height = Convert.ToInt32(request.QueryString["height"]);
     
        CaptchaImageGenerator captchaImage = new CaptchaImageGenerator(code, width, height);
     
        response.Clear();
        response.ContentType = "img/jpeg";
        response.Cache.SetCacheability(HttpCacheability.NoCache);
     
        captchaImage.RenderImage(response.OutputStream);
    }

    UsageRegister the CaptchaHandler by adding the following to your web.config’s httpModule element.

    <addverb="*"path="captchahandler.axd"type="Newtonsoft.CaptchaControl.CaptchaHandler, Newtonsoft.CaptchaControl"/>

    To add the CaptchaControl to a page simply place it where you want it to be displayed:

    <%@ Register TagPrefix="ncc" Namespace="Newtonsoft.CaptchaControl" Assembly="Newtonsoft.CaptchaControl" %>
     
    <ncc:CaptchaControl runat="server" ID="CaptchaControl" />

    The IsValid property on the page will automatically be set when the page’s validators, including CaptchaControl, are evaluated on postback.

    private void btnSubmit_Click(object sender, EventArgs e)
    {
        if (IsValid)
        {
            // logic
        }
    }

    The important question: Does it work? Since adding CAPTCHA validation to this blog comment spam has dropped from dozens each day to zero.The source and dll for the project can be downloaded here: CaptchaControl.zip

  • Logging JavaScript Errors To ASP.NET

    Over the past few years a huge jump in the complexity of JavaScript has occured on the browser, resulting in richer, more responsive and user friendly web applications. Unfortunatly this shift does not come without cost.Greater complexity on the client means more room for bugs, and without some effective means to log them you are left in the dark about problems until users are driven to complain.Solution OverviewThe client exception logger comprises of three parts: a script on the client that catches the exceptions and sends them to the server, a HttpHandler on the server that receives the error details and logs them, and an ASP.NET control that links the two together.Details logged include the following:

    • JavaScript exception message, line and file name
    • Date and time
    • IP Address
    • User agent (browser and platform details)
    • Session ID

    Catching and Sending the Error on the Client Whenever an exception is not caught in JavaScript it triggers an onerror event on the browser's window object. It is comparable to ASP.NET’s Application_Error event in the global.asax.When the page is downloaded a ClientLogger object is created and a function is attached to the onerror event. That function calls a method on ClientLogger object which will send the error details to ASP.NET on the server using the XMLHttpRequest object. This is done asynchronously and does not effect the user.

    var logger = new ClientLogger({handlerUrl:'../../ClientLogger.axd',sessionID:'2rnbawbkzuovsw55ymvflz45'});
    window.onerror = function(message, url, line) { logger.Log(message, url, line); };

    Receiving and Logging the Error on the Server When sending the error data back to the server, rather than the page calling back to itself, the logger posts the details a custom HttpHandler. This is done to minimize side effects or performance issues of creating the page again.Note that the handler does not contain any logic for logging the error details. Instead it uses the new ASP.NET 2.0 Web Event feature, and raises a custom WebJavaScriptErrorEvent event.

    WebBaseEvent.Raise(new WebJavaScriptErrorEvent(jsMessage, this, jsUrl, jsLine, pageUrl, userAgent, sessionID));

    Packaging Everything Together in a Control The ASP.NET control includes the JavaScript file (embedded in the dll) on the page and registers some JavaScript that creates the client object and attaches it to the onerror event. To enable JavaScript error logging include the control on your master page:

    <%@ Register TagPrefix="ncl" Namespace="Newtonsoft.ClientLogger" Assembly="Newtonsoft.ClientLogger" %>
    <ncl:ClientLogger runat="server" />

    And register the HttpHandler in the web.config:

    <addverb="*"path="clientlogger.axd"type="Newtonsoft.ClientLogger.ClientLoggerHandler, Newtonsoft.ClientLogger"/>

    Consuming The Web EventThe great thing about ASP.NET Web Events is that you can decide how you want to log the event, and it is simple as modifying your web application's web.config file. For example in just a few lines you can configure ASP.NET to log all errors to your database or send them to an email address. The rule below for example will log all errors to the database. You can learn more about using ASP.NET Web Events here.

    <addname="SqlServerWebErrorLogger"
        eventName="All Errors"
        provider="SqlWebEventProvider"/>

    And that's it. You will now know about JavaScript errors as they happen.The source and dll for the project can be downloaded here: ClientLogger.zip

  • WebDialog 1.0.4 released

    WebDialog 1.0.4 has been released.

    The main new feature in this release is the state of the dialog (visibility, size and position) being remembered on post back. Also new is preliminary support for working within Atlas' UpdatePanel control. Note that this support won't effect regular ASP.NET 2.0 websites.

    What's New:

    • New Feature - Visibility, size and position state posted back from client.
    • New Feature - Preliminary Atlas support.
  • Testing if a ContentPlaceHolder is Empty

    K. Scott Allen, one of the many Scotts who seem to develop in .NET, has written a comprehensive article called Master Pages: Tips, Tricks, and Traps that looks at the new ASP.NET 2.0 feature. I use a couple of those features myself to handle page titles and descriptions, and I highly recommend it to anyone planning to use master pages in the near feature.One trick that I’ve found useful and that isn't in the article is how to modify master page content depending upon whether a ContentPlaceHolder has any content.For example you might have a ContentPlaceHolder on your master for related pages. To make it easier to later modify your design later you want to put the HTML for the container and title in the master, rather than every individual page.

    <div id="divRelatedPages" runat="server">
        <h3>Related Pages...</h3>
        <asp:ContentPlaceHolder ID="cphRelatedPages" runat="server" />
    </div>

    Unfortunately doing it this way will leave a box and title without anything else on a page that didn’t include any related links. The fix to this problem is testing if the ContentPlaceHolder has any content, hiding the divRelatedPages control and title if it doesn’t.To make this test easy I’ve created an IsControlEmpty method. The code inside it is quite simple. It returns true if the placeholder has no child controls or if it has just one child LiteralControl that contains nothing that whitespace. A blank LiteralControl is what is created when an auto-generated placeholder is left empty.

    public static bool IsControlEmpty(Control control)
    {
        if (control == null)
            throw new ArgumentNullException("control");
     
        ControlCollection controls = control.Controls;
     
        // control has no children
        if (controls.Count == 0)
        {
            return true;
        }
        else if (controls.Count == 1)
        {
            LiteralControl staticContent = controls[0] as LiteralControl;
     
            // control only has a literal child which is either empty,
            // or contains nothing but whitespace
            if (staticContent != null)
            {
                if (string.IsNullOrEmpty(staticContent.Text))
                    return true;
                else if (StringUtils.IsWhiteSpace(staticContent.Text))
                    return true;
            }
        }
     
        return false;
    }
     
    public static bool IsWhiteSpace(string s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            if (!char.IsWhiteSpace(s[i]))
                return false;
        }
        return true;
    }

    Now simply pass the placeholder control to the method and hide divRelatedPages based on the result.

    if (ControlUtils.IsControlEmpty(cphRelatedPages))
        divRelatedPages.Visible = false;
  • Boot Camp: Hurting Mac Developers?

    Apple’s announcement and release of Boot Camp, a utility allowing the dual booting of Windows on Intel-based Mac hardware has certainly caused quite a stir, and for good reason. These are some thoughts on what Boot Camp will mean for those with a proclivity for one button mice and grayscale images. In particular, the effect of Mac users increased accessibility to Windows software on Mac developers.

    Mac Users

    This release is obviously good news for existing Apple users. With Intel Macs now able to run Windows the barrier to running Windows applications has fallen dramatically. A $199 Windows license is a lot less than a $1000 PC. Boot Camp means Apple users will now have easy access to Window’s huge library of applications and games, some of which previously wouldn’t have had an equivalent on Mac because of Apple’s smaller market share.

    Apple Computers, Inc

    Apple will also see benefit from Boot Camp, I believe in the form of a slow steady growth in market share. John Gruber wrote an excellent post looking at Boot Camp’s release and made an interesting statement about how Mac’s are no longer different, they’re special. They can run both Windows and OS X. The enthusiast running Windows, who previously would never have considered a Mac because it didn’t have X game or Y application, would now give buying Apple hardware some serious consideration. I expect this will be a gradual process, happening as user’s look around when upgrading their current computers, rather than a sudden rush.

    While the bump in growth from Boot Camp could be slow, I think it will be very good news for Apple as these users will be the best kind to get. Enthusiasts are the people that run websites and have (popular) blogs. They are the movers and shakers of the Window’s world. Tyhco and Gabe of Penny-Arcade for example both recently purchased Macs and have waxed lyrical on the subject to an audience of god knows how many people. Having influential customers is never a bad thing.

    So is Boot Camp a home run for the world for the world of Mac computers? In my opinion, not quite.

    Mac Developers

    While the lower barrier for Apple user’s to run Windows applications will lead to growth in the share of users running Apple hardware, overall the effect on Mac developers will probably negative. The reason? In a word: Competition.

    Apple has a significantly smaller install base than Windows, which translates into a smaller potential market for software that targets OS X. To Mac users the most obvious effect of the smaller market is that software available on Windows, some niche application for example, might not be available for Macs. The market just isn’t large enough to make developing it on OS X commercially viable.

    Since there are no Mac developers producing those very niche market applications there is no harm done by making it easier for users to use with Windows. However the other effect of the smaller market is that where software applications are available on OS X, the range of choice is not as great as it is on Windows.

    In other words there are less developers competing with one another. Where there could be dozens of an application on Windows for some specific task, there may only be a handful on OS X; and where there are only a handful on Windows there may be just one choice on for the Mac.

    Where previously a Mac developer might have been able to charge a premium for his software, possibly because his was the only one for Macs that had a certain feature, he will now have to be much more aware of what the price of the equivalent software on Windows is. Charge too much and he’ll lose sales as user’s who were previously restricted to Mac software by the high cost of buying a separate PC will now buy the Windows version instead. Without the previous premium will he be able to survive? Is it worth him to continue making software targeting OS X given its small install base and the increased competition from the comparatively cut throat world of Windows applications? Time will tell.

    Final thought:

    Apple hardware is now special. It can run on both Windows and OS X. But by the same logic that also means Windows software is special because it can run on both types of hardware. Supposing Apple continues to improve its integration with Windows beyond dual booting to the point where Windows software can run within OS X, where does that leave Mac software?

  • WebDialog 1.0.3 released

    Version 1.0.3 of WebDialog has been released. This release is primarly focused on bug fixes.

    Also included is the source code of 3 example websites: Callback sample, Modal sample and IFrame sample. The samples can also be viewed on the updated WebDialog online demo webpage.

    What's New:

    • Other - Added three sample websites to the WebDialog download: Callback sample, Modal sample and IFrame sample.
    • New Feature - Added an IsVisible() function to the WebDialog JavaScript object.
    • Bug Fix - Fixed the page overlay not hiding with the dialog if Show() was called multiple times.
    • Bug Fix - Message of exceptions thrown during a callback are now displayed in the dialog. Future versions will allow this to be customized in a template.
  • The Perfect Quiz

    Forget personality, IQ, love and every other test or quiz on the internet; the Web 2.0 or Star Wars Character test is here. The creator has somehow managed to combine the ridiculing of the silly Web 2.0 bandwagon that is currently going around with Star Wars. Surely this is the perfect storm of quizzes.

    Obligatory results:

    37/43. I love Star Wars as much as the next IT professional but come on!

  • WebDialog 1.0.2 released

    This release has a couple of bug fixes and new features. 1.0.1 was a minor update correcting the help file.

    What's New:

    • New Feature - Added hover and click states to the dialog hide button.
    • New Feature - Added dialog icon image. By default this shows a different icon depending upon the user's browser. Currently has IE, Firefox, Mozilla and Opera icons.
    • New Feature - Added a ContentStyle property.
    • Bug Fix - DropDown jump issue on Firefox.
    • Bug Fix - Text selection is no longer disabled when dialog is visible.
  • Google Analytics Downtime Solutions

    Google Analytics was down for a few hours today. While it is not unusual for an ASP service to have downtime, Google Analytics works by you including a link to their Javascript file on your website and while the website was down today that file was also unavailable. Anyone who linked to the file in the page header will have found that their websites were not loading. This is because no page content is displayed until all header files have been downloaded. This is a big deal if your business is based around the internet. Some website owners have decided to remove the service entirely because of todays incident.

    The simple fix to this is to include the script tag with the link to http://www.google-analytics.com/urchin.js at the bottom of webpage, which Google now recommends doing. If the Google Analytics website goes down, and the file is unavailable, the page will continue to display normally.

    Although this solves the big problem of no content being display, there are still two issues.

    Analytics Functions

    The first is that any calls to the Google Analytics functions such as urchinTracker to track downloads or outbound links in click events will break. The script containing the function hasn't been loaded, either because Google is down or the user simply clicked the link before the page reached loading the script tag linking to Google. The solution to this is test whether the function exists before it is called.

    <a href="webdialog/webdialog.msi" class="imagelink" onclick="if (typeof(urchinTracker) != 'undefined') urchinTracker('/downloads/webdialog');">

    The other problem is that any of your own Javascript in the page onload event will never be called. The onload event only runs once all content for the page, including Javascript, has been loaded by the browser. If Google Analytics is down and the browser is hung waiting on loading the Analytics script, the onload event on the page will never be raised and Javascript functions attached to the event will never be called. There are two way to deal with this issue: Either place any critical Javascript calls in an Init function, which is then called at the bottom of the page, or use Dean Edward's onload work around.

    Google Analytics is a powerful service, at the right price (free!). Hopefully by taking these precautions you should be able to continue tracking visiters with Google Analytics without it interfering with the rest of your website.

    Update:

    What NOT to do!

    Don't host a local copy of urchin.js yourself and link to that.

    The reason Google is giving out a link to a file, rather than the file itself, is so that they can easily update it when fixing bugs or adding functionality. Updates will trickle down to all websites automatically.

    If you are hosting urchin.js yourself then one day stats for your website may stop working without warning because your version of the file has become out of date.

    Update 2:

    Google has added a page about to their website about hosting the urchin.js file locally. For the same reasons I wrote above they don't recommend it.

  • WebDialog 1.0 released!

    Newtonsoft WebDialog 1.0 has been released and is available to download and to buy.

    Whew! It is a nice feeling to be able to say that :)

    I'd like to thank those that tried out the beta and provided feedback. You helped me fix a number of bugs and cater to some scenarios that I wouldn't have otherwise thought of, and WebDialog is a better product for it.

    You can download WebDialog here:

    http://www.newtonsoft.com/downloads/

    And you can now purchase WebDialog here at the new store:

    http://www.newtonsoft.com/store/

    If you have any questions or queries, don't hesitate to ask.

    This is what is new since the last update a week ago:

    • Bug fix in IE where the page would flicker after dragging the dropdown and then changing a dropdown. You've gotta love IE.
    • Added the name of the WebDialog browser object to the IFRAME. This allows it to more easily be referenced from nested dialog pages.
    • Added documentation. Included is a class reference of WebDialog and other objects, and some task based guides to help new users getting started. They are: Display Content; Hiding, Showing and Positioning; Customizing Appearance; and Creating Modal Dialogs.
    • Packaged everything together in an MSI installer.
  • WebDialog beta available for download

    Newtonsoft WebDialog has gotten to the point where I feel it is ready to begin beta testing.

    Documentation is still largely work in progress but there are installation instructions and intellisense for all new objects, as well as a quickstart guide on this website. The WebDialog beta is fully functional when developing on your own computer.

    WebDialog beta download

    WebDialog quickstart guide

    If you encounter any bugs or have any comments I'd love to hear them. You can either use the support request form or leave a comment here.

  • About WebDialog

    Essentially WebDialog is an ASP.NET control for displaying dialogs inside the browser window. It allows developers to display dialogs when, where and how they want to without all the current browser restrictions.

    A couple of WebDialog examples

    Features

    Anyone who has built rich web sites will know that there are a lot of problems around the area of displaying dialogs. Aggressive popup blockers, no cross platform compatible modal dialogs and simplistic, inflexible confirmation and alert popups all limit what a developer can do when creating a UI. WebDialog is designed to solve many of these issues:

    • Display user friendly dialogs inside the browser window.
    • Display dialogs and popups where and when you want.
    • Cross-browser support.
    • Powerful, yet easy to use.
    • Can create splash screens, confirmations, ad popups, modal dialogs and more!

    Coming Soon

    WebDialog is not quite ready to be released but it should be available within the next few weeks. In the mean time I have put it’s webpage up here. The webpage goes into detail on some of the features mentioned above as well as having more screenshots, a quickstart guide on how it to use it within ASP.NET and some online demos to try out.

  • Hello World

    Welcome to my blog. Peer pressure has claimed another hapless soul. All the cool kids are doing it and who am I to argue with them?

    My name is James Newton-King and I am (at the time of writing this) 22 years old, live in Wellington New Zealand, and am a software developer. You should also know that I'm the kind of person that would spend 10 minutes on Google researching what other people said in their first posts before writing this. I'm not sure what they says about me.

    So whats this all about then?

    Here I'll be blogging about software development in general and .NET and developing on the web in particular. I've learnt a lot from reading other's blogs at blogs.msdn.com and weblogs.asp.net, and articles at sites like Code Project; and I would like to give something back to other new developers.

    Finally, occasionally something off topic might creep in here. It might be about IT. It might be about current events. It might even be something personal. As a request to all both of my future readers, if you ever catch me blogging about what I had for breakfast, please do everyone a favour and tell me to shutup.