Alex Papadimoulis' .NET Blog

Alex's musings about .NET and other Microsoft technologies

  • ScriptOnly - The Opposite of a NOSCRIPT

    Despite all of the advances in client-side scripting, the wonderful JavaScript libraries like Prototype and Scriptaculous, and the ease of writing AJAXy code in ASP.NET, there’s still one aspect of modern web development that can be a complete pain in the butt: accessibility for users without JavaScript. If you’re lucky – perhaps you’re developing an Intranet application, or the like – a simple <noscript>Error: This application requires JavaScript enabled</noscript> is all it takes. But other times, you need to take that extra step and make it work for those with and without JavaScript enabled.

    There’s a lot of ways that this can be accomplished, but one of the more popular ways is with the SCRIPT/NOSCRIPT combo...

    <script type="text/javascript">
        document.write('Only users with JavaScript will see me.');    
    </script>
    <noscript>
        Only users without JavaScript will see me.
    </noscript>
    

    While this works fine in a lot of scenarios, it can get especially tricky when you want to put server-side controls on the SCRIPT side of things. A lot of developers resort to something like this...

    <div id="javaScriptOnly" style="display:none">
        Only users with JavaScript will see me.
        <asp:LinkButton runat="server" ... />
    </div>
    <div id="noJavaScript" style="display:block">
        Only users without JavaScript will see me.
        <asp:Button runat="server" ... />
    </div>
    <script type="text/javascript">
        document.getElementById('javaScriptOnly').style.display = 'block';
        document.getElementById('noJavaScript').style.display = 'none';
    </script>
    

    ... and of course, things quickly get much uglier once you do this in the real world.

    One solution that I use is a simple, custom-control called ScriptOnly. It works just like this...

    <inedo:ScriptOnly runat="server">
        Only users with JavaScript will see me.
        <asp:LinkButton runat="server" onClick="doSomething" ... />
    </inedo:ScriptOnly>
    <noscript>
        Only users without JavaScript will see me.
        <asp:Button runat="server" onClick="doSomething" ... />
    </noscript>

    JavaScript users see a LinkButton, while non-JavaScript users see a plain old submit button. What’s neat about this technique is that you can put any type of content - server-controls, html, script tags, etc - and that content will only be displayed for JavaScript users. In essense, it works like a reverse NOSCRIPT tag.

    Behind the scenes, ScriptOnly is a very simple control...

    [ParseChildren(false)]
    public class ScriptOnly : Control
    {
        protected override void Render(HtmlTextWriter writer)
        {
            //Render contents to a StringWriter
            StringWriter renderedContents = new StringWriter();
            base.Render(new HtmlTextWriter(renderedContents));
    
            //write out the contents, line by line
            writer.WriteLine("<script type=\"text/javascript\">");
            StringReader sr = new StringReader(renderedContents.ToString());
            while (sr.Peek() >= 0)
            {
                // This could be optimized to write on one line; but
                // I've found this makes it easier to debug when
                // looking at a page's source
                writer.WriteLine(
                    "document.writeln('{0}');",
                    jsEscapeText(sr.ReadLine()).Trim());
            }
            writer.WriteLine("</script>");
        }
    
        private string jsEscapeText(string value)
        {
            if (string.IsNullOrEmpty(value)) return value;
    
            // This, too, could be optimzied to replace character
            // by character; but this gives you an idea of
            // what to escape out
            return value
                /*  \ --> \\ */
                .Replace("\\", "\\\\")
                /*  ' --> \' */
                .Replace("'", "\\'")
                /*  " --> \" */
                .Replace("\"", "\\\"")
                /*  (newline) --> \n */
                .Replace("\n", "\\n")
                /*  (creturn) --> \r */
                .Replace("\r", "\\r")
                /* </script> string */
                .Replace("</script>", "</scri'+'pt>");
        }
    }

    When "pre-reistered" in your web.config, it works just as well as the NOSCRIPT tag.

  • Coghead: Web Applications for Dummies by Dummies

    There's been a buzz going around about a new web startup called Coghead.  Heralded by Business 2.0 as one of the "innovations that could reorder entire industries," Coghead is lead by former Red Hat executive Paul McNamara and Extricity founder Greg Olsen. El Dorado Ventures, a Venture Capitalist firm, recently invested $2.3M in the company. According to McNamara,

  • Stop Using Enterprise Manager! (Use DDL Instead)

    Of all the tools that ship with SQL Server, Enterprise Manager is by far the most feature-packed and widely-used. Nearly every SQL Server developer is familiar with Enterprise Manager. They are comfortable using the wizards and GUI to do everything from creating a new table to adding a schedule job. But as a project grows to encompass more developers and environments, Enterprise Manager becomes a detriment to the development process.

  • Holy Crap: I'm an Official MVP for MS Paint

    There are few emails that one will receive in his lifetime that will render him completely speechless. This past weekend, I received one such email. Its subject read Congratulations on your MVP Award!

    I struggle with the words to describe how elated I am to be chosen for this award. Sure, I’ve worked my butt off in microsoft.public.accessories.paint, helping both newbies and vets solve their problems. But I never expected this. For me, it’s always been about my love of the Paint, and sharing my knowledge and expertise of Paint with the world.

    I don’t want to bore you with me patting my self on the back, so I’ll just use the rest of this space to share my top three tips and tricks. I’ve got plenty more, so if you ever need some help with Paint, don’t hesitate to ask this MVP!


    Why are some of my edges jagged?
    You’ve discovered one of the dark secrets of digital art: pixilation. Because everything in your Paint image is made of small square blocks, the only way to make a diagonal line or a curve is to arrange the pixels in “steps;” these very steps give the image that ugly, jagged appearance.

    Fortunately, we can help smooth out the jagged edges with a technique called anti-aliasing. The trick is to make the jagged edge an in-between color of the two bodies of colors. For our red circle and white background, all we need is pink, applied with the spray paint can tool.

    And like magic, the jagged edge is no more!

    How do I do shadows?
    Shadows in Paint are incredibly easy to do:
    1) Draw the shape you want to draw, but instead use black
    2) Draw the shape you want to draw, using the colors you really want to use, but draw it at an angle slightly away from the black shape

    Look ma, a shadow!

    How can I make realistic looking Hair?
    This is one of the more difficult things to accomplish in Paint. But it’s certainly doable. First, you need to figure out what hair style you want to use. Once you figure that out, it’s just a matter of using the right tool.

    Curl

    Believe it or not, this is a simple matter of using the wonderfully handy spray can tool. Just pick the hair color, and go crazy!!!

    Baldy

    This hairstyle is so ridiculously simple you’ll wonder why more cartoons characters aren’t bald. Simply apply the ellipse tool twice, above each ear, and you’ve got yourself a bald guy!

    Side Part

    When you want to make your character look neat and orderly, only the polygon tool will do. Here’s something funny: I like to part my own hair on the left, but draw it parted on the right. Funny, see, I told you!

    Bed Head

    Oh no, caught red handed without a comb! You can easily achieve this look with the use of the paint brush tool. Don’t go too crazy, it’s pretty easy to slip and go through an eye.


    Be sure to congratulate Jason Mauss as well. He was awarded this year’s MSN Messenger MVP.

  • Express Agent for SQL Server Express: Jobs, Jobs, Jobs, and Mail

    UPDATE: My appologies, but with the advent of relatively inexpensive commercial solutions avaiable, I've decided to suspend this project indefinitely. If I do need a solution for myself, I may take it up again. But until then, I would recommend getting a commercial version (http://www.valesoftware.com/products-express-agent.php is one source) or using the Windows Task Manager to run batch files.

  • Gettin' Down in Detroit: The 2005 Launch Party

    I saw that Jason Mauss wrote about his experience at the San Fransisco 2005 Launch Party, so I thought I'd share my experience at the Detroit venue. Because it wasn't the "real" Launch Party, we didn't have anything fancy like a speech from Steve Balmer, songs performed by AC/DC, or appearances by the guys from Orange County Choppers. But it was still a good time. Please bare with my lack of actual photographs, as I did not have the foresight to bring a camera.

  • MySQL 5.0: Still A "Toy" RDBMS

    "Ha," an email from a colleague started, "I think you can finally admit that MySQL is ready to compete with the big boys!" I rolled my eyes and let out a skeptical "uh huh." His email continued, "Check out Version 5. They now have views, stored procedures, and triggers."

    My colleague has been a MySQL fan since day one. He loves the fact that it's free and open source and could never quite understand why anyone would spend tens of thousands of dollars on something else. But then again, he has never really had an interest in understanding; data management just isn't his "thing." Thankfully, he readily admits this and stays far, far away from anything to do with databases, leaving all of that "stuff" to the experts. No less, he'll still cheers whenever there's a MySQL "victory." it is, after all, free and open source.

    Data professionals have traditionally relegated MySQL as a "toy" relational database management system (RDBMS). Don't get me wrong, it's perfectly suitable for blogs, message boards, and similar applications. But despite what its proponents claim, it has always been a non-choice for data management in an information-system. This is not a criticism of the "free open source" aspect of the product, but of its creators.

    The MySQL developers claim to have built a reliable RDBMS yet seem to lack a thorough understanding of RDBMS fundamentals, namely data integrity. Furthermore, they will often surrogate their ignorance with arrogance. Consider, for example, their documentation on invalid data [emphasis added]:

    MySQL allows you to store certain incorrect date values into DATE and DATETIME columns (such as '2000-02-31' or '2000-02-00'). The idea is that it's not the job of the SQL server [sic] to validate dates.

  • "When Should I Use SQL-Server CLR User Definied Types (UDT)?"

    No one has asked me that question just yet, but with the release of SQL Server 2005 just around the corner, I'm sure a handful of people will. Unlike regular User Defined Types, CLR UDTs are a new feature of SQL Server 2005 that allows one to create a .NET class and use it as a column datatype. As long as a few requirements are followed, one can create any class with any number of properties and methods and use that class as a CLR UDT.

    Generally, when a new feature is introduced with a product, it can be a bit of a challenge to know when and how to use that feature. Fortunately, with SQL Server's CLR UDTs, knowing when to use them is pretty clear:

    Never.

    Let me repeat that. Never. You should never use SQL Server CLR User Defined Types. I'm pretty sure that this answer will just lead to more questions, so allow me to answer a few follow-up questions I'd anticipate.

    Why Not?
    CLR UDTs violate a fundamental principle of relational databases: a relationship's underlying domains must contain only atomic values. In other words, the columns on a table can contain only scalar values. No arrays. No sub-tables. And, most certainly, no classes or structures. Remember all the different levels of normalization? This is the first normal form, you know, the "duh" one.

    This is a big thing. One can't just go and fudge a tried-and-true, mathematically-validated, theoretically-sound concept and "add and change stuff to it 'cause it'll be cool." Think of how much your car would love driving on a road made of stained glass blocks three years after it was built by an engineer who thought it'd look better.

    Deviating so grossly from the relational model will bring as much joy as a dilapidated glass road. Take Oracle's foray into relational abuse: nested tables. I don't believe that there has ever been a single, successful implementation of that abomination. Sure, it may work out of the box, but after a year or two of use and maintenance, it decays into a tangled mess of redundancy and "synch" procedures -- both completely unnecessary with a normalized relational model.

    And if that doesn't convince you, just think of having to change that CLR UDT. How easy do you think it would be to add a property to the class representing a few million rows of binary-serialized objects? And, trust me, it won't be nearly as easy as you think.

    But wouldn't I want to share my .NET code so I don't have to duplicate logic?
    This is always a novel goal, but an impossible one. A good system (remember, good means maintainable by other people) has no choice but to duplicate, triplicate, or even-more-licate business logic. Validation is the best example of this. If "Account Number" is a seven-digit required field, it should be declared as CHAR(7) NOT NULL in the database and have some client-side code to validate it was entered as seven digits. If the system allows data entry in other places, by other means, that means more duplication of the "Account Number" logic.

    By trying to share business logic between all of the tiers of the application, you end up with a tangled mess of a system. I have illustrated this in the diagram below.

  • "What's the Point of [SQL Server] User-Defined Types?"

    I'm asked that question every now and then from other developers who've played around in SQL Server Enterprise Manager and noticed the "User Defined Data Types" tab under their database. UDT seem a bit strange and pointless because they do not allow one to define (as one might expect) a data structure with more than one related data element. A UDT consists simply of a name and a base type (INT, VARCHAR(6), etc).