Andornot Blog

Wednesday, May 12, 2010 10:10 AM

Adding Google Analytics without touching your site

by Ted Jardine

I had a problem: Kathy and Denise wanted Google Analytics configured for our demo Genie site that can be found at http://genie.andornot.com. However, Genie doesn't provide an easy way to centrally add the couple lines of Google Analytics code to every page served up by the application. For that matter, neither does any WebPublisher PRO site right out-of-the-box (easy-peasy though if we're using ASK and our WebPubResults control).

You might also have the same problem: you recognize that having multiple means of tracking and analyzing your site's traffic is no longer optional. However, while you've got server log file analysis handled (we use SmarterStats for all our hosted clients) your site doesn't have a single central place (such as site-wide central templates) to easily integrate a javascript-based page tagging solution such as Google Analytics.

So what do we do? Instead of updating 10s if not 100s or 1000s of files manually one-by-one (crossing my fingers that I could find them all) and hoping my code wouldn't need to change anytime soon, I came up with a modified version of the Web Analytics Tracking Module available on Microsoft's IIS.net site. Now, with a little elbow grease for initial server setup (seriously, not very much elbow grease at all), turning on site tracking for any site on our servers is simply a matter of placing a DLL in our application's bin directory, and adding a couple lines to our site's Web.config. Sweet.

Why not just use the original IIS.net Web Analytics Module?

Before jumping in and explaining how to set everything up, I should explain that I needed create my own custom build of the module because the module on IIS.net only works under IIS 7's integrated pipeline, not under IIS 7's classic pipeline (which Genie needs to run under) or IIS 6. The required changes ended up being relatively minor:

  1. Modified the ReadModuleConfiguration method in WebAnalyticsHttpModule.cs to the following:
  2. /// <summary>
    
    /// Reads the module specific configuration properties
    
    /// </summary>
    
    /// <param name="context"></param>
    
    /// <returns>Boolean indicating the success/failure</returns>
    
    private bool ReadModuleConfiguration(HttpContext context)
    
    {
    
         try
    
         {
    
             ConfigurationSection section = null;
    
             if (HttpRuntime.UsingIntegratedPipeline)
    
                section = WebConfigurationManager.GetSection(context, "system.webServer/webAnalytics", typeof(WebAnalyticsSection));
    
             else
    
                section = WebConfigurationManager.GetSection(context, "system.web/webAnalytics", typeof(WebAnalyticsSection));
    
              if (section != null)
    
                 _webAnalyticsModuleConfig = (WebAnalyticsSection)section;
    
         }
    
         catch (Exception)
    
         {
    
             return false;
    
         }
    
           return _webAnalyticsModuleConfig != null;
    
        }
    
    }
  3. Add the classic pipeline <system.web>/<webAnalytics> schema to WebAnalytics_schema.xml:
  4. <sectionSchema name="system.web/webAnalytics">
    
        <attribute name="trackingEnabled" type="bool" defautlValue="false"></attribute>
    
        <attribute name="trackingScript" type="string"  defautlValue="This is a default text"></attribute>
    
        <attribute name="insertionPoint" type="enum" defaultValue="body">
    
            <enum name="head" value="0" />
    
            <enum name="body" value="1" />
    
        </attribute>
    
    </sectionSchema>
    
  5. To make sure there's no versioning conflicts, I updated the Assembly's version to v1.1 in AssemblyInfo.cs (note the v1.1 references in the instructions below as opposed to v1.0):
  6. [assembly: AssemblyVersion("1.1.0.0")]
    
    [assembly: AssemblyFileVersion("1.1.0.0")]

 

Configure your server (one time only)

  1. Register the WebAnalyticsModule.dll in the GAC (for shiny stuff in the IIS 7 Manager GUI).

    gacutil -if WebAnalyticsModule.dll
  2. Copy the WebAnalytics_schema.xml to "%windir%\system32\inetsrv\config\schema" folder.
  3. Add the following section definition to the "%windir%\system32\inetsrv\config\applicationhost.config" file in the sectionGroup for "system.webServer"
  4. <section name="webAnalytics" overrideModeDefault="Allow" />
  5. Add the module to the IIS Manager configuration by adding to two collections in the "%windir%\system32\inetsrv\config\administration.config" file:
    • Add the following to the moduleProviders collection:
    • <add name="WebAnalytics" type="WebAnalyticsModule.WebAnalyticsProvider, WebAnalyticsModule, Version=1.1.0.0, Culture=neutral, PublicKeyToken=c6b7132bcfe43312" /> 
      
    • Add the following to the modules collection:
    • <add name="WebAnalytics" />


web-analytics-tracking-in-iis
Web Analytics Tracking now directly available in IIS 7 Manager (at least for sites running under Integrated Pipeline).

 

Configure your site/s

For each site you wish to have Google Analytics enabled on (or any other script/text/html you wish to have run on every page in the site), enable it according to the following instructions (slightly different for different flavours of IIS/pipeline).

IIS 7 Integrated Pipeline

  1. Place the same WebAnalyticsModule.dll in your application's bin directory or reference the GAC version via the Web.config's <system.web>/<compilation>/<assemblies> element.
  2. Add the module to the <modules> element in your Web.config. This can be done through the IIS Manager, but it's easier to simply add it directly in the Web.config:
  3. <modules>
    
      ...
    
      <add name="WebAnalytics" type="WebAnalyticsModule.WebAnalyticsHttpModule, WebAnalyticsModule, Version=1.1.0.0, Culture=neutral, PublicKeyToken=c6b7132bcfe43312" />
    
    </modules>
  4. Specify the script/text you wish to have inserted and the location to insert it at. Again, this can be added directly in the Web.config. However, because the actual script/text needs to be encoded in order to keep your config file from going boink, it's a lot easier to just use the GUI.

  5. web-analytics-tracking-in-iis-configuration
    Easy configuration within the IIS 7 Manager GUI, including properly encoding the script for the Web.config (safe for XML).

    Enabling the above adds a <webAnalytics> element to the <system.webServer> section, looking something like (note the encoding):
    <webAnalytics trackingEnabled="true" trackingScript="&lt;script type=&quot;text/javascript&quot;>&#xD;&#xA;  var _gaq = _gaq || [];&#xD;&#xA;  _gaq.push(['_setAccount', 'UA-494411-1']);&#xD;&#xA;  _gaq.push(['_setDomainName', '.andornot.com']);&#xD;&#xA;  _gaq.push(['_trackPageview']);&#xD;&#xA;  (function() {&#xD;&#xA;    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;&#xD;&#xA;    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';&#xD;&#xA;    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);&#xD;&#xA;  })();&#xD;&#xA;&lt;/script>" insertionPoint="head" />

 

IIS 7 Classic Pipeline

Exactly the same as the IIS 7 integrated pipeline instructions above, with the following changes:

  1. Add the module reference to the classic pipeline specific <system.web>/<httpModules> section instead of the <system.webServer>/<modules> section.
  2. Make it easy for yourself, and add the script-specific settings (as in step 3 above) via the GUI in order to make sure it's all encoded properly, but then move/copy the resulting <webAnalytics> element from <system.webServer> (IIS 7 integrated pipeline specific) to <system.web>.
  3. Add the following to the <configuration>/<configSections> element in your Web.config (there should be a better way to add another sub-section to the already defined <system.web> declaration in the <configSections> element, so let me know in the comments if you know what it is):
  4. <sectionGroup name="system.web" type="System.Web.Configuration.SystemWebSectionGroup, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> 
    
        <section name="webAnalytics" type="WebAnalyticsModule.WebAnalyticsSection, WebAnalyticsModule" /> 
    
    </sectionGroup> 
    

Caveat: as your app is running under classic pipeline, not all text/html resources are running through ASP.NET, and therefore, if you have for i.e. .html and/or .asp pages you want the script automatically added to, you will need to map those extensions to also route through the ASP.NET runtime. Pretty standard classic pipeline stuff: without doing so, only pages with the .aspx extension will have the script added.

 

IIS 6 (Classic Pipeline)

I haven't tested it, but I see no reason why it won't work with the same set up as IIS 7 Classic Pipeline, with the same caveats.

Notes:

  1. As you might have guessed, you can automatically insert *anything* using this module, as long as you don't mind it inserting just before the closing </head> tag or the closing </body> tag. Copyright statements, survey scripts, "Ted wuz here" alerts for every page...if you think of it, you can do it!
  2. Again, the fancy GUI stuff doesn't help you in classic pipeline scenarios (other than an XML-encoding aid as described above).
  3. Typically you want to register scripts as close to the end of your page as possible (various technical performance and usability reasons). However, Google Analytics' latest scripts have a "push" functionality making this a moot point: so register the latest scripts right before the closing </head> tag. See the "Asynchronous Tracking Usage Guide" for more information.

Different web analytics packages have different strengths and weaknesses, and it's only with multiple different perspectives on your site traffic that you even begin to get a clear picture of what is really happening with your site. Using this web analytics module makes it even easier to add and maintain a page tagging solution on your site.

 

Download

I'd like to just directly link to my compiled DLL and schema file of the module, but unfortunately, it's not at all clear what licensing model is associated with the original module (although it's clear from his article explaining the module, that Microsoft's Ruslan Yakushev intends for us to use it). Therefore, I'll be requesting clarification on this issue, but in the meantime, just download the source code from the original article and make the quick modifications as described above. If you have problems doing so, or you want help deploying it for your site, drop us a line.

Monday, January 28, 2008 4:11 PM

Avoid Application Pool Conflicts

by Peter Tyrrell

In IIS 6.0, different versions of the .NET framework can co-exist on the same website but must use separate application pools. Once a .NET process "grabs" the app pool, other .NET processes are denied its use and report generic server errors in the browser. Which .NET process gets an app pool first depends on which is first requested after an application pool recycle. For example the .NET 2.0 process might get the application pool first, and all .NET 1.1 applications that rely on the application pool fail to run; end users see generic server errors that do not report what is really going on.

Installing Inmagic Webpublisher or Genie

Although Webpublisher inmagicbrowse and Genie inmagicgenie virtual directories are correctly set to use .NET 2.0, the installer lets the parent website determine which application pool to use. A typical Windows 2003 Server might have .NET 1.1 and DefaultAppPool as the default on new websites. If there are any .NET 1.1 applications already on the server that rely on DefaultAppPool, then inmagicbrowse and inmagicgenie are setting the server up for an application pool conflict.

Separate Application Pools

Set up a separate application pool just for Genie, and one for Webpublisher. This way you avoid any conflict with applications currently on the server, but also allow for changes in .NET dependency in future: when Genie starts using .NET 3.5 you won't have to worry about re-organizing application pools. It's also good practice to isolate applications like this so that when one does go down, it doesn't take other applications with it.

Monday, April 30, 2007 5:37 PM

Change Site ID in IIS 6

by Ted Jardine

We have an application that is dependant on a web site's Site ID in IIS. Usually, when we need to move a site from one server to the next, we just change the Site ID while using the handy IIS Migration Tool. However, we just had a site that was set up without the Site ID properly set so our database records were out of sync. A little bit of googling and presto:

  1. Open a command line (make sure you're an Admin or run the script as an Admin).
  2. Navigate to your AdminScripts directory (typically c:\Inetpub\AdminScripts).
  3. And run this script: cscript adsutil.vbs move w3svc/118431234 w3svc/11165089073 (where the first is the old Site ID and the second is the new one)

I'm displaying my ignorance I'm sure by posting this here as something I didn't know already, but heh, it's a useful thing to make note of (you didn't think I'd go do a search and replace in the IIS Metabase file did you?).

Month List