Job Change at Pets Best Pet Insurance

April 19th, 2006

Last week, I made a fairly significant change in my role at Pets Best pet insurance (a division of General Fire & Casualty, my employer). We created the position of Internet Marketing Director, which I was offered and eagerly accepted. I enjoyed my role as VP of Technology for GF&C, but it was simply too much to manage the day-to-day operations of IT while simultaneously developing Pets Best’s Internet marketing strategy, not to mention executing it.

I’m incredibly excited about this opportunity. I quit a very good job in 2000 to go back to school and finish up my bachelor’s degree in BIS with an e-commerce emphasis, and then my master’s in e-commerce from Carnegie Mellon in Pittsburgh. My new role allows me to work more directly in the field I love while utilizing the fantastic education I received at CMU. I will still continue developing on the side, as it’s something I enjoy, but it will get harder for me to keep up. Like software development, Internet marketing is an information rich and fast-changing field and doing it well requires a significant time investment outside of work. In the past two months, I’ve averaged about 20 hours per week outside of work getting up to speed on things like search engine optimization (SEO), search engine advertising, and a host of other things that I can’t disclose right now.

Stay tuned!

Do MSN adCenter Developers Live in a Bubble?

March 17th, 2006

Danny Sullivan from Search Engine Watch reports on some problems that MSN adCenter has with Firefox.  I encountered the same issue of not being able to log in to my adCenter account with Firefox and went through the same process as I do with every other Firefox unfriendly site– 1)  Sigh 2) Right-click, select View This Page in IE.   But this isn’t even the worst of it–not even close.  Apparently there are issues with the tracking javascript as well.  If a Firefox user visits a website that is using the adCenter tracking code, he/she may receive a message that more or less says the site can’t be trusted.

One can only conlude that the adCenter developers either didn’t do cross-browser compat testing or did a piss-poor job of it.  I can tell you from experience that any web developer that is even slightly concerned about the quality of work he or she does checks the web sites/pages using at least 3 or 4 browsers.  With Firefox browsershare around 10%, it’s just plain stupid not to test–especially when you’re releasing code that is going to be coming from your customers’ websites and potentially impacting hundreds of thousands of web surfers.  Stupid.

VS 2005 Refactoring Performance Tip

March 17th, 2006

Finally!  We now have a way to make refactoring with VS 2005 usable with ASP.NET apps.  Refactoring performance is so bad with VS 2005 that I had pretty much stopped using it.  It sounds like the problem is going to officially be addressed in the first service pack for VS, but until that happens check out Scott Gu’s tip for improving performance now.

Visual Studio 2005 Cache Visualizer

March 17th, 2006

Anyone who’s ever tried to look at ASP.NET’s cache in a Visual Studio Watch window has likely given up after experiencing light-headedness and a motion-sickness sensation. View the dependencies? Yeah right.

After I wrote Control Visualizer, I got a little more ambitious and decided to write Cache Visualizer. I knew it would be more challenging, just not HOW much more. Almost everything related to the cache is internal/private, so reflection is really the only way to get at the interesting information about cache entries. At any rate, after 1 ½ weeks of coding off-and-on, I can finally give you something that should come in handy if you’re using ASP.NET 2.0’s caching features.

Unlike the relatively simple Control Visualizer, this one comes with a few disclaimers:

  • I’ve been hard-pressed to get this thing done so I can move on to other projects I’ve been neglecting, so the code isn’t near as well-written or commented as I’d like (I did try to include comments on all classes and important methods though).
  • It uses a lot of reflection – much of it obtaining access to internal/private fields. Scary, but necessary.
  • SqlCacheDependency info is only displayed for Sql Server 7/2000 dependencies at this point.
  • I have no idea what the side effects may be if you remove a cache entry or touch a file with a file dependency on it if the cache entry has a remove callback set…you’ve been warned [but I’ve tried it and didn’t have any problems :o)]
  • I haven’t fully tested it. I’ve tried it with standard CacheDependency, SqlCacheDependency, AggregateDependency, with multiple file dependencies, etc. But there’s still plenty that could go wrong.
  • If it screws something up in your app….feel free to let me know, but don’t get pissed or cry to me about it :o).

Screenshots and code below….Enjoy! (The source code also includes Control Visualizer, which contains a few cosmetic UI changes since the first release.)

CacheVisualizer - File CacheDependency

Cache entry with file dependencies.

CacheVisualizer - Sql CacheDependency

Cache entry with Sql dependency.

UPDATE: Somehow I left the Value property of the list of cache info to display. The source now includes this.

Download here (47KB)

Visual Studio 2005 Control Visualizer

April 20th, 2005

Yesterday at work I was having a heck of a time debugging a rendering problem in one of our custom server controls. The nature of the problem was such that I couldn’t figure out when the change was taking place that was causing the goofy rendering. I was thinking about how nice it would be if there was an easy way to take the control (or part of it, e.g. the HeaderRow) and see as I was stepping through the code how it would render-then I realized I could create my own visualizer to do this for me (I’m using Visual Studio 2005 beta 2).

The only real problem I ran into was that most of the documented methods for creating visualizers only work with serializable target classes (a visualizer refers to the object you want to view in your visualizer as the ‘target’). Since a Control is not serializable, these methods won’t work.

Fortunately I came across Scott Nonnenberg’s blog in which he mentions using a VisualizerObjectSource to get around this serialization issue—problem solved (credit also has to go to Howard Van Rooijen). Here’s some screenshots of the Control Visualizer in action. A link to the source code is below as well. Enjoy!

Control Visualizer Screenshot 1

In this screen shot you can see the magnifying glass button by every Control visible – MyGridView (the first pop-up item) and HeaderRow.

Control Visualizer Screenshot 2

Here’s the visualizer dialog form. It shows both the html source and how it looks when rendered in a browser, as well as a few other helpful bits of information: the control’s classname, the assembly it’s in, and the value of its ControlState property.

Note that you can also change the html source and refresh the browser view, as well as save the html to disk. For anyone doing custom control development in VS 2005, this should be a handy tool!

Download here (47KB)

ProviderConfigurationSection - More Provider Code Reuse

April 18th, 2005

The previous post (ProviderInitializer) utilizes a custom ConfigurationSection class named ProviderConfigurationSection.  This class provides a few properties common to all provider-related ConfigurationSection classes in ASP.NET 2.0 (see RoleManagerSection & MembershipSection in System.Web.Configuration – each provide their own implementation of these properties rather than utilizing a common base class.  Sure, it’s minimal duplication, but….bleh).

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.ComponentModel;

namespace Johnson.Common.Configuration
{
    /// <summary>
    /// Provides base implementation for provider configuration sections.
    /// </summary>
    public class ProviderConfigurationSection : ConfigurationSection
    {
        private readonly static ConfigurationProperty _providers = new ConfigurationProperty(“providers”,
            typeof(ProviderSettingsCollection), null, ConfigurationPropertyOptions.None);

        /// <summary>
        /// Ctor
        /// </summary>
        public ProviderConfigurationSection()
            : base()
        {
        }

        /// <summary>
        /// Gets a property’s value.
        /// </summary>
        /// <param name=”propertyName”></param>
        /// <returns></returns>
        protected virtual new object this[string propertyName]
        {
            get
            {
                try
                {
                    return base[propertyName];
                }
                catch (NullReferenceException ex)
                {
                    // If the property isn’t found we get a very unhelpful NullReferenceException
                    // in the base ConfigurationSection class, so we catch this
                    // and throw something more helpful.
                    throw new KeyNotFoundException(“Could not find element matching key ‘” + propertyName + 
                     ”‘. Property names are case-sensitive, so check that proper casing was used.”, ex);
                }
            }
            set
            {
                base[propertyName] = value;
            }
        }

        /// <summary>
        /// Gets or sets the default provider.
        /// </summary>
        [
        ConfigurationProperty(“defaultProvider”, DefaultValue = null)
        ]
        public string DefaultProvider
        {
            get
            {
                return (string)this[“defaultProvider”];
            }
            set
            {
                this[“defaultProvider”] = value;
            }
        }

        /// <summary>
        /// Gets the collection of providers declared in the config.
        /// </summary>
        [
        ConfigurationProperty(“providers”, DefaultValue = null)
        ]
        public ProviderSettingsCollection Providers
        {
            get
            {
                return (ProviderSettingsCollection)this[_providers];
            }
        }
    }
}

ProviderIntializer - A Lazy Approach to Provider Managers

April 18th, 2005

One of the things I noticed when I first started digging around in ASP.NET 2.0’s provider framework was that there were a number of areas that didn’t do a very good job at reusing code. The one that stood out the most was the Initialize method on several of the provider managers (this is what I call the classes that initialize and provide static methods for accessing providers, e.g. the ProfileManager, Roles, and Membership classes). Load up Reflector and take a look at Roles.Initialize() and Membership.Initialize() (beta 2 or earlier), and you’ll see what I mean—they’re almost identical, and in my book, that’s a problem.

Below is one solution to this problem that utilizes generics. The responsibility for initializing providers has been taken away from the provider managers, and given to a class aptly named ProviderInitializer. This class takes care of the gory details of initializing providers, e.g. thread locking, careful exception handling, etc. I’ve used it in several custom providers and have found it to meet my needs—but it can be easily made more flexible by extracting blocks of code from the Initialize method into their own virtual methods.

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration.Provider;
using Johnson.Common.Configuration;
using System.Configuration;
using System.Web.Configuration;

namespace Johnson.Common.Providers;
{
    /// <summary>
    /// Provides initializtion logic for provider manager classes
    /// </summary>
    /// <typeparam name=”ProviderType”>The Type of the provider to initialize.</typeparam>
    /// <typeparam name=”ProviderCollectionType”>The provider’s corresponding collection
    /// type.</typeparam>
    /// <typeparam name=”ConfigSectionType”>The Type of the config section for reading
    /// provider settings.</typeparam>
    public class ProviderInitializer<ProviderType, ProviderCollectionType, ConfigSectionType>
        where ProviderType : ProviderBase
        where ProviderCollectionType : SafeProviderCollection<ProviderType>, new()
        where ConfigSectionType : ProviderConfigurationSection
    {
        private bool _initialized;
        private Exception _initializeException;
        private object _lock;
        private string _configSectionName;

        /// <summary>
        /// Ctor
        /// </summary>
        public ProviderInitializer(string configSectionName)
        {
            _configSectionName = configSectionName;
            _initialized = false;
            _lock = new object();
        }

        /// <summary>
        /// Initializes the provider.
        /// </summary>
        /// <param name=”provider”>The default provider.</param>
        /// <param name=”providers”>The provider collection.</param>
        public void Initialize(ref ProviderType provider, ref SafeProviderCollection<ProviderType> providers)
        {
            // check if initialize was already attempted and failed - if so, no reason to attempt
            // initializing again
            if (_initialized)
            {
                if (_initializeException != null)
                {
                    throw _initializeException;
                }
            }
            else
            {
                lock (_lock)
                {
                    try
                    {
                        // check again to make sure another thread hasn’t initialized provider
                        // since lock was acquired
                        if (_initialized)
                        {
                            if (_initializeException != null)
                            {
                                throw _initializeException;
                            }
                            return;
                        }

                        // Get provider section from config file
                        ConfigSectionType config = GetProviderConfigurationSection();

                        // GetProviderConfigurationSection() could have set _initializeException, check if null
                        if (_initializeException == null)
                        {
                            if (string.IsNullOrEmpty(config.DefaultProvider))
                            {
                                _initializeException = new ProviderException(“Default provider not specified.”);
                            }
                            else
                            {
                                providers = new SafeProviderCollection<ProviderType>();

                                ProvidersHelper.InstantiateProviders(config.Providers, providers, typeof(ProviderType));
                                providers.SetReadOnly();

                                // set default provider
                                if (providers[config.DefaultProvider] == null)
                                {
                                    _initializeException = new ProviderException(“Default provider not specified.”);
                                }
                                else
                                {
                                    // this is a safe cast, as each provider added to the providers collection has
                                    // already been checked to ensure it derives from the appropriate Provider Type.
                                    provider = (ProviderType)providers[config.DefaultProvider];
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _initializeException = ex;
                    }

                    _initialized = true;

                    if (_initializeException != null)
                    {
                        throw _initializeException;
                    }
                }
            }
        }

        /// <summary>
        /// Gets the config section for the provider.
        /// </summary>
        /// <returns></returns>
        protected virtual ConfigSectionType GetProviderConfigurationSection()
        {
            if (string.IsNullOrEmpty(_configSectionName))
            {
                _initializeException = new ProviderException(“configSectionName cannot be null or empty”);
                return null;
            }

            ConfigSectionType config = ConfigurationManager.GetSection(_configSectionName) as ConfigSectionType;

            if (config == null)
            {
                _initializeException = new ProviderException(“Unable to load provider configuration settings.”);
            }

            return config;
        }
    }
}