comments edit

Subtext Logo The Subtext team is currently furiously working to prepare the Subtext 1.9 Daedelus release for your blogging enjoyment. Subtext 1.9 will run on ASP.NET 2.0 in Medium trust and contain a few new goodies, though those goodies have been kept to a minimum as the goal was to create a straight port to ASP.NET 2.0. The release date has not been set since my day job and another minor side project has been keeping me busy. My hope is to release somewhere around the first or second week of August.

In the meanwhile, we found the need to respond to some minor bugs in the last release. Thus today we release Subtext 1.5.2 which still runs on ASP.NET 1.1. This is a very minor release, so probably not necessary unless you are affected by one of the bugs listed below.

Probably the most annoying bug was one that caused problems when attempting to create a post using the web-based admin tool. This was due to a misconfiguration on my part of our ReverseDOS configuration file.

It was this misconfiguration that inspired my “stroke of pure genius” suggestion to the creator of ReverseDOS (though methinks he is a bit strong on the compliment). ;)

Here are the release notes.

Version 1.5.2 - Bugfix Release
- BUG:  [1492127] Fixed a constraint on the 
                  subtext_Config.BlogGroup in the import  
                  script.
- BUG:  [1524172] The User Name Is Being Saved as the Title
- BUG:  [1502661] Change ReverseDOS.config - turn on  
                  isRegex="true" flag for
            Trusted Addresses.
- BUG:  [1514406] Fixed bug in which permissions were not 
                  applied to [Subtext_GetEntry_PreviousNext] stored 
                  procedure.

Download it here.

The number of code contributions to Subtext has been increasing lately which is wonderful! Thanks for sticking with us and we really appreciate the contributions. Keep it up!

code, blogging comments edit

Dave Burke makes the interesting claim that Community Server is an open source application. Whether this is true or not of course depends on your definition of the term Open Source. Here is Dave’s definition.

To talk about Community Server and Open Source we should start with a baseline definition of an Open Source application: All of the source code is available. For free.

But is that all there is to Open Source, access to the code? Is mere access to the code the fairy dust that has inspired such a passionate movement in the software community?

Certainly the term Open Source has had a history of ambiguity, so that definition might contain some validity. But I do not think that is the commonly agreed upon minimal criteria for something to be considered Open Source.

Open source isn’t just about whether the source code is available, it is all about the license to the source code.

My favorite definition of open source software is The Open Source Definition (or OSD for short) on the Open Source Initiative website.

The definition starts with the following introduction and then lists serveral criteria for open source software.

Open source doesn’t just mean access to the source code. The distribution terms of open-source software must comply with the following criteria:

The first criteria listed is Free Redistribution which states…

The license shall not restrict any party from selling or giving away the software as a component of an aggregate software distribution containing programs from several different sources. The license shall not require a royalty or other fee for such sale.

Contrast this to the Community Server license agreement 2.0 which states…

3g. Distribution. You may not distribute this product, or any portion thereof, or any derived work thereof, to anyone outside your organization. You are not allowed to combine or distribute the Software with other software that is licensed under terms that seek to require that the Software (or any intellectual propertyin it) be provided in source code form, licensed to others to allow the creation or distribution of derivative works, or distributed without charge.

For many people, the terms of the Community Server license might not be a problem. They are not terribly restrictive. If you plan to use Community Server under the community license your only requirement is to display the Powered By Community Server logo on every page of the site that uses Community Server.

However for many others, these terms are restrictive enough. For example, suppose you don’t like the way development is progressing on Community Server. You cannot fork the code base and start a new project based on the source code. Although a fork may seem like a bad thing, Karl Fogel points out in his book Producing Open Source Software - How to Run a Successful Free Software Project that the threat of a fork is what keeps the leader(s) of an open source project from being tyrannical. It is this threat of a fork that motivates and requires open source projects to be well run.

Not every open source license is created equal as I pointed out in my guide to Open Source Software Licensing. For example, under the BSD license in which Subtext is licensed, you and I are free to create a commercial derivative version of Subtext and keep your changes to the code closed source and proprietary. That’s right. If you wanted to (and had the ability to), you could package up the Subtext source code in its entirety and start selling it as a packaged product.

Note that you can’t turn around and claim that you have the copyright to the Subtext code. You would only have copyright to your changes to the code. Pretty much the only restriction is that the original license must be retained with with the code, but it does not have to be publicly visible in your site (such as in an about box).

In contrast, with a GPL Licensed project, you could start selling it, but you couldn’t keep your changes closed source without violating the terms of the license.

In the end, I think we need to agree on a term for unique products such as Community Server in which the source code is freely available, but does not fit the definition of an open source product. I suggest the term Source Available.

Please do not misconstrue this as an attack on Community Server or its licensing. I have met both Scott Watermasysk and Rob Howard and they are both very smart and capable leaders of a strong company. Community Server is a great product and deserves the recognition it gets. I am not a zealot and have no beef with closed source products. Certainly my livelihood depends on many such products.

At the same time, I am passionate about Open Source software and it is important to me to help keep the distinctions clear and educate others on what open source software is and the value it provides.

comments edit

Anyone have recommendations for Content Management systems for ASP.NET (ideally 2.0) that can handle a lot of traffic and allow for extremely customized site design? I am curious about which products are out there other than DotNetNuke and Microsoft Content Management Server.

Ideally this is something that you have implemented successfully on a project.

comments edit

Now this is the ultimate in geekery. K. Scott Allen posts pickup lines in .NET.

Now is this really necessary? Don’t geeks have enough troubles with the ladies without these serious groaners to encourage them?

So naturally, I must respond with my own groaners. Warning, not safe for … well really anyone who enjoys humor that is actually humorous.

  • You can handle my event any time
  • What’s your sign? I’m unsigned and I do byte. Rowr.
  • I’d like to get Interlocked with you and see what increments.
  • Them hips must be newing up objects real fast because you are putting pressure on my heap.
  • The moment I saw you I nearly overflowed my stack.
  • Care to reference my private member?
  • You Auto-Complete Me.

Update: My favorite comment so far on these groaners comes from Sahil Malik over on Scott’s blog.

Creating .NET pickup lines are a bit like opening a strip bar in antartica. Who are you gonna use ’em on?

My response is that these are not for us geeks. It is for those who wish to land a geek.

comments edit

My company has a small business account at Washington Mutual. I handle a lot of our banking via the online banking website. For several months now, their online banking website has been an absolute pain to use. After logging in I would be unable to access features that are kind of important such as…oh…I don’t know… the register and bill pay!

What was weird is that I would click on the link and would get some error message about calling technical support or an access denied message. But click on it again once (or 10 times) and it would finally work. Right now, the change password feature doesn?t appear to work.

Over time I would send messages to customer service and never get a satisfying response. Finally, Akumi offered to draft up a letter to the President of WAMU after one particularly frustrating bout with the site in which I was fuming.

Fast forward several days and I get a call from a representative who actually knows something about what is going on with the site and doesn’t blame me or my account. He is helpful and gives me his direct line. As he is walking me through some steps, I notice that some of the URLs end with .aspx. Oh, that is a promising sign!

I mention this to the rep because I never noticed it before. Most of the site runs on classic legacy ASP. The rep informs me that this weekend they have a planned upgrade to ASP.NET. That is definitely a step in the right direction!

comments edit

VelocIT Logo When we started VelocIT, one of the early tasks we had was to develop an identity. Identity development is an ongoing process that is really never over. Typically it starts with a flurry of identity building, then it tapers off as real work takes precedent. Every few years though, the process ramps up again as companies reinvent themselves or freshen their “look” for the next decade.

In our case, we had the talented Jon Hebert help us with our logo design. He writes about the process of starting with a vision and ending with a logo. I love the progression from the rough early sketches (which look like doodles I made in sixth grade) and ending with a logo we are all very happy with.

comments edit

Golly gee whiz but you learn something new every day. I was a big fan of Quickdoc viewer as a means to quickly view an HTML rendering of your XML comments directly from within VS.NET.

The reason I say was is that I cannot for the life of me get that sucker to work in VS.NET 2005 on my machine. I am also having problems with GhostDoc. It seems any plugin that uses the new XML file based registration (instead of the registry) doesn’t work for me. Perhaps because I am running as a LUA?

In any case, I just noticed that Resharper has a similar feature, though not nearly as nice as Quickdoc. If you select a method or class and hit CTRL+Q, it will show a window with a more readable version of your XML comments. The following image demonstrates the feature.

I am very happy to find this, but only because I can’t get QuickDoc to work. Quickdoc is far better in how it renders the documentation in pretty much the same way that NDoc does. Maybe I should the Jetbrains folk with a feature request to improve this a tad bit.

comments edit

creek Yesterday afternoon the wife and I took a bike ride along Ballona Creek. Now the word creek might conjure up an image for you of tall brushy trees on grass shores following the languid contours of a water way occasionally broken up by a small rapid or waterfall. Maybe the picture on the right reflects that vision.

If so, you do not live in Los Angeles.

Ballona Creek The picture at the left here reflects the concrete reality of Los Angeles water ways. Los Angeles rivers and creeks are heavily angular and typically filled with a murky green substance one hesitates to call “water” in fear of insulting the life sustaining liquid.

Now this may not look like a nice place for a bike ride, but consider for a moment the alternative - Biking down Venice Boulevard: Dodging gas guzzling H2 drivers in vehicles so large they require binoculars to see us lowly bikers. Stopping at a light every five seconds. Breathing in the smog ridden fumes of cars that I know have failed their smog check. Nah, that is not for me.

Personally, my favorite rides are up in the ocean tinged fresh air hills of Santa Monica Mountains (those of us who have lived in Alaska pretty much call everything here in Los Angeles a “hill”, with the exception of Mt. Baldy).

But there is something to be said of a ride that one can take right from the door of his or her own home. A short ride down the street takes us to the Ballona Creek Bike Trail entrance. From there, miles and miles of trail without interruptions from stop lights and motorized vehicles. And for the most part, it doesn’t really smell all that bad and there are some nice views of L.A. here and there.

But what really makes this ride great is the prize at the end. Marina Del Rey and Playa Del Rey. As the water turns from green sludge to a bluer color that reminds you that it is indeed water we are riding next to, the view opens up to the harbor. Sail boats drift by as the trail continues on and takes you right along the beach with people playing volleyball, jumping in the water, and throwing sand all over the place. It is really beautiful there.

We stopped at Tanner’s coffee to sit back for a moment and enjoy frosty beverage (it was the only thing we could find at that moment) and then headed back. Next time I will be sure to take some pictures.

comments edit

Bug I recently ran into a perplexing problem that I believe is a bug in ASP.NET 2.0.

Subtext dynamically loads UserControls into the page when fulfilling a request. When commenting on a post, we load a user control that contains the comment form fields and some instances of the RequiredFieldValidator validation control.

While testing, I noticed I kept getting javascript errors when trying to post a comment. Here is the error message:

missing ; before statement

Viewing the source, I noticed the error occurs in the javascript generated by the ASP.NET runtime for client side validation. Here is a tiny snippet of the line with the problem.

var ControlWithValidators.ascx_validateThat = document.all ? ...

Notice the problem? There is a dot in the variable name that Javascript does not like since ControlWithValidators is not an object. What the?

After some digging around I found the culprit. I won’t bore you with the nitty gritty details. When dynamically adding controls to a page, it is a good idea to specify an id before adding them to the Controls collection. That way the controls can reload their state on Postback. However the snippet of code I found was giving the controls an ID that contained a period.

To prove this was indeed the culprit, I created a new simple VS.NET 2005 Web Application Project that exhibits the bug. The page dynamically loads a user control that contains a validation control. Here is the Page_Load method of the web page. When you compile this and run the page, you will see the javascript error.

protected void Page_Load(object sender, EventArgs e)
{
    Control control = LoadControl("ControlWithValidators.ascx");
    control.ID = "ControlWithValidators.ascx";
    placeholder.Controls.Add(control);
}

The quick fix was to simply replace the period with an underscore when assigning the id. Hopefully this helps you if you ever run into something so obscure.

If you are interested in duplicating the bug, you can download the validator bug demo solution here. By the way, does anyone know where is the best place to report this kind of thing?

comments edit

Here is a quick little nugget for you custom provider implementers. I recently scanned through this article on MSDN that describes how to implement a custom provider and found some areas for improvement.

Reading the section Loading and Initializing Custom Providers I soon encountered a bad smell. No, it was not my upper lip, but rather a code smell. Following the samples when implementing custom providers would lead to a lot of duplicate code.

It seemed to me that much of that code is very generic. Did I just say generics?

Simone (blog in Italian), a Subtext developer, recently refactored all our Providers to inherit from the Microsoft ProviderBase class.

One of the first things he did was to create a generic provider collection:

using System;
using System.Configuration.Provider;

public class GenericProviderCollection<T> 
    : ProviderCollection 
    where T : System.Configuration.Provider.ProviderBase
{

    public new T this[string name]
    {
        get { return (T)base[name]; }
    }

    public override void Add(ProviderBase provider)
    {
        if (provider == null)
            throw new ArgumentNullException("provider");

        if (!(provider is T))
            throw new ArgumentException
                ("Invalid provider type", "provider");

        base.Add(provider);
    }
}

That relatively small bit of code should keep you from having to write a bunch of cookie cutter provider collections. But there is more that can be done. Take a look at the LoadProviders in Listing 6 of that article.

There are two things that bother me about that method listing. First is the unnecessary double check locking, which Richter poo poos in his book CLR via C#. The second is the fact that this method is begging for code re-use. I created a static helper class with the following method to encapsulate this logic (apologies for the weird formatting. I want it to fit width-wise):

/// <summary>
/// Helper method for populating a provider collection 
/// from a Provider section handler.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static GenericProviderCollection<T> 
        LoadProviders<T>(string sectionName, out T provider) 
            where T : ProviderBase
{
    // Get a reference to the provider section
    ProviderSectionHandler section = 
        (ProviderSectionHandler)WebConfigurationManager
              .GetSection(sectionName);

    // Load registered providers and point _provider
    // to the default provider
    GenericProviderCollection<T> providers = new 
          GenericProviderCollection<T>();
    ProvidersHelper.InstantiateProviders
          (section.Providers, providers, typeof(T));

    provider = providers[section.DefaultProvider];
    if (provider == null)
        throw new ProviderException(
            string.Format(
                  "Unable to load default '{0}' provider", 
                        sectionName));
    
    return providers;
}

This method returns a collection of providers for the specified section name. It also returns the default provider via an out parameter. So now, within my custom provider class, I can let the static constructor instantiate the provider collection and set the default provider in one fell swoop like so:

public abstract class SearchProvider : ProviderBase
{
    private static SearchProvider provider = null;
    private static GenericProviderCollection<SearchProvider> 
       providers = ProviderHelper.LoadProviders<SearchProvider>
           ("SearchProvider", out provider);
}

By employing the power of generics, writing new custom providers with a minimal amount of code is a snap. Hope you find this code helpful.

comments edit

Jim Holmes and James Avery announced that their new book Windows Developer Power Tools is going to be published in November.

Since I haven’t read the book yet, I cannot claim it will absolutely be the must read book of the summer. But I have a good feeling about this one for some reason.

Ok. Ok. I admit, I am biased because I am a contributor. Take a look at the table of contents here. My contributions are in Chapter 11, “Accessing Subversion and CVS with TortoiseSVN/CVS” as well as in Chapter 13 where I wrote about one of my favorite topics, Subtext.

I also reviewed the chapter on MbUnit with Andrew Stopford.

Having seen a couple other draft chapters, I am really excited about this book and not just because I contributed. Open source projects can be notorious for lacking in documentation. I can’t be sure, but I imagine that this book may be the impetus for some of these projects to actually write some documentation. But I am going out on a limb by saying that.

My contribution to this book is much more significant and original than my pseudo-contribution to another book this year.

comments edit

Arizona Tea You probably didn’t know this, but this blog is more than a technical blog. It is also your source for solving all the world’s problems. For example, there is the age old question, “Where did the matching sock go?” Did you notice the extra amount of lint in the dryer? Problem solved.

Today I noticed something interesting in the cupboard. We bought some Arizona Iced Tea Mix. It’s the powder stuff you mix with water to produce a refreshing drink. I noticed that not only is it packaged in a tin, but right there on the tin it lets you know that it is a collectible tin. Really? Wow! I can’t wait to get the whole set!

So that got me thinking, it makes a ton sense to label it as a collectible. Otherwise that tin becomes an ordinary piece of garbage when the little tea packages run out. But now, my friends, it is a wonderful mantle piece ready to be displayed with pride to other collectors. Perhaps I will be the one to puff out my chest and brag how I found the rare Peach Tea Tin with the misprint logo, eliciting a bit of envy among other collectors.

But why stop there. I notice that candy bars produce a lot of litter on the streets. Why not have our Snicker bars come in collectible wrappers? Or that impossible to break plastic shell that electronic devices are packaged in? Maybe if we made every newspaper issue a special collector’s edition, we could really reduce our landfill clutter.

The end result is that we will have moved from a centralized landfill structure (and all us geeks know centralized is bad! Booo!) into a decentralized peer-to-peer (good! yay!) landfill structure. It is the Napsterization of garbage…er collectibles (though perhaps Bittorentization is more accurate, but Napsterization sounds better).

comments edit

Subtext Logo Okay, it is survey time for all you Subtext users! I would like to know which Subtext skin you use for your blog. Please leave a comment with the skin that you use. If you use a custom skin, then just say Custom.

I have heard many say that the skins in Subtext look like they were designed by a developer rather than a designer. Well surprise surprise, probably because they were! I have a sneaking suspicion that many are not in use.

The reason this is important to me is that rather than simply continuing to add more and more skins to Subtext (generating a huge list), I would like to weed out some of the more drab skins. But instead of deleting skins, I was thinking I could simply replace them with newer skins that still fit the spirit of the original skin’s name. For example, I might replace the skin White with a new design that is very light in color and tone. Make sense?

comments edit

I have been considering using a separate library for generating the RSS and Atom feeds in Subtext. My first thought was to use RSS.NET but I noticed that there seemed to be no recent activity.

I contacted the admin and found out that RSS.NET has been bought by ToolButton Inc and will be released as a product. Very cool!

In the meanwhile, I still need an open source RSS library to package up with Subtext. Fortunately, RSS.NET was developed under the MIT license which, as I mentioned before, is very compatible with our BSD license.

So one option is to simply copy the code into our Subtext code base. My only qualm about this approach is that I would like to keep stand-alone libraries that are not central to the Subtext Domain out of the Subtext codebase as much as possible, preferring to reference them as an external library.

Ideally, I would like to start a new project that is essentially a fork in RSS.NET, perhaps called FeedGenerator.NET (call me the forkmaster). I could probably host it on CodePlex in order to give me an opportunity to try it out and provide feedback. Would anyone find such a library useful other than us blog engine developers? Anyone have a better name?

I probably wouldn’t spend much time on this project except to provide changes and bug fixes as needed by Subtext. It would by no means be intended to compete with Web 2.0 Tools products, since they are probably going to be much more full featured than our humble needs. Besides, under the MIT license, any improvements we make would be available for them to roll into their product (following the terms of the license of course). It is the beauty of the MIT and BSD licenses.

Any thoughts? Suggestion? Etc…?

comments edit

In my last post, one of the restrictions listed when running in medium trust is that HTTP access is only allowed to the same domain. It is possible in web.config to add a single domain via the originUrl attribute of the <trust> element as described by Cathal.

To add more than one domain requires editing machine.config or creating a custom trust policy which will not be accessible to many users in a hosted environment. This may pose a big problem for those who care about trackbacks since even if you could modify machine.config, there is no way to predetermine every domain you will trackback.

One solution is to beg your hosting environment to relax the WebPermission in medium trust. If trackbacks and pingbacks are important to you, you shouldn’t be above begging. ;)

Another is for someone to create a passthrough trackback system in a fully trusted environment. Essentially this would act on behalf of the medium trusted trackback creator and forward a trackback to the final destination. It would require blogging engines affected by medium trust to trust this single domain. Of course the potential for abuse is high and the rewards are low (unless people out there absolutely love trackbacks).

log4net logging aspnet comments edit

UPDATE: Mea Culpa! It seems like Log4Net has no problems with medium trust and an external log4net file. I have written an updated post that talks about the problem I did run into and how I solved it.

A while ago I wrote a quick and dirty guide to configuring Log4Net for ASP.NET. Unfortunately, this technique does not work with ASP.NET 2.0 when running in medium trust.. This technique continues to work with medium trust!

While digging into the problem I found this blog post (from an aptly titled blog) by Kevin Jones.

This article from Microsoft discusses the ramifications of running ASP.NET 2.0 in medium trust more thoroughly. Here is a list of constraints placed on medium trust applications.

The main constraints placed on medium trust Web applications are:

  • OleDbPermission is not available. This means you cannot use the ADO.NET managed OLE DB data provider to access databases. However, you can use the managed SQL Server provider to access SQL Server databases.
  • EventLogPermission is not available. This means you cannot access the Windows event log.
  • ReflectionPermission is not available. This means you cannot use reflection.
  • RegistryPermission is not available. This means you cannot access the registry.
  • WebPermission is restricted. This means your application can only communicate with an address or range of addresses that you define in the <trust> element.
  • FileIOPermission is restricted. This means you can only access files in your application’s virtual directory hierarchy. Your application is granted Read, Write, Append, and PathDiscovery permissions for your application’s virtual directory hierarchy.

You are also prevented from calling unmanaged code or from using Enterprise Services.

Fortunately there is a way to specify that a configuration section within web.config should not require ConfigurationPermission. Simply add the requirePermission="false" attribute to the <section> declaration within the <configSections> area like so:

<configSections>
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler
      , log4net"     
      requirePermission="false"/>
</configSections>

Unfortunately this applies to configuration sections within the web.config file. I have not found a way to specify that ASP.NET should not require ConfigurationPermission on an external configuration file. As I stated in my post on Log4Net, I prefer to put my Log4Net configuration settings in a separate configuration file. If anyone knows a way to do this, please let me know!

So in order to get Log4Net to work, I added the declaration above to the web.config file and copied the settings within the Log4Net.config file (pretty much cut and paste everything except the top xml declaration) into the web.config file. I then removed the assembly level XmlConfigurator attribute from AssemblyInfo.cs as it is no longer needed. Instead, I added the following line to the Application_Start method in Global.asax.cs.

protected void Application_Start(Object sender, EventArgs e)
{
    log4net.Config.XmlConfigurator.Configure();
}

So in summary, here are the changes I made to get Log4Net to work again in medium trust.

  • Added the log4Net section declaration in the configSections section of web.config and made sure the requirePermission attribute is set to the value false.
  • Moved the log4Net settings into web.config.
  • Removed the assembly attribute XmlConfigurator
  • Added the call to XmlConfigurator.Configure() to the Application_Start method in Global.asax.cs.

I have been working on getting the version of Subtext in our Subversion trunk to run in a medium trust environment, but there have been many challenges. Some of the components we use do not appear to run in a medium trust environment such as the FreeTextBox. Fortunately, we have a workaround for that issue which is to change the RichTextEditor node in web.config to use the PlainTextRichTextEditorProvider (which is a mouthful and should probably be renamed to PlainTextEditorProvider).

comments edit

Apple Ad Recently I poked lighthearted fun at one of the recent Apple commercials called “Network”

There are many who dislike the ads and claim that the ad is blatantly not true. One example is this humorous and well written rebuttal by Seth Stevenson.

Seth points out…

The final straw, for me, is that the spots make unconvincing claims. The one titled “Network” has a funny bit where “that new digital camera from Japan” is represented by a Japanese woman in a minidress. While Hodgman has trouble talking with the woman, Long speaks Japanese and shares giggles with her because “everything just kind of works with a Mac.” Now, I happen to have a digital camera from Japan, and it works just fine with my PC. It did from the moment I connected it.

Good point Seth. Perhaps the ad would have been more accurate had it been a Japanese printer rather than a digital camera. And I mean a printer that really is from Japan. My wife’s dad left us an Epson PM-950C Printer (among other things). This printer is not listed on the Epson U.S. site, but presumably can be found in the Japanese site.

In order to test it out, we plugged it into the USB port on her five year old iBook and printed a web page. Worked like a charm.

Fast forward a couple of weeks and we want to use the printer on my PC. We plugged it in and get the Windows cannot find the driver for the hardware dialog and were unable to print. Effectively, it didn’t just work. I then downloaded a driver that is supposed to be the U.S. equivalent. Still didn’t work.

My wife laughed out lound and said, “See! The ads are right!” I caught myself making excuses explaining to her that there are technical reasons beyond her comprehension and that I just need to toy with it for a moment to get it to work.

But I caught myself. Why am I making excuses for PCs and Microsoft? The experiment was quite simple. I plugged in a Japanese printer into a Macintosh, and we were able to print. I plug in the same printer into our PC (which was recently re-installed) and it didn’t work. Anecdotal evidence, sure, but adds weight to the Apple claim that things just work with the Apple and they don’t just work with Windows.

And responding with, “Well it will with Vista” is not a satisfactory answer. Tomorrow cars will fly, the U.S. will win the World Cup, and we will control our computers by having conversations with them and manipulating holograms. But the fact of the matter is that we all live in today and I will give Apple a bit of credit here.

comments edit

A while ago I had the idea of posting a picture of the day. Of course I didn’t mean every day, but the title might lead one to believe so. Therefore in order to reduce confusion, here is the next photo in my Picture of the Moment series.

Geisha
Trio

This is the most favorited and interesting picture according to Flickr in my Flickr account. So naturally that tells you that it wasn’t me who took this photo, but my lovely wife while on a trip to Japan. I was reminded of this picture because someone recently added a comment.

Speaking of Flickr, I love how you can comment specific regions of a picture by drawing box on the region. If you click on the image, you can see my feeble attempts at humor by moving your mouse of the photo. My comments are in sharp contrast to the elegance of three Geisha walking through a crowd.

comments edit

Jeff asks the question, “Isn’t programming supposed to be fun?”? Ha ha ha, naive little bunny. As if the person who invented programming had fun in mind. Silly rabbit.

You’ve heard the cliche. The reason it is called work is because it is work. Programming is fun when it is just for fun.

Cynical jokes aside, I actually did work for fun at my last job. Well technically, I worked for FUN. My former employer was bought by a company that then changed its name to Fun Technologies. It is listed under the symbol FUN on the Toronto Stock Exchange and the Alternative Invesment Market of the London Stock Exchange.

When I visited headquarters in Toronto the CEO gave me a hat with the ticker symbol emlazoned on the front. I think I still have it somewhere. I would wear it and go around telling people that I work for FUN. It was mildly funny for about two minutes. But as is my style, I dragged it out for thirty.

sql comments edit

Bullet Working as a team against a common database schema can be a real challenge. Some teams prefer to have their local code connect to a centralized database, but this approach can create many headaches. If I make a schema change to a shared database, but am not ready to check in my code, that can break the site for another developer. For a project like Subtext, it is just not feasible to have a central database.

Instead, I prefer to work on a local copy of the database and propagate changes via versioned change scripts. That way, when I check in my code, I can let others know which scripts to run on their local database when they get latest source code. Of course this can be also be a big challenge as the number of scripts starts to grow and developers are stuck bookkeeping which scripts they have run and which they haven’t.

That is why I always recommend to my teams that we script schema and data changes in an idempotent manner whenever possible. That way, it is much easier to simply batch updates together in a single file (per release for example) and a developer simply runs that single script any time an update is made.

As an example, suppose we have a Customer table and we need to add a column for the customer’s favorite color. I would script it like so:

IF NOT EXISTS 
(
    SELECT * FROM [information_schema].[columns] 
    WHERE   table_name = 'Customer' 
    AND table_schema = 'dbo'
    AND column_name = 'FavoriteColorId'
)
BEGIN
    ALTER TABLE [dbo].[Customer]
    ADD FavoriteColorId int
END

This script basically checks for the existence of the FavoriteColorId column on the table Customer and if it doesn’t exist, it adds it. You can run this script a million times, and it will only make the schema change once.

You’ll notice that I didn’t query against the system tables, instead choosing to lookup the information in an INFORMATION_SCHEMA view named Columns. This is the Microsoft recommendation as they reserve the right to change the system tables at any time. The information views are part of the SQL-92 standard, so they are not likely to change.

There are 20 schema views in all, listed below with their purpose (aggregated from SQL Books). Note that in all cases, only data accessible to the user executing the query against the information_schema views is returned.

Name Returns
CHECK_CONSTRAINTS Check Constraints
COLUMN_DOMAIN_USAGE Every column that has a user-defined data type.
COLUMN_PRIVILEGES Every column with a privilege granted to or by the current user in the current database.
COLUMNS Lists every column in the system
CONSTRAINT_COLUMN_USAGE Every column that has a constraint defined on it.
CONSTRAINT_TABLE_USAGE Every table that has a constraint defined on it.
DOMAIN_CONSTRAINTS Every user-defined data type with a rule bound to it.
DOMAINS Every user-defined data type.
KEY_COLUMN_USAGE Every column that is constrained as a key
PARAMETERS Every parameter for every user-defined function or stored procedure in the datbase. For functions this returns one row with return value information.
REFERENTIAL_CONSTRAINTS Every foreign constraint in the system.
ROUTINE_COLUMNS Every column returned by table-valued functions.
ROUTINES Every stored procedure and function in the database.
SCHEMATA Every database in the system.
TABLE_CONSTRAINTS Every table constraint.
TABLE_PRIVILEGES Every table privilege granted to or by the current user.
TABLES Every table in the system.
VIEW_COLUMN_USAGE Every column used in a view definition.
VIEW_TABLE_USAGE Every table used in a view definition.
VIEWS Every View

When selecting rows from these views, the table must be prefixed with information_schema as in SELECT * FROM information_schema.tables.

Please note that the information schema views are based on a SQL-92 standard so some of the terms used in these views are different than the terms in Microsoft SQL Server. For example, in the example above, I set table_schema = 'dbo'. The term schema refers to the owner of the database object.

Here is another code example in which I add a constraint to the Customer table.

IF NOT EXISTS(
    SELECT * 
    FROM [information_schema].[referential_constraints] 
    WHERE constraint_name = 'FK_Customer_Color' 
      AND constraint_schema = 'dbo'
)
BEGIN
  ALTER TABLE dbo.Customer WITH NOCHECK 
  ADD CONSTRAINT
  FK_Customer_Color FOREIGN KEY
  (
    FavoriteColorId
  ) REFERENCES dbo.Color
  (
    Id
  )
END

I generally don’t go to all this trouble for stored procedures, user defined functions, and views. In those cases I will use Enterprise manager generate a full drop and create script. When a stored procedure is dropped and re-created, you don’t lose data as you would if you dropped and re-created a table that contained some data.

With this approach in hand, I can run an update script with new schema changes confident that I any changes in the script that I have already applied will not be applied again. The same approach works for lookup data as well. Simply check for the data’s existence before inserting the data. It is a little bit more work up front, but it is worth the trouble and schema changes happen less frequently than code or stored procedure changes.