2005 2006 2007 2008 2009 2010 2011 2015 2016 2017 2018 aspnet azure csharp debugging docker elasticsearch exceptions firefox javascriptajax linux llblgen mongodb powershell projects python security services silverlight training videos wcf wpf xag xhtmlcss

.NET Course I'm teaching

So, for a while now I've been teaching a .NET 2.0/C# 2.0/Object-oriented desing class and decided to come up with a simple class website.

I'm covering not only the basics, but also many advanced topics that you would only find in footnotes. Mainly I'm going to be covering stuff that I wish someone would explain to me in plain english!! So, I'm going to be spending time explaining the differences between ref and out, const and readonly, and try{}catch{} and try{}catch(Exception ex){} among other topics. You can bet that I'll be spending A LOT of time just on delegation!!

There are actually a few series going on at once: C# Language (Intro, Intermediate, Advanced), .NET Framework and Design, Object Orientation and Design Patterns, SOA and Enterprise Development, ASP.NET 2.0 (web-standards "tableless"/CSS!!!), and WinFX concepts are the series all going on in parallel.

As far as the intro ASP.NET stuff is concerned, there are great ASP.NET books out for that kind of stuff. I'm mainly focusing on the middle layer and more advanced concepts. I'm actually planning a lecture for Microsoft Atlas. Given my love for Firefox, .NET, and remote scripting (err, Ajax), that should be fun! Also in the course of things I plan on having a lecture to discuss .NET design guidelines and another lecture on the architecture and mechanics of the CLR! .NET assembly language (yeah, yeah, the IL) rules!

Now what is my supplemental book recommendation? Basically anything that Troelsen has written. His latest book "Pro C# 2005 and the .NET 2.0 Platform" is written incredibly eloquently.

I absolutely love .NET... and this should show! maybe I can get an MVP out of this :D hint hint!!

Anyhow, here's the page I threw togther for it. I'll be posting more information, links, and samples as time goes along.http://www.davidbetz.net/dotnetcourse/

C# Fundamentals Exam Released!



Awesome! The Brainbench C# Fundamentals exam just went public! Why do I care? Well, because I was the technical editor for the exam! I'm rather excited because this was my first publicly shown work as a technical editor of anything.

I think exam takers will find the exam to be fair. It's not too terribly advanced, but it's not a beginners exam either. It should really test if you know what you're talking about. One thing that I will remind everyone of is that C# is a standardized language, not "some Microsoft language". So, this exam tests your knowledge of the official C# (ECMA-334) language, not your slang usages of it. Also, sadly, this exam is on the older C# 1.0, not 2.0, which is my favorite language.

Currently the exam is available for free at brainbench.com. The full link is below. Enjoy!

Exam Update



Well, I'm a month into the ACTUAL writing of the C# 2.0 exam and I'm finding it just as fun as I thought it would be. This exam is more advanced than most people are probably going to want it to be, but I just can't imagine WHY someone would want to take a sissy exam. That doesn't help anyone. On the other end of things, anyone who knows Richter's CLR via C# book by heart should do great on this exam.

The only previews I can give at this time are that this exam is really more of a C#/CLR 2.0 exam as I have a sections for reflection and AppDomain management. I also have sections for more controversial things like COM Interop and unsafe code (not too bad-- I'm not about to ask pointer arithmetic questions!). The other thing I can say is that this complements the 70-* certification exams in that this covers the more technical dimension of the CLR, C#, and the framework. It's more like computer science exams than the certification exams. That is, they are more algorithmic than scenario-based.

As I progress, I'm also setting aside questions for a possible CLR 2.0 exam (for my own exam; probably not Brainbench). I figure this exam could cover things like fusion, assembly loading mechanics, CLR internal memory management, identification of core DLLs ( i.e. mscorwks.dll) and other fun topics. I would really like to see "IT" people think MUCH more like CS people; internals and mechanics are VERY good things to know.

Brad Abram's Presentation



Anyone who knows me knows I'm an architect and designer at heart… every time I see construction work I just stare at it and study how everything is being planned. Heck, I learned much of software architecture from watching Discovery Channel's Extreme Engineering. I love the stuff… ergo, Brad Abrams is my hero. His work is astonishing. As far as I'm concerned he is the glue that kept the BCL together.

Everyone NEEDS to check out his latest presentation on design guidelines. This is some good stuff. Usually I think PowerPoint is a mind numbing waste of time, but this presentation is great. By the way, if you don't OWN the design guidelines book by Krzysztof Cwalina and Brad Abrams, YOU NEED TO. If you never looked at it, please stop writing code today.

Check it out...

.NET Slides



Back in 2005 I taught a class where I gave an overview of various parts of the .NET universe (at the time, the WinFX universe). I covered everything from C# to data binding to ASP.NET to service-oriented architecture to web standards. My goal was to give a familiarization with each of the topics so that the students can then learn the topics on their own in a way that best fits them.

My first session, however, was a presentation experiment. Instead of using really nasty verbose slides, I had just a few words on a slide and on one slide I had simply the number 42. Don Box would have loved my presentation. The point of the experiment was to make sure that people were paying attention to the topic and not simply reading a useless slide. I really think that PowerPoint is a massive hindrance to education. You can access my experimental presentation, named .NET Overview, below.

My next to last session was on web standards and in this session I simply told a story and then gave a few examples showing how web standards development is the only web development that is acceptable. You can access this presentation, named Web Standards Presentation, below.

Below is also a link to a video where Don Box talks about giving great technical presentations. I would recommend this video to anyone who gives talks on really any topic. Don't just watch it, study it. It takes practice.

The ECMA-334 Standard



Let me state publicly for the record: I do not approve of books for learning C#. The only guide you will ever need is the ECMA-334 standard. It's a readable guide to the entire C# language that covers every facet of the language. This document is the definitive guide for C#. In fact, there is no document on MSDN that even comes close to the comprehensive native of C# than does the ECMA-334 standard as the ECMA-334 standard is C#.

Why do I mention this at all? Because, from time to time I get people asking me what book he or she should *buy* to learn C# and I always tell them what I've just stated above. Unlike Visual Basic, C# is NOT Microsoft's baby. They may have been the ones who gave birth to C# and continue feed it and nurture it, but it's a standard -- not Microsoft's baby.

Lastly, while you are getting the ECMA-334 standard, check out the ECMA-335 standard. This one is the standard for the CLI (Common Language Infrastructure -- which Microsoft implements as the CLR or Common Language Runtime). It goes into detail about the IL (Intermediate Language), the Common Language Specification (CLS), the Common Type System, and talks in some detail about various .NET concepts. I would consider this standard to be more advanced than what most people need at first, so I don't recommend this for initial learning (for that get Duffy's Professional .NET Framework 2.0 [0764571354] and then Richter's CLR via C# [0735621632]).

As a footnote, you could also check out the ECMA-262 standard (ECMAScript, that is, JavaScript), but it's not nearly as well written as the ECMA-334 and ECMA-335 standards and because of that I've never recommended it's reading to anyone.

Minima and Data Feed Framework Renamed and Explained



As of today I'm renaming any of my CTP releases to simply… "releases". That is, my Minima February 2007 CTP is now "Minima - February 2007 Release" and my Data Feed Framework February 2007 CTP is now "Data Feed Framework - February 2007 Release".

The motivation behind these is different for each. With regard to Minima, I knew it wouldn't be a long term or real production project, so announcing it as a CTP was a mistake on my part. Not a big deal. Lesson learned. Furthermore, I knew from the start that it would be more of a training tool than anything else. With regard to my Data Feed Framework (DFF), after using it in various areas I realized that my initial release was sufficient for most scenarios.

As a reminder… what is Minima? Minima is an ASP.NET 2.0 blog engine built using a SQL Server 2005 database and an LLBLGen Pro 2.0 DAL that provides the base functionality that most technical bloggers would need. Since it's initial release I've added some functionality to my own instance of Minima and have used the February 2007 release as a training tool numerous times. Moving forward I want to make it very clear that Minima is primarily a training tool and a such, it's a blog template that people learning ASP.NET can enhance and upgrade to aide in their own personal learning. Having said that, Minima is a full fledged blog engine and it does have features such as labels and the ability to have more than one URL point to the same entry. In any case, if you want something to help you learn the various components of ASP.NET, please feel free to take Minima and use it as you please (see attribution/licensing note below).

By using Minima as a training tool you can learn much about base ASP.NET technology as well as manual Ajax prinicples, CSS theming, HttpWebRequest, proper use of global.asax, framework guidelines, and type organization. Furthermore you can use it to learn WCF, the power of HTTPHandlers, and how to effectively utilize LLBLGen Pro. I will try to release versions of Minima to demonstrate the new technologies of the day. For example, when ASP.NET Ajax matures a bit (I find it slower than a dead turtle right now), I'll be adding portions to demonstrate ASP.NET Ajax. However, I will not be adding new functionality for the sake of functionality. If the functionality can be used as a training tool, then I will add it. Also, Minima is a great way of learning WPF. How so? I deliberately did NOT include a client! Why? Because I would rather you use whatever you want to use to create a simple form to access the API via WCF. The client I use a very basic WPF client that calls the Minima WCF service. So far, Minima has been a very effective learning tool and I hope you will find it useful as well.

As far as my Data Feed Framework (DFF). What is it? It's a self-contained framework that converts SQL statements into RSS feeds. I've used this in a number of places where creating a manual RSS feed and MANAGING the RSS feeds would just be too time consuming. For example, say you have a ASP.NET 2.0 e-commerce website and you have new products released at various intervals. Well, it would be AWESOME if you had an RSS feed to announce new products and sales without having to send out an ethically questionable e-mail blast. With DFF, you simply write something like "select Title=ProductName, Description=ProductDescription from Product where ProductDate > '7/11/07' order by ProductDate desc" and BAM you have an RSS feed. Since an RSS feed is simply a select statement in a column in a row in a SQL Server table, you could also use it to dynamically create a custom feed for each person who wants to monitor the price of a certain product. It's very flexible. RSS feeds are accessible via their name, their ID, or you can use a "secret feed" to force a feed to be accessible via GUID only. DFF also includes some templating abilities to help customize the output of the RSS feed. In addition to the DFF SQL to RSS engine, DFF also includes an ASP.NET 2.0 control called an InfoBlock that allows you to consume any RSS feed and display it as an XHTML list. You can see an example of how to use an InfoBlock my looking at my blog. The boxes on the right are InfoBlocks which allow me to manage my lists using a SQL Server table (the DFF database contains a Snippet and a SnippetGroup table to store autonomous information like the information in these lists--please see the documentation for more information). DFF is creating secret RSS feeds that my own personal version of Minima then consumes. With this as an example, it should be easy to see how DFF can be used in portals. My DFF demonstration video shows a bit more of that.

For more information regarding my Data Feed Framework (DFF), please skim the concise documentation for Data Feed Framework linked below. It would also probably be a good idea for you to watch my short video documentation for DFF as well. Please note that even though DFF is designed to be a production framework, it too can be used as a training tool. The most obvious thing you can learn is how to create data-bound server controls for ASP.NET 2.0 as this is exactly what an InfoBlock is.

You may use either the SQL->RSS engine or the InfoBlock portion or both. It's up to you. Also, as with all my .NET technologies that I create, the source and database files are included for extensibility and so you may use these as training tools (for yourself or for others). Lastly, for both Minima and Data Feed Framework, please remember to keep the license information intact and make it very clear that your work either uses or is based on either whichever product you are using.

Minima - Links

Data Feed Framework - Links

NetFXHarmonics SolutionTemplate/E-Book



Recently I started putting together my standard .NET solution template for public release. This template contains the base architecture and functionality that all my projects need. This template is also organized in a very clear way that clearly separates each type of element into it's own section to maximize expansion and ease of development.

In order to make sure that the solution is understandable by many different types of developers, there are commentaries in each file in the solution. In addition to this, many of the files have full chapter-length lessons on a development topic contained in that file. For example, in the Code/SampleDomManipulator.js file, I wrote a rather extensive introduction to JavaScript browser dynamics through DOM manipulation. Because of these lessons, this solution template is also living .NET e-book.

Here is a list of some of the topics I've written about in this first release of my solution template, some of them are simple explanations and others are lengthy detailed lessons.

  • HttpHandler Creation
  • HttpModule Creation
  • HttpHandlerFactory Creation
  •  
  • Custom Config Section Creation
  • .NET Tracing
  •  
  • MasterPages Concepts
  • Global.asax Usage
  •  
  • CSS Theming, Management, and Media-Specific Sheets
  •  
  • JavaScript Namespaces
  • JavaScript File Consolidation
  • Firefox Console Usage
  • JavaScript Anonymous functions
  • JavaScript Multicast Event Handling
  • DOM Element Creation
  • DOM Element Manipulation
  • DOM Element Deletion
  • JavaScript Event Handling with Low Coupling
  •  
  • JavaScript GET/POST XmlHttp Service Interop
  • Manual XmlHttp Service Creation
  •  
  • JavaScript/CSS/ASP.NET/C# Code Separation
  • Highly Cohesive Type Organization

This solution template could be used for the basis for production projects or as a training utility for people new to ASP.NET, people new to JavaScript, DOM Manipulation or AJAX or people who just want to learn how to organize their projects more effectively.

As with all my projects, but much more so with this one, I will be updating the solution template over time to account for more AJAX techniques and .NET technologies. I will also continue to expand the commentaries and lessons to the point where this solution itself becomes a case study, a sample application, and book all wrapped up in one.

Links

Minima, DFF, and SolutionTemplate/E-Book now in Subversion



I've recently realized how lame it is to have to download a new ZIP file each file a new version of a framework is released or when a project has some changes. So, I'm moving my projects to Subversion instead of making everyone download my ZIP files. This should help me update the projects more often and allow everyone else to get my projects easier. Please note that this replaces all RAR/ZIP files I've previously released.

Currently, I have the following projects in Subversion:

  • Minima
  • Data Feed Framework
  • NetFXHarmonics .NET SolutionTemplate With E-Book

You can access these projects with any Subversion client, though you would probably want to use TortoiseSVN for Windows development. You can access the projects at the following SVN HTTP addresses. You are free to also use these SVN HTTP locations to browse through the code in your web browser. My primary emphasis is in .NET training and education, so I do hope this helps. Also, given that my SolutionTemplate is also my e-book, you can easily look at the files there and read them online without having to download the project.

Note the /trunk/ path at the end. There are currently no projects in the tags section of the Subversion repository and, honestly, I'm still planning what to do with that section. The branches section is currently set to not allow anonymous access.

By the way, if you're unfamiliar with it, Subversion is an incredibly powerful and seamlessly easy to use revision control system that allows for code repositories (that is, code stores) to be stored in a centralized local to allow access from diverse locations. Subversion also does automatic versioning of your commits (that is, saves) to the code repository. Not just versioning as in a magic number change, but also as in it saves all versions of your files so you can go back and see your changes over time.

Subversion is used for many different reasons and some of them have nothing to do with code. For example, I've been using something similar to it (CVS) for a rather long time now to store all my documents so I can keep everything stored in a centralized location and so I can see the progress of my work. One use that I found rather interesting was that one company was using Subversion to store and provision new instances of their application. So, you can use it as a place to store your code, as a global file system, or as an application repository. Subversion stores whatever you want to store, including binary files. For more information on Subversion, see the online O'Reilly e-book "Version Control with Subversion" below.

Related Links

Simplified Universal HttpHandlerFactory Technique



A few months ago I wrote about the Universal HttpHandlerFactory Technique where you have one HttpHandlerFactory that all your ASP.NET processing goes through and then in that HttpHandlerFactory you then choose what HttpHandler is returned based upon what directory or file is accessed.  I still like this approach for certain scenarios, but my blog got to the point where I was managing 11 different HttpHandlers for about 25 different path and file patterns.  So, it was time to simplify.

What I came up with was basically my go to card for everything: put it in SQL Server.  From there I just checked the URL being accessed against the patterns in a database table and then looked up what HttpHandler to use for that particular request.  Then, of course, I cached the HttpHandler for future file access.

Here are my SQL Server tables (yes, I do all my design in T-SQL-- SQL GUI tricks are for kids):

create table dbo.HttpHandlerMatchType  (
HttpHandlerMatchTypeId int primary key identity not null,
HttpHandlerMatchTypeName varchar(200) not null
) 

insert HttpHandlerMatchType select 'Contains' insert HttpHandlerMatchType select 'Starts With' insert HttpHandlerMatchType select 'Ends With' insert HttpHandlerMatchType select 'Default'

create table dbo.HttpHandler ( HttpHandlerId int primary key identity not null, HttpHandlerMatchTypeId int foreign key references HttpHandlerMatchType(HttpHandlerMatchTypeId), HttpHandlerName varchar(300), HttpHandlerMatchText varchar(200) )

Here is the data in the HttpHandler table:

 HttpHandler Table

Looking at this image and the SQL Server code, you can see that I'm matching the URL in different ways.  Sometimes I want to use a certain HttpHandler if the URL simply contains the text in the HttpHandlerMatchText and other times I'll want to see if it the URL ends with it.  I included an option for "starts with" as well, which I may use in the future.  This will allow me to have better control of how paths and files are processed.  Also, notice that one is "base".  This is a special one that basically means that the following HttpHandler will be used (keep in mind we are in a class that inherits from the PageHandlerFactory class-- please see my original blog entry):

base.GetHandler(context, requestType, url, pathTranslated);

Now in my HttpHandlerFactory's GetHandler method I'm doing something like this (also note how LLBLGen Pro helps me simply my database access):

HttpHandlerCollection hc = new HttpHandlerCollection( );
hc.GetMulti(new PredicateExpression(HttpHandlerFields.HttpHandlerMatchTypeId != 4));


IHttpHandler hh = null;
foreach (HttpHandlerEntity h in hc) {
    hh = MatchHttpHandler(absoluteUrl, h.HttpHandlerName.ToLower( ), h.HttpHandlerMatchTypeId, h.HttpHandlerMatchText.ToLower( ));
    if (hh != null) {
        break;
    }
}

This is basically just going to look through all the HttpHandlers in the table which are not the "default" handler (which will be used when there is no match).  The MatchHttpHandler method basically just passes the buck to another method depending of whether I'm matching the URL based on Contains, StartsWith, or EndsWith.

private IHttpHandler MatchHttpHandler(String url, String name, Int32 typeId, String text) {
    IHttpHandler h = null;
    switch (typeId) {
        case 1:
            h = MatchContains(url, name, text);
            break;
    <span style="color: rgb(0,0,255)">case</span> 2:
        h = MatchStartsWith(url, name, text);
        <span style="color: rgb(0,0,255)">break</span>;


    <span style="color: rgb(0,0,255)">case</span> 3:
        h = MatchEndsWith(url, name, text);
        <span style="color: rgb(0,0,255)">break</span>;


    <span style="color: rgb(0,0,255)">default</span>:
        <span style="color: rgb(0,0,255)">throw</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">ArgumentOutOfRangeException</span>(<span style="color: rgb(128,0,0)">"Invalid HttpHandlerTypeId"</span>);
}


<span style="color: rgb(0,0,255)">return</span> h;
}

Here is an example of one of these methods; the others are similiar:

private IHttpHandler MatchContains(String url, String name, String text) {
    if (url.Contains(text)) {
        return GetHttpHandler(name);
    }
    return null;
}

As you can see, it's nothing fancy.  The last method in the chain is the GetHttpHandler, which is basically a factory method that converts text into an HttpHandler object:

private IHttpHandler GetHttpHandler(String text) {
    switch (text) {
        case "base":
            return new MinimaBaseHttpHandler( );
    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"defaulthttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">DefaultHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimaapihttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaApiHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimafeedhttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaFeedHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimafileprocessorhttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaFileProcessorHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimapingbackhttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaPingbackHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimasitemaphttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaSiteMapHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimatrackbackhttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaTrackBackHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"minimaurlprocessinghttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">MinimaUrlProcessingHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"projectsyntaxhighlighterhttphandler"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">ProjectSyntaxHighlighterHttpHandler</span>( );


    <span style="color: rgb(0,0,255)">case</span> <span style="color: rgb(128,0,0)">"xmlrpcapi"</span>:
        <span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">XmlRpcApi</span>( );


    <span style="color: rgb(0,0,255)">default</span>:
        <span style="color: rgb(0,0,255)">throw</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,128,128)">ArgumentOutOfRangeException</span>(<span style="color: rgb(128,0,0)">"Unknown HttpHandler in HttpHandlerMatchText"</span>);
}
}

There is one thing in this that stands out:

case "base":
    return new MinimaBaseHttpHandler( );

If the "base" is simply a call to base.GetHandler, then why am I doing this?  Honestly, I just didn't want to pass around all the required parameters for that method call.  So, to make things a bit more elegant I created a blank HttpHandler called MinimaBaseHttpHandler that did absolutely nothing.  After the original iteration through the HttpHandlerCollection is finished, I then do the following (it's just a trick to the logic more consistent):

if (hh is MinimaBaseHttpHandler) {
    return base.GetHandler(context, requestType, url, pathTranslated);
}
else if(hh != null){
    if (!handlerCache.ContainsKey(absoluteUrl)) {
        handlerCache.Add(absoluteUrl, hh);
    }
    return hh;
}

One thing I would like to mention is something that that sample alludes to: I'm not constantly having everything run through this process, but I am caching the URL to HttpHandler mappings.  To accomplish this, I simply setup a simple cached dictionary to map URLs to their appropriate HttpHandlers:

static Dictionary<String, IHttpHandler> handlerCache = new Dictionary<String, IHttpHandler>( );

Before ANY of the above happens, I check to see if the URL to HttpHandler mapping exists and if it does, then return it:

if (handlerCache.ContainsKey(absoluteUrl)) {
    return handlerCache[absoluteUrl];
}

This way, URLs can be processed without having to touch the database (of course ASP.NET caching helps with performance as well).

Related Links

All my work in this area has been rolled-up into my Themelia ASP.NET Framework, which is freely available on CodePlex. See that for another example of this technique.

Real World HttpModule Examples



Back when I first discovered HttpHandlers I remember being ecstatic that the control that I thought I lost when moving from PHP to ASP.NET was finally returned, but when I first discovered HttpModules I remember almost passing out at the level of power and control you get over the ASP.NET request pipeline.  Since then, I've used HttpHandlers, HttpHandlerFactories, and HttpModules in many projects, but I'm noticing that while many people have heard of them, many have no idea what you would ever use them for.  So, I would like to give a few examples.

The first example is really simple.  On my blog, I didn't ant anyone to alias my web site or access it in any other way than by going to www.netfxharmonics.com.  Since HttpModules allow you to plug into the ASP.NET request pipeline, I was able to quick write an HttpModule to do exactly what I wanted:

public class FixDomainHttpModule : IHttpModule
{
    public void Dispose( ) {
    }

<span style="color: rgb(0,0,255)">public</span> <span style="color: rgb(0,0,255)">void</span> Init(<span style="color: rgb(0,128,128)">HttpApplication</span> context) {
    context.BeginRequest += <span style="color: rgb(0,0,255)">delegate</span>(<span style="color: rgb(0,128,128)">Object</span> sender, <span style="color: rgb(0,128,128)">EventArgs</span> ea) {
        <span style="color: rgb(0,128,128)">HttpApplication</span> ha = sender <span style="color: rgb(0,0,255)">as</span> <span style="color: rgb(0,128,128)">HttpApplication</span>;
        <span style="color: rgb(0,128,128)">String</span> absoluteUrl = ha.Context.Request.Url.ToString( ).ToLower( );
        <span style="color: rgb(0,0,255)">if</span> (ha != <span style="color: rgb(0,0,255)">null</span>) {
            <span style="color: rgb(0,0,255)">if</span> (<span style="color: rgb(0,128,128)">MinimaConfiguration</span>.ForceSpecifiedDomain) {
                <span style="color: rgb(0,0,255)">if</span> (!absoluteUrl.StartsWith(<span style="color: rgb(0,128,128)">MinimaConfiguration</span>.Domain.ToLower( ))) {
                    context.Response.Redirect(<span style="color: rgb(0,128,128)">MinimaConfiguration</span>.Domain);
                }
            }
        }
    };
}

}

...with this web.config:

<httpModules>
  <add name="FixDomainHttpModule" type="Minima.Web.HttpExtensions.FixDomainHttpModule" />
</httpModules>

By doing this I don't need to put a check in each page or in my MasterPage.  Since HttpModules are for the entire application, even URLs accessing my images are forced to be done by www.netfxharmonics.com.

Another example is a simple authentication system for a system I was working on a while back.  The application allowed anyone logged into active directory to access it's resources, but only certain people logged into active directory would be authorized to the use application (i.e. anyone could access images and CSS, but only a few people could use the system).  Knowing that the .NET framework is the model for all .NET development, I looked at the machine's web.config to see how ASP.NET implemented its windows and form authentication.  As it turns out, it does so by HttpModules.  So, I figured that the best way to solve this problem was by creating an HttpModule, not by throwing a hack into each of my WebForms or my MasterPages.  Furthermore, since ASP.NET uses the web.config for its configuration, including authentication configuration, I wanted to allow configuration of my authentication module to be via the web.config.  The general way I wanted to configure my HttpModule would be by a custom configuration section like this:

<Jampad>
    <Security RegistrationPage="~/Pages/Register.aspx" />
</Jampad>

The code for the HttpModule was extremely simple and required only a few minutes to throw together.  If the page being accessed is a WebForm and is not the RegistrationPage set in web.config, then the system's Person table is checked to see if the user logged into the machine has an account in the application.  If not, then there is a redirect to the RegistrationPage.  Simple.  Imagine how insane that would have been if you wanted to test for security on each page.

public class JampadSecurityModule : IHttpModule
{
    public void Dispose( ) {
    }
<span style="color: rgb(0,0,255)">public</span> <span style="color: rgb(0,0,255)">void</span> Init(HttpApplication context) {
    context.BeginRequest += <span style="color: rgb(0,0,255)">delegate</span>(<span style="color: rgb(43,145,175)">Object</span> sender, <span style="color: rgb(43,145,175)">EventArgs</span> ea) {
        HttpApplication ha = sender <span style="color: rgb(0,0,255)">as</span> HttpApplication;


        <span style="color: rgb(0,0,255)">if</span> (ha != <span style="color: rgb(0,0,255)">null</span>) {
            CheckSecurity(context);
        }
    };
}


<span style="color: rgb(0,0,255)">private</span> <span style="color: rgb(0,0,255)">void</span> CheckSecurity(HttpApplication context) {
    SecurityConfigSection cs = (SecurityConfigSection)<span style="color: rgb(43,145,175)">ConfigurationManager</span>.GetSection(<span style="color: rgb(163,21,21)">"Jampad/Security"</span>);


    <span style="color: rgb(0,0,255)">if</span> (<span style="color: rgb(43,145,175)">String</span>.IsNullOrEmpty(cs.Security.RegistrationPage)) {
        <span style="color: rgb(0,0,255)">throw</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(43,145,175)">SecurityException</span>(<span style="color: rgb(163,21,21)">"Security RegistrationPage is required."</span>);
    }


    <span style="color: rgb(0,0,255)">if</span> (cs == <span style="color: rgb(0,0,255)">null</span>) {
        <span style="color: rgb(0,0,255)">return</span>;
    }


    <span style="color: rgb(0,0,255)">if</span> (!context.Request.Url.AbsoluteUri.Contains(cs.Security.RegistrationPage) &amp;&amp;
        context.Request.Url.AbsoluteUri.EndsWith(<span style="color: rgb(163,21,21)">".aspx"</span>)
        ) {
        PersonCollection pc = <span style="color: rgb(0,0,255)">new</span> PersonCollection( );
        pc.GetMulti(<span style="color: rgb(0,0,255)">new</span> PredicateExpression(PersonFields.NTLogin==ActiveDirectoryFacade.NTUserName));


        <span style="color: rgb(0,0,255)">if</span>(pc.Count &lt; 1){
            context.Response.Redirect(cs.Security.RegistrationPage);
        }
    }
}
}

Again, plugging this into the web.config makes everything automatically happen:

<httpModules>
    <add name="JampadSecurityModule " type="Jampad.Security.JampadSecurityModule" />
</httpModules>

Recently I had to reuse my implementation in an environment that would not allow me to use LLBLGen Pro, so I had to rewrite the above 2 lines of LLBLGen Pro code into a series of Strongly-Typed DataSet tricks.  This implementation also had a LoginPage and an AccessDeniedPage in the custom configuration section, but other than that it was the same idea.  You could actually take the idea further by checking if the person is currently authenticated and if they aren't do a check on the Person table.  If they have access to the application, then PersonLastLoginTime column to the current time.  You could do many things with this implementation that would be rather crazy to do in a WebForm or MasterPage.

Another example of an HttpModule would be my custom access control system I built into my blog.  I'm not going to paste the code here as it's just the same idea as the other examples, but I will explain the concept.  Basically I created a series of tables in my blog's SQL Server database that held information on access control.  In the Access table I put columns such as AccessDirection (allow, deny), AccessType (IP Address, UserAgent, HTTP Referral), AccessText, AccessMessage, and AccessRedirect.  My HTTPModule would filter every ASP.NET request through this table to figure out what to do with it.  For example, I could block an IP address by creating a table record for 'deny', 'IP Address', '10.2.1.9', 'Your access has been denied.', NULL.  Immediately upon inserting the row, that IP address is blocked.  I could also block certain UserAgents (actually this was the original point of this HttpModule--bots these days have little respect for the robots.txt file).  I could also block requests that were from a different web site.  This would allow me to stop people from leaching images off my web site for use on their own.  With a simple HttpModule I was able to do all this in about an hour.  By the way, one record I was tempted to create was the following: 'deny', 'UserAgent', 'MSIE', NULL, 'http://www.getfirefox.com/'.  But I didn't :)

Now when would you use an HttpModule versus an HttpHandler?  Well, just think about what the difference is.  An HttpHandler handles a specific address pattern for a specific set of HTTP verbs, while every request in an application goes through an HttpModule.  So, if you wanted to have an image creator at /ImageCreator.imgx, then you need to register .imgx to IIS and then register your image creation HttpHandler in your web.config to handle that address (in case you forgot, web browsers care about the Content-Type, not the file extension.  In this example, your HttpHandler would set the Content-Type as 'image/png' or whatever your image type is.  That's how a web browser will know what to do with a file.  It has nothing to do with the file extensions; that's just for IIS.)  On the other hand, if you wanted to block all traffic from a specific web site, then you would create an HttpModule, becayse HttpModules handle all traffic on an application.  So, if you just remember this fundamental difference in purpose between the two, then shouldn't have my problems in the future.

Coders and Professional Programmers



I have to say it: there is a severe lack of skill in the technology world today, even among senior-level developers.  Perhaps I just have too high of standards, but when I see a person working in technology, I kind of expect them to have the requisite skill set for the job.  It always amazes me when I see a developer, even a senior-level developer, who doesn't know the basics of their own system (i.e. an ASP.NET developer who doesn't understand CSS positioning or a .NET developer who doesn't understand the framework design guidelines).  They may have degrees and have years of experience, but they have no actual skill.  It's always concerned me a bit that people have so little skill, but I wasn't able to put the problem into words until recent.  Well, that's not completely true.  An old friend of mine put it into words years ago, but it wasn't until this week that I was reminded of my own story.

Last week I was in a bookstore looking at a few design patterns books and a "1960s NASA engineer" type of guy in a white shirt and tie came up next to me, dressed in extremely casual blue jeans and a black shirt, looking at similar books.  I noticed he picked up a rather lame design patterns book, so I took it upon myself to hand him the GoF book saying "This one is the classic".  He thanked me and started to flip through it.  A minute later I realized that I couldn't resist asking: "So, what exactly are you looking for?"  He mentioned he was looking for a book demonstrating a state machine.  I grabbed another book, flipped the pages a bit and handed it to him saying "page 486".  His response was "Wow, thanks… so, where did you go to school?"  I have to admit that I've gotten many questions in bookstores, but I've never been asked that one FIRST.  The way he asked the question wasn't so much out of sincere curiosity, but more out of arrogance.  It felt like wanted to compare his degrees to my own.  I simply replied "School?  What?  You're looking at it…", pointing to the wall of computer books.  He immediately shut up and stepped away.  I'm not sure if that qualified me as a leper or if I just castrated the man's sense of academic accomplishment, but, regardless, that conversation was over.  However, a few moments later I found a book I was looking for and said "AHA! This will make them think!"  The same man curiously asked "What do you mean?"  I explained that I was looking for a book to recommend to developers to help then get a clue about software architecture.  The man gave the look of familiar with my situation and said something I haven't thought about in years: "Oh yeah… I know exactly what you mean.  Some people just don't get the difference between a coder and a professional."  At that point I had my flash back to a time of my life almost 6 years earlier… back when I was a coder.  It was a lifetime ago and I had all but repressed until recently.

The year was 2001 and I was a PHP programmer, Linux hacker and Math major at Kansas State University.  My idea of programming was looking at the PHP documentation, reading the PHP documentation comments and copy/pasting until my application was built.  I figured I knew what I was doing because I had already been in the field for 5 years; I was only now going back to school after a 3 year academic hiatus.  I would mix PHP, HTML, JavaScript, and tiny bits of CSS all in the same page in an absolutely unreadable pile of slop, "but it worked".  A friend of mine from high school, who by this time was a Microsoft employee, looked at what I was doing and mentioned to me in his usual blunt style: "Dude, that's not programming, that's slop coding.  You don't even have a data access layer, do you?"  Completely ignorant of the first clue of what he was talking about I said "Well, sure I do, PHP has a connector to mySQL.  I'm not accessing mySQL directly; I'm using the PHP API."  Thinking back on it I think he wanted to punch me in the face from that painfully ignorant comment."  Truth be told, I was not a professional programmer even though I had 5 years of crazy JavaScript development, 2 years of Ajax development, 2 years of ASP development, 2 years of SQL Server development, and 1 year of PHP development under my belt; I was only a coder.

After that, I spent a tremendous amount of time going back to the books and learning more about technology.  In high school I had some of the lowest grades in my classes because I spent my nights reading video game programming,  graphics programming, C/C++ programming, computer history, networking theory, Novell NetWare, and web development books.  In college, the pattern was being repeated in a the same familiar way.  I spend a ton of time studying all kinds of new technologies, one of which being XHTML/CSS design, all to the destruction of my meaningless academic career.  After finally breaking free from the tight bondage of academia I went to work for a few places as a PHP developer.  After one of two complete waste-of-time contractor positions I finally realized that it was time to cross over to .NET.  So, I spend an incredible amount of time studying .NET concepts, ASP.NET, the Framework, and C# technologies.  After a month I took and passed the 70-315 (ASP.NET) exam and the 70-229 SQL Design exam a week later.  From there I went to study the 70-320 (.NET components) and 70-228 material (SQL Administration).  Around that same time I realized that Mozilla finally released a product that didn't suck.  Not only did this product not suck, it was by far and away the most revolutionary piece of technology since the Internet itself: Mozilla Firefox 1.0.  With that I also started studying web standards much more deeply.  Being former Linux hacker, I wasn’t and still am not brained washed by the Microsoft extremist cult, so I've always been open to having the best technology regardless of vendor.

At this same time I realized that I really, really wanted to be a professional programmer and not a coder in any way.  So, I said goodbye to Visual Studio and took back my EditPlus to do all my .NET work.  I was not about to rely on Intellisense to do my work for me and already knew the danger of learning a new technology by error messages.  For the next year I deliberately did all my development without color syntax and without Intellisense.  I've never had any respect for "drag-n-drop" property developers, so I never used the designers anyhow, but now I wasn't even going to let Intellisense help me either.  If I needed to do something, guess what, I had to actually read the manual.  There would be no copy/paste slop coding and no hitting the forums every single time I hit the slightest bump.  If I had a problem, I would think about it and solve it using that technology, not simply a hack to throw some hack together.  I had enough years of wasting my time doing that.  Yes, at first, this got me into trouble, but I was determined to be a professional programmer at any cost and not a coder at all.  I wanted to internalize the systems as I had internalized driving my car.  After the initial slowdown (and the initial "being let go" from a project), I became much faster than all the other developers from the forced memorization of much of the documentation.  Whereas others had to look up how to use the Sqlconnection, SqlCommand, SqlDataAdapter, and DataSet combination, I was typing them out as if I were writing a sentence.  Around the same time I spent much time studying LLBLGen Pro, unit testing, object-oriented design (not to be confused with the entry-level concept of object-oriented programming I learned 10 years ago in C++), N-tier architecture, Modern JavaScript, and a year after that I took a block of time to study web services, MSMQ, COM+, service interop, and other communication mechanisms (most of which were later rolled up into WCF) all to the point of either complete or partial internalization.  In 2005 I was finally able to say that I am a professional programmer, not simply a coder.

As you can see from my story I know what it’s like to be a coder and I know the temptation to remain as a coder.  You think “your way” works and therefore you shouldn’t change it.  In fact, you probably hate other technologies, because their way isn’t "your way".  I can understand that too, but really it’s just a misunderstanding of that other technology.  My first ASP.NET application (a photo gallery) had absolutely no declarative code and was written with 100% Response.Write statements (I often tell people "make sure your first project in any technology is NOT a production one"; this is why).  I didn’t have the first clue what I was doing and, being a longtime classic web developer, I could not get that “magical” ASP.NET postback through my head.  Building that same application today would consist of an elegant ASP.NET custom control and two or three web forms.  I also understand what it’s like to say “…but this is how I do it in this other technology”, when in a reality that’s a completely meaningless statement.  Each technology has its own paradigms, naming schemes, guidelines, concepts, and languages.  Just because you are a Java rock star, doesn’t mean you will be able to do anything in .NET for at least 6 months.  The same goes for VB rock stars and PHP rock stars (as odd as it sounds, in my experience PHP developers have the hardest time learning .NET where as VB developers excel rather quickly-- this goes to show how hard it can be to un-link and old technology from your mind). I also know what it’s like to ask yourself “how can I do this?”  That’s what a coder asks where as a professional asks “How has this been built before in this technology; what is my precedence?”  In case you didn’t know, software development has been around for decades.  If you are running around trying to come up with a way to do something, you may be wasting your time as it’s probably been done before, the debates have probably already happened, people have probably already learned from their mistakes; you just have to accept what they've done for you, within limits, of course (i.e. C++ design patterns transfer to C#, but obviously not OOP style as .NET doesn’t allow multiple implementation inheritance).

So, if you find yourself in a place where most of your development is done doing things “your way” or the way “you have always done it” or if you ever ask “how can I do this”, maybe it’s time to break down and take some time out of your life to convert from being a coder to a professional.  It is definitely an investment, but with many great books out today (not all are so great), you could probably convert from being a coder to some level of professional programmer rather quickly (it took me a bit longer because I didn't have any role models to work under and I had no idea what the scope of the training was). There is an old computer science saying that goes something like this: "Anyone can write code that a computer can read, it takes a professional to write code a human can use."  We should all think about that and possibly post it on our walls.

To aide in the process of converting from a coder to a professional programmer, a few months ago I wrote up my requirements for a Senior-Level developer or Architect on my blog.  It should give you a shell outline for some of the technologies and topics you seriously need to have under your belt to be a professional.

Web Application Security Presentation



Today I found a really nice web application security presentation by Joe Walker.  Honestly, almost none of it is common sense and I would therefore encourage all web developers to check this out.  Also on the same page as the presentation are a number of very good AJAX security links like the XSS (Cross Site Scripting) cheat sheet.

BTW, this type of stuff is touched on in the Brainbench AJAX exam.

Links

Accelerated Language Learning (Timothy Ferris)



Many years ago I wrote a paper on accelerated learning and experience induction.  This paper explains how I induce weeks of experience in days, months of experience in weeks, and years of experience in months and how to dramatically learn new technologies with little to no investment.  I know people who have worked in a field for 4 years, but only have 6 months worth of skill (usually VB developers -seriously).  I also know people who have worked for 6 months, but have over 4 years of skill (usually Linux geeks; paradoxically, VB developers usually are quicker to learn .NET basics than PHP developers, though they usually switch places in more advanced studies.)  How can anyone expect to gain skill by doing the exact same job for 4 years (e.g. building database driven interfaces, cleaning data, writing reports)?  Obviously, calendar-years of experience is not directly related to skill-years of experience.  As it turns out, my learning techniques are not uncommon.

Today, author Timothy Ferris (Four Hour Work Week) posted a blog entry about how he learns languages in an incredibly short timeframe.  His post was fascinating to me for many reasons, one of them being that his first step is as follows: "Before you invest (or waste) hundreds and thousands of hours on a language, you should deconstruct it."  This is the same first step in my accelerated learning method.  Apparently I was on to something!  In his deconstruction method, he asks a few key questions and does some component and paradigm comparisons to give you some idea of the language scope and of its difficulty.  Based on what you learn from the deconstruction, you should have a good idea of what the language entails.

In my learning system, I refer to this deconstruction as "learning the shell", which is followed by "learning the foundations", then "learning the specifics" -- Shell, Foundations, Specifics -- my SFS (pronounced "sifs") method.  The method exploits Pareto's Law, allowing you to learn 20% of the technology at first to give you 80% of the return.  That's MUCH more than what most so-called "experts" have anyhow!  As it turns out, Timothy Ferris uses Pareto's Law in his language learning as well.  You can hear about this in his interview with my other role model, Scott Hanselman.

For more information on Timothy Ferris' other life-optimization work, check out his book The Four Hour Work Week and his blog.

Related Links

Prototype and Scriptaculous Book



Today I noticed the book "Prototype and script.aculo.us: You never knew JavaScript could do this!" and while you do not need a book to learn P&S, this book will definitely induce a good 6 months to a year of experience into your skill set.  The book is available on Amazon in print or on the book's website in PDF format.

If you only want to know the basics of P&S, then you'll be fine with looking over the Prototype documentation and script.aculo.us samples.  However, regardless of how deep you want to go, you should definitely check out the freely available source code for the book available on the book's website.

As always, let the tools do the work, but don't rely on them for everything.  It's critically important that you understand AJAX developer from a deep mechanical level before you start using JavaScript or AJAX frameworks.  If you aren't well-versed in JavaScript and AJAX development, then I highly recommend AdvancED DOM Scripting: Dynamic Web Design Techniques by Jeffery Sambell.

Related Links

10 Things Most Developers Didn't Know in 2007



To end 2007, I thought I would make a list of things which I found that most developers didn't know.  To make things more interesting, this list is actually a series of 10 mini-articles that I wrote today.  Since this article has several sub-articles, here's a table of contents to help you out (these aren't really in any order of importance):

#1  SQL Server supports powerful subqueries as anonymous sets.

Many developers don't take the time to seriously look at T-SQL or SQL Server internals.  As such, they miss many of SQL Server's more powerful features.  In January 2007, when co-worker saw he write the following query, he about fell out of his seat:

select MemberName, m.MemberId, count() from (select 
    distinct MemberId, 
    VisitUserAgent 
    from VisitSession 
    where MemberId is not null) a 
inner join Member m on a.MemberId = m.MemberId 
group by m.MemberId, MemberName, VisitUserAgent 
having count() > 1 
order by count(*) desc 

For starters, the guy didn't know you could do a filter after a group by, but that's not my point.  He had no idea that SQL Server (2000) allows you to use subqueries or use subqueries as anonymous sets.  As you can see, you can select from the list as well as use it in a join.  This tidbit alone should toss many painfully slow cursor-based stored procedures into the trash.  It's a simple SQL feature, but it's a powerful one.

#2  Firefox has an operating-system style console for web application debugging.

It's incredibly hard to find an ASP.NET web developer who knows this one.  It's a feature that knocks people right off their seats.  Instead of throwing alerts all over your AJAX applications, you can use the Firefox console and the dump( ) function.  Did I mention this has been a native feature since Firefox 1.0?

Step 1 (start Firefox with -console switch)

Step 2 (add the boolean key 'browser.dom.window.dump' to the Firefox configuration an set it to true)

Then simply call dump( ), instead of alert( ) and you're done. Your output will go to the Firefox console window (which looks almost exactly like a cmd window).

With this technique you can entirely avoid any possibility of having an infinite loops of alerts.  Personally, I like to track all the output of my web applications.  This comes in very handy when I'm using event capturing or need to watch the progressive state of my application.  When I do this, I also like to write an output identifier to each data dump.  Here's a sample of what I usually use for debugging:

var Configuration = { 
    Debug: false
}; 


var Debug = { 
    counter: 0, 
    write: function(text) { 
        if(Configuration && Configuration.Debug) { 
            dump(text); 
        } 
    }, 
    writeLine: function(text) { 
        if(Configuration && Configuration.Debug) { 
            Debug.counter++;        
            dump(Debug.counter + ':'+ text + '\n'); 
        } 
    } 
};

Here's some sample output using the Debug.writeLine( ) abstraction:

Leaves alert( ) in the dust, doesn't it? You can actually learn more about this technique and others from my Firefox for ASP.NET Web Developer video series found on my blog.  These topics are crucial to your understanding of modern web development.

#3  JavaScript has natively handled loosely-coupled multi-cast events for years.

This isn't something just for the Firefox, Opera, Safari world.  Even IE6 has native support for this feature. I'm not sure why this is, but in September 2007 when I was designing the AJAX exam for Brainbench, not a single one of the reviewers knew that JavaScript natively supported loosely-coupled multi-cast events.  I actually comments from almost all of the reviewers telling me that I should "leave server-side questions out of the exam".

JavaScript loosely-coupled multi-cast events are one of the most important core features of AJAX applications. They allow you to quickly and efficiently attach multiple event handlers to the XHTML same element. This becomes critically important when you are with multiple AJAX components, each of which that want to have an event handler attached to the load event of the window object.

I wrote an article about this in September 2007, so I'm not going to go into any kind of details here.  You my also opt to view this file from my SolutionTemplate, which supplements that blog entry.

#4  Not all image formats are created equal.

A few months ago, I came in as lead architect about half way through a project.  After having a few people fired for absolute incompetence, I did find a few people (PHP guys) who were ready, willing, and actually able to learn ASP.NET.  Everything was going well until the designer came back with his new theme and my associate whom I was training implemented it.  Everyone thought the project was going fine until I stepped in the room.  It didn't take but 10 seconds for a red flag to go up.  Just looking at the web site I could tell that this theme implementation was a disaster.  I noticed that there were signs of JPEG compression all over every single one of the images.  However, being a scientist and part-engineer I knew that measurement was a major key to success.  So, I whipped out Firebug, hit refresh and felt my jaw drop.  The landing page was 1.5MB.  Ouch.

You absolutely can not use one single image format for ever image on your web site, especially not the deadly JPEG format which does little more than destroy your images.  There are rules which web developers must need to follow or else a project is doomed to failure.  First off, you need to be using PNG24s for the all important images, while comparing their file sizes and quality with PNG8 compression.  Using Adobe Photoshop's Save For Web feature is very helpful for this.  If the image is a photo or something with many "real life" colors and shades, perhaps you want to do a size and quality comparison against a JPEG version as well.  If you absolutely need to have transparent images for IE6, then you need to take extreme care and either make special PNG versions for each background or, if you don't care too much about quality and the image is small with very few colors, use a GIF with transparencies.  The same goes for Firefox and printing.  Firefox (as of 2.0) does not print transparent PNG images.  So, if you want to support printing in Firefox, then you need to either make special PNG images for each background or make low-quality GIF images.

Needless to say, the designers theme had to go under severe reconstruction.  Not just because of the image sizes, but because he felt the need to design special input box, textarea, and button controls.  His design would have worked well for a WPF application, but this is the web (... but don't even get me started on the fact that his design for a wide screen monitor at over 1300x800.  The design was useless anyhow!)  The next project I ran as lead architect went much smoother.  Because it was extremely AJAX intensive, everything was minimized to the absolute core.  Each page had the minimal default.css plus it's own CSS sheet and only included the JavaScript it needed.  The web site landing page included barely anything and even had it's own extremely stripped down version of the JavaScript files.  For this project, I went from 350K in development to 80k in production.

#5  Custom server controls are not esoteric, complicated, or take too long to create.

  This seems to be a very common misconception amongst ASP.NET developers.  The reality, however, is that creating server controls is often a very trivial task.  Yet, many developers will use a GridView or other canned control for everything.  The GridView is awesome for basic tabular in a very simple, data-driven applications, but I can rarely use it.  On the other hand, I love the repeater and rely on it for almost everything.  Actually, it and the Literal are my two favorite controls.  I have to rely on these two controls to ensure that my AJAX applications are extremely optimized.  One of the beautiful things about .NET is that every ASP.NET control is simply a .NET class, which means that you can programmatically reuse them, inherit from them, and override their internals.  Thus, allowing us to create some powerful and elegant custom server controls.

On the same project with the overly sizes image files, we had an interesting meeting about how to show a media play list on a web page.  There was all kinds of talk about using Flash to create a media play list.  The conversation was quickly giving me an allergic reaction.  So, after hearing all kinds of absolutely insane quotes of time for creating a Flash play list, I decided to take matters in to my own hands.  Two hours later I handed the client a complete play list from A to Z.  To be clear, I had built this one something I had already had, but the grand total of time was them about 3 hours.  It's amazing what you can do when you understand the .NET framework design guidelines and aren't afraid to follow best-practices.

Here is how you would use a similar control:

<%@ Register Assembly="Jampad.Web" Namespace="Jampad.Web.Controls" TagPrefix="j" %>


<j:Media id="media01" runat="server" />

In your code behind, you would have something that looked like this:

media01.DataSource = MediaAdapter.GetContent(this.MemberGuid);

Upon loading the page, the data was bound and the output was a perfect XHTML structure that could them be customized in any number of ways using the power of CSS.  How do you make something like this happen?  It's simple, here is a similar control (Media.cs) placed in a class library (WebControls.csproj):

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;


namespace Jampad.Web.Controls
{
    [ToolboxData("<{0}:Media runat=\"server\"></{0}:Media>")]
    public class Media : CompositeControl
    {
        private Repeater repeater;
    <span style="color: blue">public </span>Media( ) {
    }


    <span style="color: blue">private </span><span style="color: #2b91af">Object </span>dataSource;


    <span style="color: blue">public </span><span style="color: #2b91af">Object </span>DataSource {
        <span style="color: blue">get </span>{ <span style="color: blue">return </span>dataSource; }
        <span style="color: blue">set </span>{ dataSource = <span style="color: blue">value</span>; }
    }


    <span style="color: blue">protected override void </span>CreateChildControls( ) {
        <span style="color: #2b91af">HtmlGenericControl </span>div = <span style="color: blue">new </span><span style="color: #2b91af">HtmlGenericControl</span>(<span style="color: #a31515">"div"</span>);
        div.Attributes.Add(<span style="color: #a31515">"class"</span>, <span style="color: #a31515">"media-list"</span>);


        <span style="color: blue">try </span>{
            repeater = <span style="color: blue">new </span><span style="color: #2b91af">Repeater</span>( );
            repeater.DataSource = <span style="color: blue">this</span>.DataSource;
            repeater.ItemTemplate = <span style="color: blue">new </span>MediaTemplate(<span style="color: #2b91af">ListItemType</span>.Item);
            repeater.HeaderTemplate = <span style="color: blue">new </span>MediaTemplate(<span style="color: #2b91af">ListItemType</span>.Header);
            repeater.FooterTemplate = <span style="color: blue">new </span>MediaTemplate(<span style="color: #2b91af">ListItemType</span>.Footer);
            div.Controls.Add(repeater);
            repeater.DataBind( );
        }
        <span style="color: blue">catch </span>(<span style="color: #2b91af">Exception </span>ex) {
            <span style="color: #2b91af">Literal </span>error = <span style="color: blue">new </span><span style="color: #2b91af">Literal</span>( );
            error.Text = <span style="color: #a31515">"&lt;span class=\"error-message\"&gt;" </span>+ ex.Message + <span style="color: #a31515">"&lt;/a&gt;"</span>;
            div.Controls.Add(error);
        }


        <span style="color: blue">this</span>.Controls.Add(div);
        <span style="color: blue">base</span>.CreateChildControls( );
    }
}
}

Notice the use of the repeater control.  This is the same control we use in ASP.NET as <asp:Repeater />.  Since this is .NET, we can use it programmatically to create our own powerful controls.  Also notice the various templates that are being set on the Repeater.  These are the same templates you would set declaratively in an ASPX page.  In this case, I'm programmatically assigning to these templates an instance of MediaTemplate (in MediaTemplate.cs).  This MediaTemplate.cs is just another file thrown in a class library, in our case the same WebControls.csproj, though since it's just a class, it could be in a different assembly and namespace altogether. Here's what the MediaTemplate.cs looks like:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;


namespace Jampad.Web.Controls
{
    internal class MediaTemplate : ITemplate
   {
        ListItemType type = new ListItemType( );
    <span style="color: blue">public </span>MediaTemplate(<span style="color: #2b91af">ListItemType </span>type) {
        <span style="color: blue">this</span>.type = type;
    }


    <span style="color: blue">public void </span>InstantiateIn(<span style="color: #2b91af">Control </span>container) {
        <span style="color: #2b91af">Literal </span>lit = <span style="color: blue">new </span><span style="color: #2b91af">Literal</span>( );
        <span style="color: blue">switch</span>(type) {
            <span style="color: blue">case </span><span style="color: #2b91af">ListItemType</span>.Header:
                <span style="color: blue">break</span>;


            <span style="color: blue">case </span><span style="color: #2b91af">ListItemType</span>.Item:
                lit.DataBinding += new EventHandler(<span style="color: blue">delegate</span>(<span style="color: #2b91af">Object </span>sender, System.<span style="color: #2b91af">EventArgs </span>ea) {
                    <span style="color: #2b91af">Literal </span>literal = (<span style="color: #2b91af">Literal</span>)sender;
                    <span style="color: #2b91af">RepeaterItem </span>item = (<span style="color: #2b91af">RepeaterItem</span>)literal.NamingContainer;
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"&lt;div class=\"media-item\"&gt;\n"</span>);
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"  &lt;div class=\"media-item-inner\"&gt;\n"</span>);
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"    &lt;a href=\"{0}\"&gt;&lt;img src=\"{1}\" alt=\"Media\" class=\"media-thumb\" /&gt;&lt;/a&gt;\n"</span>, (<span style="color: #2b91af">String</span>)<span style="color: #2b91af">DataBinder</span>.Eval(item.DataItem, <span style="color: #a31515">"mediaPath"</span>), (<span style="color: #2b91af">String</span>)<span style="color: #2b91af">DataBinder</span>.Eval(item.DataItem, <span style="color: #a31515">"thumbPath"</span>));
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"  &lt;/div&gt;\n"</span>);
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"  &lt;div class=\"media-item-bottom\"&gt;&lt;/div&gt;\n"</span>);
                    literal.Text += <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"&lt;/div&gt;\n\n"</span>);
                });
                <span style="color: blue">break</span>;


            <span style="color: blue">case </span><span style="color: #2b91af">ListItemType</span>.AlternatingItem:
                <span style="color: blue">break</span>;


            <span style="color: blue">case </span><span style="color: #2b91af">ListItemType</span>.Footer:
                <span style="color: blue">break</span>;
        }
        container.Controls.Add(lit);
    }
}
}


Simply compile those to together and you're set.  You can even embed (hopefully tiny) images in your project to make things even more seamless.  Using this simple pattern, I've created all kinds of things.  You can see a real example of this, including image embedding, in my SQL Feed Framework (formerly known as Data Feed Framework).  It's InfoBlock controls follow this same pattern.  For much better examples, whip out reflector and start digging around the System.Web namespaces.

It's actually rather astonishing to learn of some of the attituted some developers have about custom controls. When I was one of the editors for an ASP.NET 2.0 exam last year, I noticed one of the questions ask which type of control was "harder" to create. The answers were something like "User Control", "Custom Control", and a few others. They were looking for the answer "Custom Control". Since "harder" is not only a relative term, but also a subjective and an abstract one, the question had no actual meaning. Custom controls aren't "harder" than user controls.

#6  Most developers I worked with in 2007 had never heard of an O/R mapper.

Why do most developers still absolutely insist on wasting their time writing a chain of SqlConnection, SqlCommand, and SqlDataAdapter?  Perhaps it's just an addiction to being busy instead of actually being productive that causes this.  I don't know.  I would, however, expect these developers have to have some curiosity that there may be an easier way.  ADO.NET is awesome stuff and it is the foundation for all .NET O/R mappers, but if I'm not throwing around 1,000,000 records at a time with SqlBulkCopy, I'm not interested in working with ADO.NET directly.  We need to have a system that allows us to get what we want instead of forcing us to screw about with low-level mechanics.  It's no secret that I'm a huge supporter of Frans Bouma's work with LLBLGen Pro and I also use LINQ in most of my .NET 3.5 applications.  For a corporate .NET 2.0 project, there's absolutely no excuse to not pay the $300 for LLBLGen Pro.  Managers!  Open the wallets!  It will save you money.

However, it's not always about the money.  Even if the developers knew about O/R mapping, and the company isn't from in a poverty-stricken 3rd world country, sometimes extreme pride, lack of personal integrity, and political alignment can destroy any chance of being productive.  A long time ago I worked at a company where I thought I would be productive.  Five or so weeks into the design phase of the project, we received a politically-focused project manager as big brother.  He was absolutely against the use of any modern technology and despised the idea of an O/R mapper.  He instead told us that we were to write a stored procedure for every possible piece of interaction that would happen.  He also wanted us to use Microsoft's data application block to access the stored procedures.  At one point he said that this was their O/R mapper, showing that he had no idea what an O/R mapper was.

A few days after his reign had started, I took an hour or so to write up a 12 page review document covering various aspects of LLBLGen Pro and how they would work on the project.  I thought it was a very convincing document.  In fact, one guy looked at it and was convinced that I took it from the LLBLGen web site.  The project manager, however, was beginning to be annoyed (this is not uncommon with me and old-school project managers!)  The project manager decided to call together a panel of his "best" offshore developers and put me in what basically amounted to be a doctoral defense.  Prior to the meeting I sent out my "dissertation" and asked everyone to read it before they arrived at the meeting so that they would be prepared for the discussion.  When it was time for the meeting, I was told to sit at one side of a large meeting table and the project manager and his team sat at the other.  Then the disaster began.  First off, not one single person on that team had read my document.  Secondly, for the next 45 minutes they asked me basic questions that the document would have answered.  Even after they admitted that I had answered all of their concerns to their satisfaction and being told by their team that LLBLGen Pro was obviously a very productive tool, they reached the conclusion that they still weren't going to use it.  It was a waste of my time and I still want those 45 minutes of my life back.

What was really interesting about my defense was the developer's code.  In the meeting, the developers had showed me their [virtually unreadable, anti-.NET framework design guidelines, inefficient, insecure] .NET project code and I was shocked to see how much time they wasted on writing the same stuff over and over and over again.  When they showed me their stored procedures, I about passed out.  It's a wonder how any of their systems run.  They were overridden with crazy dynamic SQL and cursors.  They even had most of the business logic in the data access tier.  The concept of N-tier architecture was not something that they understood at all.  I think that's the point where I gave up on my defense.  If a developer doesn't even understand the critical need for N-layer and N-tier architecture, there's just no way they will be able to understand the need for an O/R mapper.  It's actually one of the fastest way to find a coder hiding amongst professionals.  Their SQL/ADO.NET code was also obviously not strongly-typed.  This was one of the core points of an O/R mapper and these developers could not understand that.  They could not see the benefit of having an entity called Person in place of the string "Persno" (deliberate misspelling).

This project didn't really take off at all, but for what parts I was involved, I used the next best thing to an O/R mapper: a strongly-typed data-set.  Read this carefully: there is no shame in using a strongly-typed data set if you don't have an O/R mapper.  They are no where near as powerful, but they are often good enough to efficiently build your prototypes so that the presentation layer can be built   You can replace the data access components later.

The training of developers in the use of LLBLGen Pro and LINQ O/R mapping was one of the main reasons I publicly released both my Minima Blog Engine and my Minima 3.5 Blog Engine source code to the public in 2007.  You are free to use these examples in your own training as you see fit. 

For more information and for some example of using an O/R mapper, please some of my resources below:

#7  You don't need to use SOAP for everything.

This is one of the reasons I wrote my XmlHttp Service Interop series in March and May 2007.  Sometimes straight up HTTP calls are good enough.  They are quick, simple, and light-weight.  If you want more structure, you can simply use XML serialization to customize the smallest possible data format you can think of.  No SOAP envelope required.

Here are the parts to my series:

Also keep in mind that you don't need to keep JSON to JavaScript.  It's a beautiful format that could easily be an amazing structured replacement for flat CSV files.  RESTful interfaces using GET or POST with HTTP headers are also a great way to communication using very little bandwidth.  My AJAX applications rely heavily on these techniques, but I've also used them for some behind the scenes work as well.

One great example of how you can use RESTful services is by looking at the interface of the ESV Bible Web Service V2. In November 2007, I wrote a .NET 3.5-based framework to abstract the REST calls from the developer. By looking at my freely available source code, you can see how I'm interacting with the very light-weight REST service.

#8  A poor implementation of even the most beautiful database model can lead to a disast

Developers and Web Developers



(This is a sequel to my Coders and Professional Programmers article)

I'm fairly sure the year was 2001. It was before I did my transition from coder to professional, but it was long after I became a real web developer (1994).  This was the year that the web became severely corrupted by an influx of thousands of MFC/VB developers thinking they were web developers simply because they knew how to drag-n-drop a control onto a canvas and make something appear in a web browser. The influx was, of course, due to the release of ASP.NET. These people were not web developers and that same coder-mill continually throws out unprofessional after unprofessional today.  This was the year I got so upset with the pragmatic, unprofessional web developers running around taking my work that I retired for 3 years to go back to college.

So, what is a web developer?  Surely is at least one definition per person in the entire industry, but I must say that, at root, it's a person who understands and can proficiently interaction with web technologies.  What web technologies?  Today, these include, at a minimum, semantic XHTML, CSS, and Modern JavaScript.  In a sense, you could easily mark these as the pillars of web programming.  Without academic and hands-on knowledge of these technologies, there is no web devolvement (yes, both are required-- and despite what the pragmatists think, the former is critical). Furthermore, this technology list changes over time.  If I were to retire today, I have no right to come back in 5 years claiming to be a web developers.  To be a web developer at that time, I need to learn a new X, Y, and Z in including their guidelines and best practices.  You must keep up or be left behind.

Having said that, PHP, JSP, and ASP.NET developers often inappropriately call themselves web developers.  Not all PHP, JSP, or ASP.NET developers are like this, especially PHP developers! Respect, respect!  In any case, I can kind of see the confusion here, but even still, a quick realization of what these technologies are should have killed any thoughts of this a long time ago.  These people work with server-side technologies, not web technologies.  The same CGI model used 15 years ago is the same model today.  The only thing these people are doing is creating code that runs on a server and shipping the output.  Period.  That's not web development; this is the same work you would do if you were to build an Excel report.  It’s just work behind the scenes that may or may not touch a web browser.  Even then, just because it hit a web browser, doesn’t mean its web development.  There’s no client-side technologies involved at all. Without deeply interacting with client-side technologies, there is no web development.  In fact, the inanimate object known as a web server is more of a web development than server-side-only people.

Web development begins at the point when you begin to ponder the technologies and implementation from the perspective of the client-side.  I'm sure most people won't believe me when I say this, but I did web development for my 4 years of high school before I even knew that you could use server-side software to dynamically create pages.  Everything I did was in pure JavaScript and fancy frame manipulation.  This was web development.  I didn't need CGI or Perl.  PHP, JSP, and ASP.NET simply sends out a stream and it just so happens that a web browser may be the one making the request.  The output may be for a web browser, but that in absolutely no way makes it web development.  That's like going to a foreign country and using a translator device and saying because you have that device, you speak the language.  You in absolutely no way speak the language!  Worst, some people will defend, virtually to the death, the idea that they do speak the language simply because they know a few words to "fix" the translation!  We see this in server-side-only developers who, because they know a few HTML tags, think they know the technologies.

Most of the time, however, server-side-only developers really think they are web developers. So, this simple and obvious explanation won't do.  Therefore, we are forced to make a distinction between web 1.0 and web 2.0 developers.  We often think of web 2.0 as being quick, dynamic, and smooth client-side dynamics.  This is from a marketing perspective, but it's hardly a definition that satisfies the computer scientist.  The distinction I use is actually a bit more straightforward: web 2.0 development is development from the client-side perspective.  This definition actually reminds me of the definition of a series I learned in my Real Analysis class in college: a mapping from N to R.  How in the WORLD is that a series!? Isn't a series a set of entities or something?  Well, somehow it's a mapping from N to R (I've yet to hear another professor give this same definition, but the point is that "formal definitions" in mathematics rarely look like their application in reality).

When I talk about web 2.0 to a colleague or a client I'm talking about web-specific design and implementation from the perspective of the client. From this perspective calls are made to various services for interaction with outside data.  In other words, web 2.0 is a client-service model for the web.  In this sense, what is web 1.0?  Just the opposite: development from the server-side perspective.  This is ASP.NET development, for example.  When you are working with ASP.NET, you are working from the perspective of the server and you send data out.  In this model, you have a logically central system with entities accessing it. In reality, this isn’t web development—it’s development of something that may or may not do web development for you. Web 1.0 is a server-client model for the web (notice the word server, instead of service—as seen in the web 2.0 model)  If you are a deep Microsoft developer you recognize the web 2.0 paradigm: WPF/WCF allows you to easy create a client-service model bypassing the client-server model all together.  You create your client interfaces in WPF and access WCF servers as you need them.

In this perspective, what does this mean in terms of the actual technologies?  Well, almost all my web applications are done using the web 2.0 model.  That is, all my programming is done from the perspective of being inside the web browser.  I'll directly modify the DOM and access data via AJAX calls as required.  Some of my applications are pure-AJAX. That is, not single postback in the entire system (like meebo.com-- meebo is a prime example of a web 2.0; everything is from the perspective of the client with communication via AJAX services.)  In fact, my controls are very Google-ish.  Google is also deep into this model.  See their AdSense, AdWords, or Analytics controls; insert a declarative script and it does the rest from the perspective of the client.  As you can see here, you don't even need the XHR object for web 2.0!

What does ASP.NET AJAX bring?  In this model, ASP.NET AJAX is as web 1.0 technology that gives you the dynamics of web 2.0.  This was actual the entire point behind creating it.  Web 1.0 developers (who are often not web developers at all!) can use their existing server-side perspective and paradigms to implement dynamics on the remote system (in a web 1.0 model the client is the remote entity-- whereas in web 2.0 the services are remote).  ASP.NET AJAX very much allows for a web 2.0 model, but that's not how it's primarily marketed.  As a side note, I should mention that, this model for explaining web 1.0 and 2.0 is only a logical representation and therefore can not be right nor can it be wrong.  The fancy marketing representation kind of works too, but it's often too abstract to have real meaning.

Personally, I think the web 1.0 model of development is counterproductive and encourages sloppy priorities.  The user experience is the point of the system. Without that, the entire point of the web site is dead.  One of my problems with ASP.NET AJAX is how it's marketed.  The server-perspective model of development encourages development that seems backwards.  Furthermore, because of this, the aforementioned so-called "web developers" continue to spread their disease of pragmatism all over the world further aiding in the disintegration of quality.  As I've originally stated, most of these people don't understand even the basics of semantic XHTML, which is the single most fundamental aspect of web development, which can be seen in their use of div-soup or <br/> mania.  These people may be awesome server-side professionals putting my enterprise architecture skills to absolute shame and run circles around me in just about any algorithm or design pattern implementation, but they are only coders when it comes to the web.

After years and years of dealing with people like this, I've come to notice a few signs of web 1.0 coders:

  • If someone says "Firefox?  How's that better than IE?", it goes without saying that this person not only hasn't the first clue about web development, they don't even understand the tool which represents the core purpose of web development: the web browser.  People like this are almost always helpless.  You could try to explain the true power of CSS, the fact that SVG, HTML5, and Canvases are in every web browser except IE, or talk about how Firefox has the architecture of an operating system with its console, it's own registry (about:config), as well as the ability to install apps (extensions), but you're probably only going to get the same pragmatic blank stare of a coder. Fortunately, I haven’t heard say this in at least 3 years.
  • If someone says "I know CSS, here…" and shows you how they used font-size, color, and font-weight on a few elements contained in a table embedded in a table embedded in yet another table, then you have your work cut out for you, because you met a person who thinks HTML is the latest cool technology on the block and hasn't the first clue what CSS really means.  As I've stated in my article "CSS Architecture", CSS is not just a styling technology.  Furthermore, we web 2.0 developers realize that CSS is to be used in harmony with semantic XHTML and therefore understand the dangers of using a table.  These people obviously don't.  Of course, the minute their boss asks for mobile support, they come running to you because they now realize "DOH! Tables are too wide! AHH! Tables make the page size too big!" They will have to learn their lesson eventually.
  • If someone says "I know JavaScript, here… " and they show you a validation function, then you need to explain to them that JavaScript isn't merely a scripting language, but is rather a very powerful object-oriented/functional programming language which often puts strongly-typed languages to shame.  It includes closures, namespaces, an extremely rich object system, object-oriented access levels, multi cast events, and a boat load of core JavaScript objects.  Yet web 1.0 developers haven't the first clue. This problem isn’t nearly as bad as it used to be, though. MSDN magazine devoted some time to the topic in the May 2007 issue and the number of JavaScript experts in the Microsoft community is growing very rapidly.
  • If someone says "Hmm… I don't see the control you are talking about in my toolbox", then you know you are dealing with a coder.  Not only that, you're probably dealing with a person who has never, ever learned what semantic development even is.  Typically people like this will use the dead concept of a WYSIWYG designer to drag-n-drop controls and set properties with their mouse.  Clearly, these people focus more on how something seems to look at the moment, not how the page is actually built.  Pragmatists.  Personally, I’ve never designer support into anything, ever. If you can’t program it, don’t develop it! I personally find it extremely unprofessional to even allow designer-support. The target audience typically has absolutely no concept of the difference between a semantic <h1></h1> and a pragmatic <div id="myHeader"></div>.  Not only will their code cause problems down the road, your code will never integrate with it, which, of course, means you will be rewriting everything. Anyone who understands the importance of semantic XHTML understands the sheer severity of this problem.  You will break a page's structure by relying on a designer.  A designer should only be used by a professional who knows how to fix it's flaws.  Since only a professional would be able to fix the flaws, it follows that only a professional should do web development.  Duh?  For more information on semantic XHTML, see any modern web 2.0 book or my mini-article here (a quick note-- when I was formatting this post in WLW, every one of my list items would start a new list-- if I didn't understand semantic XHTML, I would have been completely stuck [also notice I'm using the semantic term "list item" not the syntactical term "<li />"-- focus on what things ARE, not what they DO-- try focusing on what something IS using a WYDIWYG designer!])

I know I've written about this topic before, but it's is just such a critically important topic.  Just because someone does something, that doesn't mean they are in that profession.  I change my own oil and change my tires, but this doesn't make me a mechanic.  A few months ago I was talking to a guy who actually said that he doesn't care about what he produces, because "it's just a job".  Just a job!?  Why don't you just get another one!  These people need to stop masquerading as web developers, stop undercutting my professional company by offering $3.75/hour unprofessional "development", start upping their own standards and start showing a little respect to us that were here first.  To a lot of us professionals this isn’t just a “job”; it’s actually become part of us! Unfortunately, I've learned years ago that people don't change.  Not for their marriage, not for their family, and especially not for their careers.  It's hopeless.  Moving on.