Home

Archived Posts from “What Is It”

Getting Started with AnkhSVN

22

July

I’ve previously written about managing your Subversion repositories via the TortoiseSVN client.  TortoiseSVN integrates with Windows Explorer and provides a really slick way to do things like view the status of your source code, update your Subversion working copy and commit change.

But as slick as it is, TortoiseSVN requires one to bounce between their IDE and the Windows Explorer.  You’re right!  A simple, two-second step, a mere ALT-TAB, shouldn’t be that disruptive but, for me, it is and it keeps me from committing my changes as often as I probably should.  Perhaps this is a flaw in the way I work, but it is, without a doubt, the way I work.

There are two players in the "Subversion Source Control Provider for Visual Studio" space.  There’s VisualSVN and there’s AnkhSVN.   Until this week, I had heard nothing but good things about VisualSVN and AnkhSVN reviews weren’t nearly as favorable. 

I ended up trying VisualSVN for over a week and, frankly, I was disappointed. I deserve to get negative feedback about publishing the following comments without any supporting documentation but I found VisualSVN to be sluggish and I felt it called up TortoiseSVN dialogues (rather than handling the file management itself) far too often.  Since so many folks like the product, I would be willing to bet I simply had a very bad first go (although I did spend over 1 week with the product.) All the same, it is uninstalled, the $49 are still burning a hole in my pocket and, well, there was no harm done. 

I reverted to my old ways of not using source control effectively by avoiding Windows Explorer and TortoiseSVN and then, on my birthday, AnkhSVN 2.0 Final was released.  Though folks grumbled about the previous version, 2.0 is a near rewrite of the original and is now a full Source Control Provider Integration Package rather than a Visual Studio Add-In. With commercial backing from CollabNet and renewed open source enthusiasm, AnkhSVN 2.0 seemed to deserve a look so I looked…

Quick Start

1. Download AnkhSVN 2.0 here and run the install package.  If you want the latest and greatest, check out the daily builds

 

2. The AnkhSVN download page says to install and then "Start Visual Studio and choose Tools -> Settings -> Source Control and make sure AnkhSVN is the active source control provider."  Actually, you want Tools -> Options rather than Settings, but you would probably figure that out on your own.  All the same, AnkhSVN was already configured/selected.

 

3. Open an existing solution and noticed the new "Pending Changes" windows (also available via View -> Show Pending Changes.)  Enter your repository URL into the empty "Working on:" field and, if you are as lucky as me (after all it was my birthday), everything should just work. 

image 

 

4. This step is optional, but inevitable. I think. After about 20 minutes of playing with AnkhSVN you’re probably going to want to hook up your favorite diff tool.  If your favorite diff tool is WinMerge, perform the following: Go to Tools -> Options -> Source Control -> Subversion -> External Diff Path = "C:\Program Files\WinMerge\WinMergeU.exe" "%base" "%mine"

image 

 

5. Once you are setup, you will see green check-marks alongside items in the Solution Explorer window.  And, as you start to make changes, you will see modified items added to the Pending Changes window.  This, my friends, is  a great feature!  Now you able to manage all of your changes in a single location rather than having to navigate through Windows Explorer or even the Solution Explorer. In another life, StarTeam provided me with similar functionality by allowing me to flatten out the folder hierarchy and then sorting by status, but the Pending Changes windows is 100 times better.  Sure, you can manage your commits via the Solution Explorer, but I’m not going to. The Pending Changes view is also great since the Solution Explorer doesn’t always conveniently show you the status of your files.  Take the screen shot below, for example.  Collapsing the EmailTemplates folder leaves me no insight into the state of the files within.  (For the record, I prefer VisualSVN’s Solution Explorer display.)

 

image

 

 

 

 

Side note: If I could do it all over again, I really wish I followed the posted download instructions.  The suggested setup sounds straight forward enough, but trying to replicate the steps now, after already setting up, is seemingly impossible.  The instructions can be firmed up for clarity (see prior example referring to incorrect menu names), but I would have liked to give them a test run without jumping the gun and setting up my own way first.  If you do follow the published install instructions, let me know how it goes for you as I simply can not make heads or tails out of some of the steps.  One thing which seems to be missing — perhaps because of my impatience — is the persistence of the Subversion repositories added to the Repository Explorer.  It is really nice a version of the Repository Browser is built in, but it seems odd that repositories would need to be reestablished each time you open a solution.  Anyhow, it is probably my fault…

Wrap Up

Thus far, I am pleased with AnkhSVN.  For those of you who tried out earlier versions and were disappointed, try again.  Here’s a partial list of what’s new in AnkhSVN 2.0:

  • For Microsoft Visual Studio 2005 and 2008.
  • Built on Subversion 1.5.0 via SharpSvn.
  • Pending changes window; subversion status and commands available in one place
  • Full support for Visual Studio 2005 and 2008; AnkhSVN is now a SCC package instead of just an addin
  • Better log viewer
  • Merge support
  • Property editor
  • AnkhSVN now supports most project types previously unsupported via the SCC api
  • All solution explorer actions (rename, copy&paste, drag&drop) keep subversion history now
  • Enhanced build process and setup
  • Automatic check for updates
  • And last but certainly not least end user documentation

For more information about AnkhSVN, check out the project’s home.

kick it on DotNetKicks.com


Ext JS

20

May

Originally built as an extension of YUI, Ext JS is a cross-browser JavaScript library for building rich Internet applications (RIA) using techniques such as AJAX, DHTML and DOM scripting. 

image A co-worker recently showed off a small sampling of what he’s done with Ext JS. Very simply, the framework blew my socks off.  If, like me, you believe you can sell anything if it has nice enough packaging, you want to review Ext JS customizable UI widgets and extensible component model.  My interest was piqued by merely clicking through the extensive set of online samples.  Some of the sample border on ridiculously cool.  Anyway, you be the judge.

Though I don’t have any hands-on experience with the framework, I understand  the API is intuitive and well documented.  A better-than-average understanding of JavaScript (functions are objects, etc) is beneficial but not required.  Ext JS can use many different base libraries or adapters (e.g. YUI, jQuery, Prototype) or it can work standalone.  So, experience other existing libraries can be a big plus.

The only negative information I have heard about Ext JS is related to their license history.  Apparently, the licensing situation used to be difficult to understand which caused at least one developer I know to shy away from the framework.  As of April 2008, however, licensing terms have been clarified by being dual-licensed with options of the GPL 3.0 license or commercial license.

Have a look and let me know what you think.

kick it on DotNetKicks.com


Resource Refactoring Tool

19

May

Resource Refactoring Tool provides developers with a super easy way to extract hard coded strings from your code into resource files.

imageI won’t say this tool has saved me days of time but has certainly saved me hours (especially on those hand-me-down projects which tend to require a good amount of clean up. )

You’ll find the tool works in VS2005/VS2008 as it leverages the existing Refactor menu. Simply install the latest version found on the CodePlex project site and then Select Text > Right Click > Refactor > Extract to Resource until you find yourself giggling to yourself.

I’m not a big utility guy, but this tool gets installed along with VS on work stations. Enjoy.


Getting Started with CruiseControl.NET

29

January

I consider myself a neophyte when it comes to continuous integration (CI), but having read up on the topic, “played around” a bit, reviewed a couple of products, and having now incorporated it into our standard development practices, I am starting to hold my own.  If nothing else, the benefits of continuous integration are now obvious and, well, I can’t imagine ever turning back. 

For me, the power of continuous integration extends far beyond build validation.  CI it has become a welcome management tool which allows me to keep my finger on the pulse of numerous developed products as well as individual developer contributions.  Though I am very interested in the overall success/fail state of the current build, equally valuable is the the notifications which email specified team members the code change log which accompanies each build. (i.e. A list modified files and associated comments since the last automated build.)  If you are responsible for overall project success (which typically includes management of deliverable, code quality, task distribution, etc) then continuous integration is for you.

As I mentioned earlier, I reviewed a few products.  Last year, I reviewed FinalBuilder which provided me a nice and easy introduction into this space.  Based almost completely on its popularly and price tag (free), I have since turned to CruiseControl.NET.  I will not claim that was able to quickly get up and running with CruiseControl.NET.  At times, I was down-right questioning if I was smart enough to figure out the product and its configuration.  But, alas, it is now running on a dedicated build machine and my team and I are all the better for it. 

Please let it be known that I am not a wizard when it comes to CruiseControl.NET.  I am, however, good at is documentation of repeatable actions and I tried to capture the steps on getting started with CruiseControl.NET below.  As always, any feedback is greatly appreciated.

By the way, if you are looking for general information on continuous integration or CruiseControl.NET, you are not going to find here.  For more information, you may wish to consult the following:  What is Continuous Integration and What is CruiseControl.NET.

That’s basically it.  Best of luck!

 

1. Find a Build Machine

Though CruiseControl.NET could be installed on a development machine, I recommended that it be installed on a dedicated build server. Your build server should have access your source control repository and an optimal STMP server.  The server should have IIS and the NET Framework installed as well.  More information on the build server to follow…

 

2. Install CruiseControl.NET

Download CruiseControl.NET Server and Dashboard and install using provided default selections. 

http://downloads.sourceforge.net/ccnet/CruiseControl.NET-1.3-setup.exe?modtime=1182463056&big_mirror=0

 

3. Install MSBuild

If you are working with .NET 2.0+ applications, you can build using MSBuild. Otherwise, you may need to learn a bit about NANT.  All of the provided sample configurations below assume you will be using MSBuild. 

The MSBuild DLL is not included in initial CCNET Server installation, but it can be downloaded from the ThoughtWorks site: http://ccnetlive.thoughtworks.com/MSBuildXmlLogger%2DBuilds/. To install, simply copy the ThoughtWorks.CruiseControl.MSBuild.dll into C:\Program Files\CruiseControl.NET\server\ location.

 

4. Install Source Control Client

You will potentially need to install your source control client on the build machine. For the samples provides, we are using Borland StarTeam 2005.  CruiseControl.NET integrates with just about every source control system I could think of, so if you are using something other than StarTeam, you will want to consult the Source Control Block documentation.

 

5. CruiseControl.NET Server Configuration

CruiseControl.NET Server is driven by CCNET configuration file settings. After the fresh install, the configuration is essentially empty and requires manual updates to the ccnet.config file itself. As far as my knowledge, there is no associated configuration editor.  First things first, crack open “C:\Program Files\CruiseControl.NET\server\ccnet.config” in Visual Studios or your favorite XML editor. (There is shortcut under All Programs > CruiseControl.NET > CruiseControl.NET Config.)

If you have a pre-configured ccnet.config file available, simply overwrite the file content. If you are starting from scratch, you may wish reference the online CruiseControl.NET configuration overview and review samples: http://confluence.public.thoughtworks.org/display/CCNET/Configuring+the+Server.  Additional example configuration files were installed on your build box as well: C:\Program Files\CruiseControl.NET\Examples.  They are worth a look.

The bad news: Though you will find examples sprinkled throughout the ThoughtWorks site and the locations noted above, you will most likely need to muck around with your own config file for a while until you get it right.  Additional samples are provide below, but just as I wasn’t able to find the magic configuration combination to get my server running right off the bat, I bet you won’t either. 

The good news: Getting the right configuration was trail-and-error process for me.  I kept the configuration very simple at first and then built upon it.  Hopefully the next steps can help you with your troubleshooting.

 

6. Start CruiseControl.NET Server

The CCNET Server is not started at the time of installation. Thus, you will need to start the service manually: Administrative Tools > Services > CruiseControl.NET Server > Select > Start the service.

If the service fails at startup, it will immediately stop and present the following generic dialogue:

The CruiseControl.NET Server service on Local Computer started and then stopped. Some services stop automatically if they have no work to do, for example, the Performance Logs and Alert service.

If you encounter this error your first stop is to consult the logs: C:\Program Files\CruiseControl.NET\server\ccnet.log. By default, the file contains verbose logging which is helpful (although somewhat difficult to navigate.)  Believe me, the logs are your fried.

Based on the log file feedback, I suggest tweaking the ccnet.config file and then restarting the service – repeating until the service is fully configured.  And, if it is easier for you, you may run the CCNET Server via the command window: CD C:\Program Files\CruiseControl.NET\server > ccnet.exe.  This approach will render errors in the cmd window rather than having to monitor the ccnet.log file.  It was a time saver for me at least.

Once the project is successfully setup, you will see something similar to the following listed in the logs:

· [CCNet Server:DEBUG] The trace level is currently set to debug. This will cause CCNet to log at the most verbose level, which is useful for setting up or debugging the server. Once your server is running smoothly, we recommend changing this setting in C:\Program Files\CruiseControl.NET\server\ccnet.exe.config to a lower level.

· [CCNet Server:INFO] Reading configuration file “C:\Program Files\CruiseControl.NET\server\ccnet.config”

· [CCNet Server:INFO] Registered channel: tcp

· [CCNet Server:INFO] CruiseManager: Listening on url:tcp://localhost:21234/CruiseManager.rem

· [CCNet Server:INFO] Starting CruiseControl.NET Server

· [PROJECTNAME:INFO] Starting integrator for project: PROJECTNAME

At this point, the Server is waiting to initiate the next build. Based on the config file <triggers> setting it could take a while to get the checkout and build to fire. Adjust the following setting to around 10 seconds while still in the testing phase:

<triggers>
  <intervalTrigger name=continuous seconds=10                   buildCondition=IfModificationExists/>
</triggers>

On a similar note, the Server restarts itself automatically each time the ccnet.config file is modified.

 

7. Potential Gotchas

I ran into a couple specific cases while debugging which I suspect could be common issues. 

1. Ensure the MSBuild timeout value allows enough time to the build to complete. This will otherwise return in a failure which wasn’t easy to troubleshoot.

<msbuild>
  <timeout>600</timeout>
</msbuild>

2. For web solutions, update the TargetPath for the Debug and/or Release build of the application to be outside of the source application directory. Otherwise, you will receive the following error:

ASPNETCOMPILER : error ASPRUNTIME: The precompilation target directory cannot be in the same tree as the source application directory.

This can be done by modifying the following in the solution file:

Debug.AspNetCompiler.TargetPath = “c:\ccnet\PrecompiledWeb\SampleWeb\”
Release.AspNetCompiler.TargetPath = “c:\ccnet\PrecompiledWeb\SampleWeb\”

Alternative, one may update the Output location found in the application MSBuild properties.

You may be wondering why an updated solution won’t be updated with the next scheduled build.  As it works out (and makes sense) only changes which are applied to source control are pulled onto the build box. 

 

8. Automating Your Builds

Once the build process is running successfully, modify the <intervalTrigger> setting to a reasonable value and then update the “CruiseControl.NET Server” Service Startup Type to Automatic and then Start the service.  I might suggest also crossing your fingers for the next day or so.

 

9. Monitoring Your Builds

The CCNet Web Dashboard Application is used for reporting a wide range of information. At one end of the scale it reports summary details of all projects being managed by CruiseControl.NET and at the other it can give specific metric output for any specific build.  The Dashboard is setup with your initial installation.  You may access the Dashboard application by navigating a location similar to the following: http://buildbox.com/ccnet/ViewFarmReport.aspx.  For more information on the Web Dashboard: http://confluence.public.thoughtworks.org/display/CCNET/Web+Dashboard

The CCTray an optional utility for use with the CruiseControl.NET Continuous Integration server. It provides feedback upon build progress, and allows control over some of the server’s operations.  As “optional utility” implies, the CCTray isn’t included with the base installation.  You may download the Windows Tray Application from the following location and install using provided default selection: http://downloads.sourceforge.net/ccnet/CruiseControl.NET-CCTray-1.3-Setup.exe?modtime=1182463076&big_mirror=0. There isn’t much to using the CCTray but I do consider it a handy add-on.  Basically, you will find a shortcut to the CCTray on your desktop. Launch the application to begin monitoring the automated build(s) status and schedule.  The information provides via the CCTray is very similar to that which is provided in the Dashboard application.  For more information on CCTray: http://confluence.public.thoughtworks.org/display/CCNET/CCTray.

 

Sample Configuration Files

If you have made it this far, I really, really hope your required configuration is similar to mine.  If so, this is your golden ticket.  I have provided two flavors of configuration files below. You will undoubted need to tweak the files a bit (replace the project locations and names along with credentials will obviously be required), but hopefully these will help get you started.  By the way, the formatting of the XML leaves something to be desires as I have formatted to fit within the given real estate.

 

Windows Service, StarTeam, MSBuild, Emailing and Unit Tests

<cruisecontrol>
  <project name=SampleService queue=Q1 queuePriority=0>
    <workingDirectory>c:\Projects\Services\SampleService
      </workingDirectory>
    <artifactDirectory>c:\ccnet\artifacts\Services\SampleService
      </artifactDirectory>
    <category>Continuous Builds</category>
    <webURL>http://buildbox.com/ccnet/server/local/project/
      SampleService/ViewProjectReport.aspx</webURL>
    <triggers>
      <intervalTrigger name=continuous seconds=600
                       buildCondition=IfModificationExists/>
    </triggers>
    <state type=state directory=c:\ccnet\state/>
    <labeller type=defaultlabeller>
      <prefix>Build-1.0.</prefix>
      <incrementOnFailure>false</incrementOnFailure>
    </labeller>
    <sourcecontrol type=starteam>
      <executable>c:\Program Files\Borland\StarTeam 2005\
        stcmd.exe</executable>
      <project>Project</project>
      <username>user</username>
      <password>password</password>
      <host>10.1.10.100</host>
      <port>11111</port>
      <path>Projects/Services/SampleService</path>
      <autoGetSource>true</autoGetSource>
    </sourcecontrol>
    <tasks>
      <msbuild>
        <executable>C:\WINDOWS\Microsoft.NET\Framework\
          v2.0.50727\MSBuild.exe
        </executable>
        <workingDirectory>C:\Projects\Services\SampleService
          </workingDirectory>
        <projectFile>SampleService.sln</projectFile>
        <buildArgs>/noconsolelogger /p:Configuration=Debug /v:m
          </buildArgs>
        <targets>Clean;Build</targets>
        <timeout>600</timeout>
        <logger>ThoughtWorks.CruiseControl.MsBuild.XMLLogger,
          C:\Program Files\CruiseControl.NET\server\
          ThoughtWorks.CruiseControl.MsBuild.dll</logger>
      </msbuild>
      <msbuild>
        <executable>C:\WINDOWS\Microsoft.NET\Framework\
          v2.0.50727\MSBuild.exe</executable>
        <workingDirectory>C:\Projects\Services\SampleService
          </workingDirectory>
        <projectFile>UnitTestBuild.proj</projectFile>
        <buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag
          </buildArgs>
        <targets>Tests</targets>
        <timeout>1500</timeout>
        <logger>ThoughtWorks.CruiseControl.MsBuild.XMLLogger,
          C:\Program Files\CruiseControl.NET\server\
          ThoughtWorks.CruiseControl.MsBuild.dll</logger>
      </msbuild>
    </tasks>
    <publishers>
      <merge>
        <files>
          <file>c:\ccnet\artifacts\Services\SampleService\
            mbUnit-testResults.xml</file>
          <file>c:\ccnet\artifacts\Services\SampleService\
            msbuild-results.xml</file>
        </files>
      </merge>
      <xmllogger/>
      <email from=no-reply@buildbox.com
              mailhost=localhost includeDetails=TRUE>
        <users>
          <user name=User 1 group=BuildMaster
                  address=user.one@buildbox.com/>
          <user name=user 2 group=TechLead
                  address=user.two@buildbox.com/>
        </users>
        <groups>
          <group name=BuildMaster notification=always/>
          <group name=TechLead notification=change/>
        </groups>
      </email>
    </publishers>
  </project>
</cruisecontrol>

Web Application, StarTeam, MSBuild, Emailing, and Build Dependencies

<cruisecontrol>
  <project name=SampleWeb queue=Q2
           queuePriority=1>
    <workingDirectory>c:\Projects\Web\SampleWeb
      </workingDirectory>
    <artifactDirectory>c:\ccnet\artifacts\Web\SampleWeb
      </artifactDirectory>
    <category>Continuous Builds</category>
    <webURL>http://buildbox.com/ccnet/server/local/project/
      SampleWeb/ViewProjectReport.aspx</webURL>
    <modificationDelaySeconds>15</modificationDelaySeconds>
    <triggers>
      <intervalTrigger name=continuous seconds=3600
                       buildCondition=IfModificationExists/>
      <projectTrigger project=SampleData>
        <!– Force build when data component is successfully built. –>
        <triggerStatus>Success</triggerStatus>
        <innerTrigger type=intervalTrigger seconds=30
                      buildCondition=ForceBuild/>
      </projectTrigger>
    </triggers>
    <state type=state directory=c:\ccnet\state />
    <labeller type=defaultlabeller>
      <prefix>SampleWeb-Build-</prefix>
      <incrementOnFailure>true</incrementOnFailure>
    </labeller>
    <sourcecontrol type=starteam>
      <executable>C:\Program Files\Borland\
        StarTeam Cross-Platform Client 2006 R2\stcmd.exe</executable>
      <project>Project</project>
      <username>user</username>
      <password>password</password>
      <host>10.1.10.100</host>
      <port>11111</port>
      <path>Projects/Web/SampleWeb</path>
      <autoGetSource>true</autoGetSource>
    </sourcecontrol>
    <tasks>
      <msbuild>
        <executable>C:\WINDOWS\Microsoft.NET\Framework\
          v2.0.50727\MSBuild.exe</executable>
        <workingDirectory>C:\Projects\Web\SampleWeb
          </workingDirectory>
        <projectFile>SampleWeb.sln</projectFile>
        <timeout>900</timeout>
        <buildArgs>/clp:PerformanceSummary /verbosity:d
          </buildArgs>
        <logger>C:\Program Files\CruiseControl.NET\server\
          ThoughtWorks.CruiseControl.MsBuild.dll</logger>
      </msbuild>
    </tasks>
    <publishers>
      <xmllogger />
      <buildpublisher>
        <publishDir>c:\ccnet\artifacts\Web\SampleWeb</publishDir>
        <useLabelSubDirectory>true</useLabelSubDirectory>
      </buildpublisher>
      <email from=no.reply@buildbox.com
              mailhost=localhost includeDetails=TRUE>
        <users>
          <user name=User 1 group=BuildMaster
                  address=user.one@buildbox.com/>
          <user name=user 2 group=TechLead
                address=user.two@buildbox.com/>
        </users>
        <groups>
          <group name=BuildMaster notification=always/>
          <group name=TechLead notification=change/>
        </groups>
      </email>
    </publishers>
    <externalLinks>
      <externalLink name=Sample Web
             url=http://buildbox.com/SampleWeb/default.aspx />
    </externalLinks>
  </project>
</cruisecontrol>


Coping with Windows Auth

30

August

There are a few primary reasons why Windows Authentication should be considered a best practice. Since passwords aren’t visibly exposed in configuration files and credentials are not sent over the network, your systems tend to be more secure.  Additionally, password management (expiration periods, minimum lengths and account lockout after multiple invalid logon requests) becomes a heck of a lot easier. Considering the benefits, I have no issues with applications accessing SQL Server using Integrated Security, however, I think there is a big different between application access and developer access. 

Really quickly, you can setup SQL Server to run in one of two security modes: Windows Authentication or Mixed Mode.  Mixed Mode is exactly as it implies and allows users to connect using Windows NT Authentication or using SQL Server Authentication.  I’m a fan of Mixed Mode which allows for application accounts to reap the benefits of Integrated Security while allowing considerably easier SQL Auth access for developers, support personnel, etc. 

Please consider the following scenarios: 

  1. An instance of SQL Server is setup in the Development Environment and it isn’t running in Mixed Mode.  This implies that one needs to be a member of the appropriate domain and have appropriate permissions in order to access the SQL Server.  Not a big deal, right?  Well, I would agree if I were a developer working onsite and the Dev Network was readily available to me. But I happen to work remotely on occasion and there isn’t an entrance point into this particular domain through VPN.  Boy, SQL Authentication sure would come in handy in this case. 
  2. Let’s say your environments (perhaps Dev, QA and Production) are hosted in separate domains.  It would be painful to switch between domains in order to access each SQL Servers, wouldn’t it?  (I know what you are thinking, “Why would a developer need to access QA or Production?”  Special assignment.  Let’s leave it at that.)

Fortunately, there’s a workaround.  If you are me, you beg and plead and moan and request that security mode be changed (not that that’s easy.) OR you discover an even better solution in the appropriately named RunAs command which allows a user to run specific tools and programs with different permissions than the user’s current logon provides.  

The following are a few of  my favorite commands which I’ve wrapped up neatly in their own .cmd file for quick execution (you will need to update the domain and user values accordingly):

  • runas /user:domain\user “C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\ssmsee.exe”
  • runas /user:domain\user “C:\WINDOWS\system32\mmc.exe /s \”C:\Program Files\Microsoft SQL Server\80\Tools\BINN\SQL Server Enterprise Manager.MSC\”"
  • runas /user:domain\user isqlw

This tip actually came from a wise, remote developer working in Canada who was confronted with Scenario 1 above.  Pretty neat, eh?


Work With Delimited Files Using CSV Reader

21

November

Over the last few years, most of my development efforts have been focused on financial applications.  Often it is my job to make the analysts’ lives “easier” by providing online tools to help better manage their data. But as many of you know, financial analysts love spreadsheets and the majority of information is stored and shared via CSV files. With this in mind, even the slickest of applications must incorporate the use of spreadsheets or it isn’t going to be quickly or happily adopted.

Recently, I was introduced to CSV Reader.  It’s a .NET class which provides a fast and reliable way to handle stream based parsing of virtually any delimited data format. 

Parsing is done using de facto standard CSV file specifications which give you the ability to open, edit and save CSV files directly from your code. 

Additionally, the latest version of the product introduces the CsvDataReader class which simplifies the common task of bulk inserting CSV data into SQL Server. This class provides on-the-fly data validation and manipulation using the ReadRecord event.

With this said, CSV Reader was designed for speed. The product site touts that data can be parsed in less than half of the time of any other parser it has been benchmarked against.

I downloaded the demo version of the library and I was impressed by its ease of use. The product site provides sufficient examples and the sample project (in C# and VB) provides a glimpse into the CSV Reader’s performance. I didn’t test the edit/save feature, but in conjunction with the snappy file parsing, this product may be a worthwhile investment.

Check out the CSV Reader and decide for yourself.

This was a paid review.


Data Dictionary Creator 1.2 On CodePlex

15

November

I had the opportunity to work with Jon Galloway on his Data Dictionary Creator tool recently. It was a good time.

We just released Data Dictionary Creator version 1.2 to CodePlex. Version 1.2 adds a lot of great features:

  • Added documentation of tables as well as columns
  • Changed Excel export from HTML based to XMLSpreadsheet to support separate worksheets for Table and Column documentation
  • Improved error handling - detection of non-DBO logins, etc.
  • (UI) - tab reorganization to fit workflow a little better
  • (UI) - moved feedback and progress bars to statusbar for consistency
  • Support for SQL 2000 and 2005 export scripts (there were several breaking changes from 2000 to 2005)
  • Limited import functionality (SQL and XML)
  • Added an Installer

As Jon says, it is worth a look:

DDC is a nice utility to help you document your databases. Even if that kind of thing doesn’t appeal to you, you might want to check out the code if you’re at all interested in using SQL Server Management Objects (SMO) or saving data to multiple formats (Word via WordML, Excel SpreadsheetML, HTML) using XSLT.

Want to learn more? Jon put together an excellent walkthough which can be found on his blog or on the Codeplex Wiki.


IE7 Support For Alpha Transparency In PNG Files

08

November

I have preferred PNG over GIF and JPEG for sometime now.  It isn’t that I’m an expert on image types, but I know that PNG files are generally smaller in size than GIF and they have consistently rendered nicely for me in Firefox and IE, so I stick with them.  

With this said, my faith in PNG had been shaken since working with Windows Live Writer.  If you have ever tried to insert an image into a post using Windows Live Writer you know that PNG is not included in their default  filter.  At first, I just got really frustrated because it took an extra click to get my job done.  Under my breath I’d curse the Windows Live Writer development team and say, “I don’t care if it is a beta release or not, somebody seriously messed up here.  How could a legitimate web-related product not automatically include PNG in their image list? ”  After a dozen or so posts, however, I started to doubt myself.  And I started doubting PNG.  After all I’m not a graphic designer (nor a web designer for that matter.)  Maybe I’m simply oblivious to the very good reason why Windows Live Writer is causing me such heartache.

Tonight I went looking for answers and I now believe my frustration has merit.  I didn’t realize it, but, Internet Explorer (like Windows Live Writer) has never fully-supported PNG and this has caused quite a lot of commotion amongst the web design community for some time now.  As I understand it, there are three arguments included in the petition for Proper PNG Support in Internet Explorer for Windows:

1. PNG is Superior to the GIF
When the same image is saved in both PNG and GIF formats, in an editor with full and proper support for both formats, the PNG image is typically a smaller file size, is free from royalties, patents, and copyright restrictions that hinder the GIF format, and can use more than 256 colors - up to 48-bit color.

2. PNG is a World Wide Web Consortium (W3C) Recommendation

Microsoft has repeatedly stated their renewed commitment to web standards, so implementing full PNG support would be the next logical step in fulfilling this promise, especially since it was supposed to be implemented over 10 years ago.

3. PNG Supports Alpha Transparency
Anybody who has designed images for use online knows the woes of trying to make that image appear smooth on any background. Some designers create different images to be used on different background colors, other designers simply leave the edges jagged, and still others just give their images a solid background. It’s a bad way to go, but it’s the only choice right now. Using PNG images with alpha transparency would eliminate all of these problems, and make the work of web designers a lot easier. 

To further explain the difference between PNG Alpha transparency and GIF transparency, a GIF image pixel is 100% transparent or 0% transparent. There is no middle ground which tends to lead to grainy-looking graphics in some cases.  Alpha transparency, on the other hand, allows for pixel transparency to range from 0% to 100%.  This allows one to blend images together much easier and create a more seamless look.

There’s some really great information on this subject available here and  here   Now that I know more about its history, the added PNG support with IE7 is worth mentioning.  Of course, I’m hopeful that the Windows Live Writer team will be influenced as well and I’m a just few clicks away from having my favorite image type included in the default filter with WLW’s next release.


SubSonic - Another Look at Code Generation

05

November

Last month, I wrote Manual Code Generation, an article which shared, in my view, the pros and the cons of code generators.  In this same article, I took sides and expressed that “I am not a fan of code generation.”  My stance came as no surprise to some — particularly my buddy (read archenemy) Jon Galloway.  We’ve gone back and forth on this topic for a few years now so, of course, Jon replied to my post with arguments in favor of code generation.  Along with arguments, he also offered a few suggestions; the best of which was to check out SubSonic.  Actually, Jon simply asked, “Have you checked out  SubSonic?”  but I know this was just his polite way of asking me to please check it out before I continued to publicly embarrass myself by making bold statements about things which I have fairly little exposure simply because I effectively dismissed them years ago.  

I have now checked out SubSonic.  In an effort to get in the last word, here’s my review:

First Impressions

The SubSonic project is hosted on CodePlex.  If you are not familiar, CodePlex is Microsoft’s open source project hosting web site. You can use CodePlex to create new projects to share with the world, join others who have already started their own projects, or use the applications on the site and provide feedback. Through CodePlex your project team may manage news feeds, releases, discussions, issues, source code and licensing.  I know this is a review of SubSonic, but CodePlex is worth talking about (especially since it helped make a good first impression.)

Nearly Everything You Need To Know

The project’s main page has nearly everything one needs to get started:

Product Overview 

The overview provides a very quick description of the product’s core feature list.  To be honest, I wish more detailed information was provided here, but I think I got the gist.  At its essence, SubSonic includes:

  1. A Data Access Layer (DAL) Builder which generates CRUD-enabled objects (which, in turn, represent selected database tables) and complementary strongly-typed collections.
  2. A complete utility toolset complete with Rails-like scaffolding which effortlessly builds admin-like web pages, migrations or DB versioning and code generators.
  3. A dynamic query tool that lets one use SQL Server, mySQL and/or Enterprise Library without having to know the underlying SQL syntax.
  4. An object-relational (OR) mapper which extends to stored procedures and views.

My one recommendation would be to elaborate on the feature set and tell a little more about the product in the overview.  Answer questions like “Why was this effort undertaken?” and ”What problem does SubSonic solve?”  That sort of thing.  I will get into this a bit more in the Webcast section, but I think the “Welcome to the ActionPack for .NET!” content found on the sample website default page would be a nice addition to the project main page. 

Source Code Download 

SubSonic 1.0.5 was recently released on 10/24/2006.  It’s a 1.3 MB .zip file download which includes the complete SubSonic Actionpack, Sample Website and Dependencies.  A double-click on the unzipped solution file, a quick update to the Northwind connection string and I was up and running.  You can’t beat that.

Starter Site Download 

Latest version of the starter site project was released on 10/24/2006 as well.  It came packaged up as a .vsi (Visual Studio Content Installer) file which, unfortunately, failed when I attempted to run it  [1].  As I mentioned previously, the Sample Website source code was provided which I’m guessing is what would come along with the Starter Site so I was still in business.

Webcast 

This demo was a treat.  I am so pleased I spent the time to watch it.  Not only did the webcast walk through highlighted functionality, but, in my opinion, it gave the product a “story.”  You see, when I am at a gallery or museum, I tend to spend more time reading about the art/artist then actually admiring the work itself.  I have a hard time appreciating a painting until I understand its background.  I really like to know what the piece represents and what drove the artist to create it.  That’s what the 20-minute webcast gave me.  It gave SubSonic a personality.  It also more deeply shared the philosophy behind the product which is Rails.  Though the written overview touched upon elements of Rails (scaffolding), the demo touched upon one of its guiding principles (Convention Over Configuration) and base architecture (MVC, model-view-controller) in the words of the author.  If you are interested in trying out the SubSonic ActionPack you should absolutely watch the webcast.

Playtime

Now that SubSonic was running on my machine, it was time to start playing around.  I started with the basics which was basically everything which was discussed in the demo. 

BuildProvider Class

If it hasn’t been mentioned already, SubSonic takes advantage of  a new feature in .NET 2.0, the System.Web.Compilation.BuildProvider Class, to generate the DAL at compile time.  There’s good reason why I’m placing a lot of  emphasis on the use of the BuildProvider: First, you are generating and working your code within the same tool – Visual Studio. Also, your code is generated automatically when you build your application.  This means your application code and generated code will never be out of synch again. Finally, I wasn’t previously familiar with the BuildProvider class, thus it made SubSonic a great learning tool.

I should mention that the generator is wired up really nicely and you don’t actually need to know a thing about the BuildProvider.  All you need to know is classes/collections will be generated for tables listed in the App_Code/builder.abp file.  You can even keep the default (not touch a line of code) and generate classes for all tables.

Additional Documentation

I built the project and clicked through the Sample Website.  Again, I really like the content on the default page so be sure to spend some time here.  I then breezed through the short tutorials found in the “Setup” and “CRUD” sections since the WebCast had already provided me with the basics.

Data Access Layer

My main interest was working with the generated DAL.  Therefore, I spent the majority of my time in the “Query the DB” section.  I did encounter an issue with the “Use a Collection” example, but otherwise the samples provided for a great testing grounds [2].

At first glance, I personally thought the provided examples were dumbed down a little too much.  Sure, they were enough to get one started, but they didn’t go beyond the bare essentials. 

For example, what if one wishes to filter their result set by more than one criterion.  How is this done?  After fiddling around a bit, I discovered this is as easy as making more than one call to the Query object’s AddWhere() function, but I wouldn’t have known without some experimentation.

Actually this is a nice segue. 

Knowing SubSonic

I’ve commented in the past that generated code is difficult to write and maintain unless you have a firm, working knowledge of the code generation tool itself.  What I mean by this is the generated code (in this case the exposed functions and methods available in the SubSonic DAL) uses custom syntax which one can only learn through using the tool and generated objects. 

The Query object’s AddWhere() function acts a good example.  Though it’s easy to query on multi-parameters, you have to learn SubSonic’s language before knowing how to do so.  This makes for an interesting point.  The documentation states that SubSonic “lets you use SQL Server and the Enterprise Library without having to know SQL.”  Though this is true, instead of learning SQL, you need to learn SubSonic’s language.  

Sticking to Conventions

To the creator’s credit, it appears that time was dedicated to making the tool and, in turn, the DAL consistent and intuitive.  SubSonic is a working example of  “Convention Over Configuration”  which makes learning how to use the product a lot easier.  There are numerous examples of this throughout the code, but most glaring is the decision to use singular, rather than plural, forms of object names.  Even if the underlying database table is named Products (plural), SubSonic is configured to generate a ProductCollection rather than a ProductsCollection.  Once you start understanding SubSonic’s conventions and patterns, you can start to navigate around the codebase with more confidence. 

(Of course, I had to look at the PluralToSingular utility function.  It will work in most cases, but the ever-present Octopi table is going to cause problems.)

Writing SubSonic

One big code generation con, in my opinion, is that someone has to spend time writing the code.  Though my point holds water, Jon argued that someone has already written SubSonic so this shouldn’t be a problem for me.  Well, maybe I’m too picky, but I’ve found that most software doesn’t do everything that I want or need and I wind up at least tweaking the generated classes/collections. 

For example, I like to be able to access collection items by key as well as by index.  The CodeSmith implementation, which I mentioned in my earlier write-up, didn’t provide this functionality.  Additionally, functions like Exists() weren’t available either.   If I recall, these custom collections were inheriting from System.Collections.CollectionBase which isn’t fall that full-featured.  SubSonic’s generated collections are a bit more robust (they inherit from System.Collections.Generic.List ) but I still can’t access, add or remove an item from the collection by key.  In the end, even though someone has already written the code, I will also need to spend time writing code if I would like this functionality. 

Code Regeneration

With this said, I wouldn’t necessarily have to modify the code generator itself.  Since SubSonic takes advantage of partial classes, I could easily maintain app-specific collection code with no concern that it would be over-written with the code generated by the next compile.  Along these lines, as Jon pointed out, SubSonic does support handcrafted code very well.  Subsonic also supports database changes as the DAL is safely regenerated when the project built.

DAL Focused

If you use the provided scaffolding model you will find it can quickly generate admin pages based on a database table and the associated DAL objects.  In the example project, scaffolding is in place to administer the Products table. What one gets out-of-the-box with this example is a list of all products along with a link add or edit. On the edit page, one may modify any of the field values (with the exception of an identity column.  Item deletion is done on the edit page as well.

Though scaffolding is in place to quickly generate admin pages, the presentation layer is not the ActionPack’s focus.  SubSonic’s bread and butter truly is the DAL which I consider a very wise approach to code generation.  In fact, in the demo, it even suggests that CRUD scaffolding should be considered for developer use only as it is presumably non-performant. I have to give SubSonic’s team a lot of credit for making scaffolding available yet sharing the limitations openly and not pushing this feature down the throats of end users.  I also really respect the decision to focus heavily in one area (the DAL), making it really solid, and not get distracted by other not-as-important features.

Keep It Simple, Stupid 

SubSonic’s DAL architecture follows the KISS principle which I admire.  For example, though the Northwind EmployeeTerritories table establishes an obvious relationship between Employees and Territories through foreign key constraints, the DAL doesn’t.  One might assume the Employee object would own an internal Territories Collection, but it doesn’t.  SubSonic generates separate objects for each database table and they are managed completely separate in the DAL.  Period. 

I may be wrong, but I believe this means one would have to do the following in order to display the names of all Territories for Employee with the last name Griswold.

  1. Fill an EmployeeCollection where last name = Griswold
  2. Fill a EmployeeTerritoryCollection reference for each Employee.EmployeeID in the EmployeeCollection.
  3. Fill a TerritoryCollection for each EmployeeTerritory.TerritoryID in the EmployeeTerritoryCollection.

You may be thinking, “That’s not exactly simple.”  Well, you are right and you’re wrong.  The object model is simple and for 90% of what needs to be coded in a given application this is more than adequate.  Again, SubSonic keeps it simple and it’s objects are generated to meet the most-likely conditions — not the exception. 

That being said, one might consider using SubSonic’s Query Object to build the necessary SQL to populate the TerritoryCollection right off the bat, I’m not sure this is possible since the query would require joining at least two tables. 

On the surface this appears that we’re ina quite the predicament about 10% of the time, but SubSonic has an answer.   Which bring us to potentially my favorite feature… 

Using Stored Procedures

In the cases where you aren’t able to use Query Object and you aren’t able to leverage the Fill methods exposed in the collections, you can fall back to using stored procedures.  This will help you do whatever is needed.

I thoroughly appreciate SubSonic’s stance on the use of stored procedures. Basically, if you want to use them, the DAL provides ample support. (Each stored procedure in the database is wrapped in their own custom, publicly available function.) If you don’t want to use SPs, that’s fine too.   Make no mistake about it, however.  This product’s concentration is on building dynamic queries which is smart for a performance and usability stand point.

I’ve used code generation tools which attempt to generate a stored procedure for every CRUD condition which could be dreamed up.  I found that most of the routines performed just fine.  After all, it is difficult to slow down a query which pulls back a single row filtered on a clustered index.  However, other stored procedures tried to do too much.  For example, the routine which accommodated for filtering results on one or many fields through the use of “like” and “coalesce()” abused the SQL Server.  It is this type of performance nightmare which SubSonic cleverly avoids by, first and foremost, generating SQL and but also by making existing SPs available. 

One comment about the generated SQL:  Dynamic SQL has raised a lot of red flags because of SQL injection concerns, but SubSonic is actually leveraging parameterized queries which are a safe “dynamic” SQL implementation.  For example, ”select productname from products where productid = @productid;” is generated.  Prior to execution, the @productid parameter value is provided to the Command object.  This technique is as safe from SQL injection as a properly coded stored procedure simply because there is no room for injection.  Try to maliciously hack code into the @productid parameter and the command will fail entirely.

I had a chance to take a look at the algorithm to build SQL strings.  It is far less code than I expected and, as a matter of fact, it is here where I stumbled across a couple lines of code which made this entire review worth while.  Per the comment, the author really liked it too.  

   1:  //the following line is my favorite… Moe, Larry, Curly…
   2:  foreach (Where wWhere in qry.wheres) {
   3:  
   4:  }
    

Wrap Up 

After spending a few hours with the SubSonic, I don’t think its name does it justice.  I’m not saying the tool deserves to be called SuperSonic just yet, but Sonic seems perfectly reasonable.  If one were to draw a line in the sand, you still won’t find me on the side with the code generator advocates.  Maybe I’m straddling the line?  After all, I’d have to be a fool not to at least keep my eye on a tool which could potentially decrease my coding (and troubleshooting) time.  For now, let’s say that SubSonic has definitely gotten my attention.

Footnotes 

1: Installation of StarterKit Failed: Installation stopped because the directory for the ProjectType value did not exist. The project type is invalid for your installation of Visual Studio.

2: Query the DB > Use a Collection Error: Disallowed implicit conversion from data type varchar to data type money, table ‘Northwind.dbo.Products’, column ‘UnitPrice’. Use the CONVERT function to run this query.


Why Did I Start Using FeedBurner?

02

November

First, what is FeedBurner?  At it’s core, FeedBurner republishes blog feeds.  This alone isn’t all that exciting, however, the service provides so much more.

FeedBurner’s most attractive feature is it’s analytics.  The service keeps track of feed subscribers, applications used to access your feed, where your readers are located and a few other statistics. 

Not only does FeedBurner manage your analytics, it also helps build your user base by introducing easy ways for readers to subscribe to your feed (via RSS, HTML and/or email) and by submitting your posts to numerous search engines for easy indexing.  And, of course, there’s the attractive FeedBurner counter you see on everyone’s site these days.  I mean, who can resist clicking on that little baby?

FeedBurner presumably maintains your reader base as well.&nb