Browsing Posts in .NET Tools

Did you know that you can get Visual Studio Intellisense support when editing NHibernate’s configuration and mapping files?* Simply drop nhibernate-configuration.xsd and nhibernate-mapping.xsd from the NHibernate zip file into:

C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas

or

C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas

Once you’ve got the XML Schemas in the right location, you should see something like this when editing NHibernate configuration and mapping files…

NHibernateIntellisense

(The little light bulb is ReSharper 3.0 suggesting a Quick Fix to split the empty XML tag into start and end tags.)

* This XML Intellisense trick works for any XML Schema (XSD) file.

N.B. Dropping your XML Schema files in the similarly named C:\Program Files\Microsoft Visual Studio 8\Common7\Packages\schemas\xml does absolutely nothing!

I created a few simple ReSharper templates to make working with NHibernate and Castle ActiveRecord easier. They currently default to SQL Server 2005 because that’s what I do most of my work against. Feel free to customize to your heart’s content.

You can grab them from here. Simply import the templates into ReSharper via ReSharper… Options… Templates… Live (or File) Templates… User Templates… Import Templates from File… You’ll want to add the file templates to your Quick access list.

The first file template is hibernate.cfg.xml. (N.B. ReSharper will try to name it hibernate.cfg1 and add the xml extension. Delete the “1″ and hit enter.) The template will prompt you for the database server, database name, and mapping assembly.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="hibernate.connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="hibernate.connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="hibernate.connection.connection_string">Data Source=localhost;Initial Catalog=DATABASE;Integrated Security=True</property>
    <property name="hibernate.dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="hibernate.use_outer_join">true</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <mapping assembly="SimpleConfiguration"/>
  </session-factory>
</hibernate-configuration>

The second file template is <Class>.hbm.xml. You will want to rename it <Class>.hbm as ReSharper will add the xml extension for you. The template will prompt you for the class name and primary key name. You’ll also want to modify the PK generator. You’ll note that default-access is “field.pascalcase-m-underscore”, which means that if you map a property called “Name”, NHibernate will access it by the corresponding field name, “m_Name”. Change your default-access to whichever naming convention you prefer. (See property access and naming strategies in the NHibernate documentation.)

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="SimpleConfiguration"
                   assembly="SimpleConfiguration"
                   default-access="field.pascalcase-m-underscore"
                   default-lazy="false"
                   default-cascade="none" >
  <class name="CLASS">
    <id name="PRIMARYKEY">
      <generator class="assigned" />
    </id>
  </class>
</hibernate-mapping>

Lastly we have the Live template for Castle ActiveRecord configuration. You can insert this into app.config or web.config. Simple position your cursor inside <configuration> and type arconfig<TAB>. If you already have other configuration sections, you’ll have to merge the activerecord section with the others.

<configSections>
    <section name="activerecord"
             type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord" />
</configSections>
 
<activerecord>
  <config>
    <add key="hibernate.connection.driver_class" 
         value="NHibernate.Driver.SqlClientDriver" />
    <add key="hibernate.dialect"                 
         value="NHibernate.Dialect.MsSql2005Dialect" />
    <add key="hibernate.connection.provider"     
         value="NHibernate.Connection.DriverConnectionProvider" />
    <add key="hibernate.connection.connection_string" 
         value="Data Source=DBSERVER;Initial Catalog=DATABASE;Integrated Security=SSPI" />
  </config>      
</activerecord>

Enjoy!

The ALT.NET Open Space Conference in Austin has come to a close. It was a fantastic experience. I had an opportunity to connect with many people whose books I have read and tools I use. Thanks to everyone who came for sharing their time and knowledge. Given that I’m used to wearing the presenter hat, it was a refreshing change to attend a conference where the purpose was to discuss and question our core tenets. Which brings me to…

What is ALT.NET? This continues to be a hotly debated topic – before, during, and after the conference. My own take… ALT.NET is about considering alternatives, it is not about being alternative. It is about taking the best frameworks and tools from Microsoft, third-parties, and the open source community to build an application that is maintainable. It is not about being anti-Microsoft. Scott Hanselman suggested that Pragmatic.NET might have been a better name. I would tend to agree. At heart, everyone there was a pragmatic developer. (If you have not read The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt and David Thomas, you really should.) It’s about thinking outside the Microsoft MSDN canon when building software.

What I find truly amusing is that, as far as I can tell, Microsoft has not attempted to create a canon. The collective knowledge has been created by regular people like us and people are fallible. Ideas that seem good at first may not stand the test of time. (DataSets/DataAdapters are a great example of an idea that in hindsight isn’t such a great one.) Microsoft is very open to better ways of developing software, as evidenced by the fact that many Microsoft employees attended. What many perceive as hostility to the community is more often disconnection from the community. But the honest truth is that they want to engage with us. I had great conversations with Simon Guest (Architecture Strategy Team), Howard Dierking (Editor in Chief of MSDN Magazine), Scott Guthrie (DevDiv), Peter Provost (P&P Team) Scott Hanselman (newest member of the Borg), and many other ‘softies about the values of the ALT.NET community and how Microsoft technologies support or hinder the development of maintainable software. (My intended purpose isn’t name dropping, but to show you, dear reader, that it’s the movers-and-shakers in Microsoft who are interested in providing a better development experience. These are the people who shape the platform and its documentation.)

Some people, who didn’t attend, have claimed that the conference was cliquey; that it was a venue for like-minded developers to say, “I do TDD.” and another developer to say, “Hey, cool. I do TDD too. You’re awesome.” On the contrary, the purpose was to foster better understanding of new techniques, such as BDD, specifications, domain-specific languages, FIT, etc. The conversations all started with a mutual understanding of what we were trying to achieve – more maintainable software supported by appropriate test artifacts.

For example, there was a lot of discussion around specification languages (like NBehave) were valuable compared with a written story on an index card. A written story is approachable by a non-technical business stakeholder and can elicit a discussion that might not otherwise happen. A specification written in C# (or Ruby) sitting in a source control system is not approachable by the non-technical business stakeholder. The answer is it depends on the individuals involved in the project. Each technique causes friction and your choice depends on which type of friction results in less project risk.

Another topic that has been widely reported is Scott Guthrie’s first public demonstration of the new ASP.NET MVC Framework. There were some pleasant surprises, including:

  • Microsoft’s commitment to testability. Controllers interact with the ASP.NET pipeline through IHttpRequest/Response rather than HttpRequest/Response. That little “I” allows us to mock out the dependency on the HTTP pipeline and run controller tests without all the ASP.NET hosting infrastructure. (ScottGu is looking to port those interfaces back into ASP.NET WebForms too.)
  • Microsoft will provide easy integration with a variety of other frameworks. For instance, if you want to mock a dependency, you can use Rhino Mocks, NMock, or TypeMock. If you want to use an inversion of control (IoC) container, Microsoft will allow you to bolt in Castle Windsor, Spring.NET, StructureMap, or ObjectBuilder. The team is even planning on providing templates for these open source frameworks. Microsoft is working with the community rather than trying to compete against it.
  • ScottGu’s team is not trying to wedge MVC into the existing WebForms model. If you use MVC, you are opting out of viewstate, postbacks, and the dreaded ASP.NET Page lifecycle. This is a brave move to make. WebForms will still work as it always has, but if you choose MVC, you will use a new set of controls specifically designed for the MVC model.
  • The bi-directional routing engine looks awesome. It allows for very flexible and human-readable URLs. The use of lambdas to create URLs was very cool.
  • The default view engine is ASP.NET. So you get all the design-time, CSS, and Intellisense support, but without the complex ASP.NET Page lifecycle, as noted above. You can easily create typed view data to communicate between your controller and view. (In MonoRail, the controller and view communicate via an untyped property bag. So you don’t get Intellisense and refactoring support.)

Overall, the design of ASP.NET MVC looks a lot like Castle MonoRail and has aspects of Ruby on Rails and Django sprinkled in. I’m looking forward to watching this technology develop. Jeremy Miller echoes my sentiments when he says, “I’m more excited about an upcoming Microsoft technology than anything else since moving from VB6 to .Net.” If you know Jeremy, he’s a hard developer to impress. So that says a lot!

There was so much more. I’ll try to put my thoughts around other discussions in the coming days as I mentally digest everything that was discussed. I’ll leave you with some personal highlights:

  • I enjoyed finally meeting Jamie Cansdale (TestDriven.NET) and hearing that he and Microsoft had come to an amicable agreement over TestDriven.NET.
  • It was great to meet Jay Flowers and thank him for all his great work on CIFactory. I even convinced him to implement an option in CIFactory to flip from using the command-line, CCNet.exe, to the Windows Service, CCNetService.exe.
  • Rock climbing Saturday night with Scott Hanselman, Russell Ball, and others was a blast. I didn’t feel like “a monkey with fly paper gloves”, but it was still a lot of fun. Maybe I’ll take it up as a hobby… 
  • Talking to Martin Fowler over dinner about the challenges in parallel computing. He said, “Concurrency is a lot like a white fluffy bunny…” at which point he leapt up and down wildly yelling, “with fangs and a mean streak a mile wide!!!” (Fans of Monty Python’s The Holy Grail will understand the reference. If you don’t, go rent the movie right now.)

The website is now live and accepting registrations. We’re accepting 100 lucky participants to take part in this unique event. Sign up now at http://www.altnetconf.com. If you don’t know what I’m talking about, go back and read this. Hope to see you there!!!

Coming to Austin, TX… October 5-7, 2007… Brought to you by the NHibernate Mafia themselves… 3 days of ALT.NET mayhem… See behaviours twisted, tests tortured, dependencies injected, object-relations mapped, and DSLs like you’ve never seen them before…

More seriously, what exactly is ALT.NET? David Laribee coined the term to describe developers who look outside the “official gospel” for ideas of how to develop software better.

  1. You’re the type of developer who uses what works while keeping an eye out for a better way.
  2. You reach outside the mainstream to adopt the best of any community: Open Source, Agile, Java, Ruby, etc.
  3. You’re not content with the status quo. Things can always be better expressed, more elegant and simple, more mutable, higher quality, etc.
  4. You know tools are great, but they only take you so far. It’s the principles and knowledge that really matter. The best tools are those that embed the knowledge and encourage the principles (e.g. ReSharper.)

Scott Bellware has assembled an all-star organizing committee, including:

The conference will be run in an open space format, which is very agile in nature and execution. Fundamentally OpenSpace is a conference with self-organizing sessions. If you have an idea for a session, you post it on the schedule. If you see a session that interests you, you show up. If that session sparks an idea you’d like to talk about, post your new session on the schedule. Lather, rinse, repeat… This will be my first time participating in an OpenSpace conference, but I’m excited by the concept.

You can expect topics covering:

  • Software design
  • Testing strategies and continuous integration
  • Test-Driven Development (TDD)
  • Behaviour-Driven Development (BDD)
  • Domain-Driven Development (DDD)
  • Domain-specific languages (DSLs)
  • Object-relational mapping (OR/M) using NHibernate
  • Dependency injection with Castle Windsor
  • Web development with MonoRail
  • Agile team practices, such as XP and Scrum
  • Plus anything else that attendees want to discuss

The Important Stuff

Cost: FREE! (except for the cost of airfare and accommodations)
Location: St. Edwards University Professional Education Center, Austin, TX
Date: Friday, October 5th, 2007 @ 5pm to Sunday, October 8th, 2007 @ noon
Attendance: 100 (max)
Registration: http://www.altnetconf.com

If you are interested in attending the event or would like to know more, please don’t hesitate to contact me or one of the other organizers.

(via Jean-Paul Boodhoo)

Manoj Khanna just created the Calgary Open Source Group specifically to foster the use of open source software in the Calgary market. Here is the group’s mandate:

“Calgary Open Source Group (COSG) is a forum that promotes the spread of Open Source Software and Free Software culture in Calgary. Through lively debate/talks, presentations and interactive network events, COSG aims to showcase the potential of open source software development and the impact it may have on software engineering for companies based in the oil city.”

Given the amount of open source software that I use in my day-to-day development and the fact that I often promote good open source tools in my presentations, I thought it only appropriate to join the group myself. So I’m member #3 right after Manoj and JP. I look forward to contributing to the community by promoting the adoption of open source tools where appropriate. Hopefully we can organize some presentations specifically around high quality open source tools for .NET development, especially for agile development. (Honestly, most of the great agile development tools – minus JetBrains ReSharper – come from the open source community.)

I spent some time troubleshooting a Subversion failure. I created a new repository using CreateSvnRepo.ps1 and successfully fetched the contents using TortoiseSVN. I added some files and then tried to commit the changes, but I got this highly cryptic error message:

Error: Commit failed (details follow): 
Error: Authorization failed 

The causes of this generic error are many and varied. So googling did not pinpoint the problem. I tried turning authorization off in the conf\svnserve.conf. Same result.

Now that was really odd. I turned off authorization, but authorization was still failing for writes. After a bit of head scratching, I noticed this:

SvnServeConfError

Thank you Notepad2! The character encoding was set to Unicode and svnserve.exe was choking silently on the encoding. Without a readable svnserve.conf, it was using defaults, which allow anonymous reads, but not writes. That’s why I was able to fetch the repository, but not write to it. Switching the character encoding to ASCII solved the problem. Here is the offending line in the PowerShell script:

“[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`nrealm=Default`r`n” > $repoConfigFile

Once I updated the command to specify the character encoding, everything was good for creating new repositories too.

“[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`nrealm=Default`r`n” | Out-File -filePath $repoConfigFile -encoding ASCII

You can grab the updated version of CreateSvnRepo.ps1 here.

Let me wrap up by saying that I like Subversion, but its failure modes leave something to be desired. It would have been more helpful to fail with an unreadable svnserve.conf than ignoring the file and using defaults. Even better would be if it understood Unicode configuration files.

Source control is a must when it comes to development. It doesn’t matter if you’ve got a large team of developers or if you’re the only one. You need to set up source control. For my own pet projects, I use Subversion. Simple to set up and simple to use, especially with TortoiseSVN. I’m not going to go into a long intro on how to set up and use Subversion or TortoiseSVN. There are many quickstarts kicking around the web on how to do this. You can google those as well as I can. What I am going to discuss is initial repository setup.

I usually create a Subversion repository per project. If I ever need to move a repository to another computer, I simply copy the directory containing the repository. No complicated export/import scripts required. Same is true with backup/restore. If something goes horribly wrong (which it never has, but just in case), I can retrieve the source repository from backup without affecting any other repository. The standard structure within a repository includes a number of project-level directories, including trunk, tags, and branches:

Trunk is where mainline development occurs. Most of the time, I will be working from svn://Eddings/Sample/trunk. When you create a release, I want to tag it, which involves making a copy of the files in trunk (or elsewhere) to the tags directory. For instance, using TortoiseSVN, I would Branch/Tag… to svn://Eddings/Sample/tags/v1.0. (N.B. Subversion uses a copy-on-write mechanism so that I’m only storing one copy of a file, even if I tag/branch it multiple times. It also uses a binary differencing mechanism to keep the repository small. So if I add a 10 MB binary file to my repository, change a few bytes, and push my changes back into the repository, the space occupied by the file will be 10 MB plus the few bytes of changes plus some versioning information.) Branches is exactly the same as tags, except it is typically used as temporary scratch space for changes that will later be merged into trunk or tags. For instance, let’s say I released v1.0, which is tagged. I am working on v2.0 in trunk, but I need to make a bug fix in v1.0. I branch v1.0 into branches/v1.0-Remediation and make the fix. When I’m ready to release, I tag branches/v1.0-Remediation as tags/v1.01 and delete branches/v1.0-Remediation. I will probably reverse integrate the bug fixes into the trunk.

Typically I also point my new repository to a globally-maintained user list. (Unfortunately Subversion doesn’t integrate with Windows auth out-of-the-box. I believe you can do it, but you need to run Subversion under Apache. More trouble than it’s worth for a single developer, in my opinion.) So there’s another manual step…

The main take-home message is that when I create a new repository, there is a bunch of initial setup that needs to be done. Why not automate it? I wanted to learn PowerShell and this seemed like a good mini-project to do it on. This is based on my own exploration of PowerShell and there might be better ways of doing things in PowerShell. So your mileage may vary. Don’t take this as gospel or best practices, but as one man’s fumblings through learning PowerShell.

Why PowerShell?

First question is why do we have scripting environments in the first place. Usually it’s because we need to glue together a bunch of commands to do something more complex. The complexity doesn’t warrant a full-fledged application and we want to be able to change it easily. Scripting to the rescue. It’s the main reason we’ve had the Windows Command Shell and the Windows Scripting Host on the Windows platform and bash, ksh, tcsh, … on Unix platforms.

Next question… Why PowerShell and not something with more sex appeal like Ruby? PowerShell has an attraction for me because it targets the .NET platform. 90% of learning a new environment is learning the libraries. PowerShell lets me leverage my .NET knowledge in a scripting environment. Maybe I’ll learn Ruby one day, but Ruby is a one-trick pony in my opinion — specifically Ruby on Rails. RoR is one hell of a trick for web applications, but I’m not ready to learn a whole new set of libraries just to write web apps. I don’t like web applications that much! Tongue out

Just like bash, ksh, tcsh, and other command shells before it, PowerShell lets me glue together simpler commands to create complex scripts. The Unix shells did this by having standard mechanisms to pipe the results of one command to the input of another, but everything is text. This means that each command requires its own parsing routines to handle the incoming text. PowerShell communicates between cmdlets using .NET objects. No more dealing with raw strings. Now I can examine objects, query them using reflection, or use them to perform actions. Cool stuff!

Getting Started with PowerShell

There are a number of good references for PowerShell that you should definitely keep close at hand.

I’m not going to walk through all the features of PowerShell as others have already done that. What I will do is discuss how I solved different pieces of the puzzle in building a script to create a new Subversion repository. Let’s look at the script piece-by-piece.

Execution Policy

Before we can execute a PowerShell script, we must modify execution policy. By default, PowerShell ships in a locked-down mode that prevents scripts from running. You can execute cmdlets at the PowerShell prompt, but you can’t execute “.ps1″ files containing scripts. To enable running script files, open a PowerShell prompt and execute:

Set-ExecutionPolicy unrestricted

Note that PowerShell features cmdlet completion using the tab key. So typing set-e[TAB] will auto-type the rest for you. If there are multiple cmdlets with the same name, you can tab multiple times to cycle through the options. You can even use wildcards to pattern match cmdlets and cycle through matching cmdlets using tab.

CreateSvnRepo.ps1

PowerShell code is in green. Discussion is in black. A discussion of implementation details are after each section of code. I’m not going to discuss the purpose of each section as that is noted in the comments heading each major section.

# CreateSvnRepo v1.2
# Copyright © 2007 by James Kovacs
# All rights reserved.
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
# ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND/OR FITNESS FOR A
# PARTICULAR PURPOSE.

Just an informational header. Comments in PowerShell are denoted by the hash (#) sign.

# Check usage
If($args.Length -ne 1) {
  Write-Host "Usage: .\CreateSvnRepo.ps1 "
  Write-Host "  where RepoName is the name of the new repository"
  Write-Host "N.B. RepoName cannot accept a file path or url."
  Write-Host "     CreateSvnRepo assumes that svn and svnadmin are in your path."
  Exit(0)
}

We need to check the command line arguments and possibly print usage information. The script expects to be called like this:

.\CreateSvnRepo.ps1 <RepoName>

where RepoName is the name of the new repository.

Variables in PowerShell are prefixed by $. There are a few default variables such as $args, which is the command line arguments. (N.B. Like in .NET, the executed script is not included in the list of arguments.) $args is a string[] and we can check its Length property, just like in C# or VB.NET. Comparison operators in PowerShell do not use conventional operator syntax, but instead use “dash” syntax. For instance, -ne is not equal, -eq equal, -gt greater than, -ge greater than or equal, -lt less than, -le less than or equal, etc. There are also bitwise, matching, and type comparison operators as well as case-insensitive versions where appropriate. See Comparison Operators in the PowerShell Quick Start for a full list.

Write-Host serves the same purpose as Console.WriteLine. Notice that cmdlet calls do not use parentheses to denote arguments as this matches the flavour of calling commands in scripting environments. Also note the standard syntax used for cmdlets, which is VERB dash SINGULAR NOUN. Even if you expect multiple items, the singular noun is used. For instance, to get a list of running processes, execute Get-Process. Cmdlets are case-insensitive.

# Set up variables needed by script
$newRepoName = $args[0]

Variables are created when they are assigned. We do not have to explicitly set the type of a variable, though we can by prefixing the variable with [type]. For example, [int]$i = 42.

$currentWorkingDir = (Get-Location).Path.Replace("\", "/")

Get-Location is a cmdlet that returns the current working directory as a System.Management.Automation.PathInfo object. To execute the cmdlet and get its result, we wrap the cmdlet in parentheses. Without the parentheses, PowerShell assumes we’re looking for a cmdlet or executable named Get-Location.Path.Replace. (This is because executables often have names such as DoStuff.exe.) Once we have a PathInfo object, we can examine its Path property. Notice that the Path property returns a string and we can perform normal .NET string operations on it, in this case changing backslashes to slashes since svnadmin (the Subversion command for creating repositories) uses Unix-style path separators.

Speaking of Unix, PowerShell includes a lot of Windows and Unix aliases. Aliases are names that execute cmdlets, possibly with parameters. For instance, both “dir” and “ls” actually execute “Get-Item *”. An alias for Get-Location is “pwd” or print working directory, which should be familiar to all Unix-heads. Get-Alias lists all the currently defined aliases and Set-Alias allows you to add or modify an alias.

$newRepoSvnPath = "file:///$currentWorkingDir/$newRepoName"

There are two types of strings in PowerShell, expanded and non-expanded strings. Single-quotes are used to denote non-expanded strings, similar to string literals in C# using @”No special characters here”. Double-quotes are used to denote expanded strings. Any variables in the string are replaced with their value. So if $fortyTwo = 42, then ‘The answer to life, the universe, and everything is $fortyTwo’ has the value The answer to life, the universe, and everything is $fortyTwo whereas “The answer to life, the universe, and everything is $fortyTwo” has the value The answer to life, the universe, and everything is 42.

$repoConfigFile = Join-Path $newRepoName 'conf\svnserve.conf'

Join-Path performs the same function as System.IO.Path.Combine in that it saves you from having to worry about whether the strings have directory separators in the correct places.

$tempPath = [System.IO.Path]::GetTempPath()
$tempDirName = [System.IO.Path]::GetRandomFileName()

Here I need to access some static methods for which there is no equivalent cmdlet (as far as I know). We identify the type using square brackets followed by :: and the name of the static method.

$workingCopy = Join-Path $tempPath $tempDirName
$dirNames = 'branches', 'tags', 'trunk'

The only new thing here is that we’re creating an array of strings. Nothing special, just comma-separate the objects and assign them to a variable.

# Ensure that we were passed only a repository name and not a path
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars()
If($newRepoName.IndexOfAny($invalidChars) -ne -1) {
  Write-Host "You must specify a valid repository name. It cannot be an absolute or relative path."
  Exit(-1)
}

More of the same, except now we’re calling a method on $newRepoName, which is of type System.String. This is a standard .NET method call with parameters. So we use parentheses around the arguments, as you can see in the call to IndexOfAny. This is the main difference between calling cmdlets and calling methods on objects.

# Ensure that repository doesn't already exist
If(Test-Path $newRepoName) {
  Write-Host "Error: Repository, $newRepoName, already exists."
  Exit(-1)
}

Here’s a new cmdlet, Test-Path, that will let us know if the path already exists or not.

The help system in PowerShell is quite useful. You access via Get-Help (or the shorter alias, help). Get-Help cmdlet will give you information on a command. Get-Help Get-Help gets help on the help system itself! Get-Help accepts wildcards. So if you want to find out everything you can do with Paths, type Get-Help *-Path. If you want to find everything you can Set, type Get-Help Set-*. This is an excellent way to poke around and find out more about available cmdlets.

# Create directory to hold the new repository
Write-Host "Creating new repository: $newRepoName"
New-Item -path . -name $newRepoName -type directory

We’re using the New-Item cmdlet, but this time we’re using named parameters. New-Item can be used to create directories, files, registry keys, and more. PowerShell uses a provider model. So as long as there is an appropriate provider, you can interact with any information store. Anyone can create a provider to extend the functionality of PowerShell. For instance, people are implementing (or have implemented) PowerShell providers for Subversion, Newsgator, SharePoint 2007, …

If(!(Test-Path $newRepoName)) {
  Write-Host "Unable to create directory, $newRepoName. Verify that you have permission to create this directory."
  Exit(-1)
}

We can use ! or -not to negate a boolean value. Here we want to make sure that we successfully created the directory.

# Create the repository
svnadmin create $newRepoName

Svnadmin is an executable that ships with Subversion. It is used for creating repositories, among other things. I execute it just like I would from the command line. The only trick is that I’m passing it the value of a PowerShell variable.

# Clear repo configuration directory
$configFiles = Get-ChildItem -path $repoConfigDirectory
ForEach ($configFile in $configFiles) {
  Remove-Item -path $configFile.FullName
}
# Overwrite configuration file to point to global password directory
"[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`n`r`nrealm=Default`r`n" | Out-File -filePath $repoConfigFile -encoding ASCII

Now we’re entering territory that is usually reserved for Perl-heads. (If you’ve ever read Perl code, you’ll know what I’m talking about.) I’m creating an expanded string (denoted by double quotes) that includes escaped character sequences, which are denoted by the back tick (`). I find the back tick a bit odd to read, but it has the advantage that you don’t have to escape slashes, which are used as path separators. So `r`n is a carriage return/line feed, equivalent to \r\n in most curly-brace languages. Next we write the string to a file by piping the string to Out-File. I set the encoding to ASCII since svnserve.exe doesn’t like Unicode encoding, which is the default. If you want to write Unicode text, you can out the output redirection operator (>). If you want to append to the file rather than overwrite, use the >> operator.

# Create a temporary working copy so we can commit initial setup in one go
Write-Host "Creating temporary working copy in $workingCopy"
New-Item -path $tempPath -name $tempDirName -type directory
svn checkout --non-interactive $newRepoSvnPath $workingCopy

Nothing interesting here. We’re just checking out a working copy into a temporary directory. Svn.exe is the main command line tool for Subversion that allows us to perform checkouts, updates, commits, branches, and a myriad of other operations. I typically use TortoiseSVN for performing these operations, but svn.exe is good when you need to script things. There are numerous ways I could have interacted with Subversion (Scott Hanselman has some other suggestions), but I wanted the one with the least dependencies. (i.e. You just need PowerShell and Subversion installed.)

Write-Host "Creating directories in working copy"
ForEach ($dirName in $dirNames) {
  $path = Join-Path $workingCopy $dirName
  svn mkdir $path
}

The only thing new here is the ForEach keyword, which does what you’d expect and iterates through the string[] of $dirNames.

# Commit changes to the repository
Write-Host "Committing changes"
svn commit $workingCopy --message "Initial repository setup"

Once again, we’re just executing svn.exe to commit our newly created directories to the repository.

# Perform cleanup
Write-Host "Cleaning up working copy"
Remove-Item -path $workingCopy -recurse -force

Lastly we clean up the mess of temporary files and directories that we created.

So that’s it. A simple PowerShell script that quickly creates a new Subversion repository for whichever pet project I’m working on. I honestly haven’t even scratched the surface of what PowerShell can do. Hopefully this gives you some ideas and a starting place for your own PowerShell scripts. Honesty the biggest benefit of PowerShell for .NET developers is that it lets us seamlessly leverage the .NET Framework. Not having another API to lug around in my head is a good thing and makes me more productive right away.

Feel free to modify the script to your heart’s content to suit your own environment. The full script can be found here.

UPDATE: Corrected the encoding of the svnserve.conf to use ASCII encoding.

A few days ago, I read Kyle Baley’s post about learning Rhino Mocks. Like many folks, he initially had trouble understanding Rhino Mocks’ record/playback metaphor. Then during the Calgary Code Camp, an attendee kindly pointed out that I had forgotten mockRepository.ReplayAll() in my unit test – fortunately before I actually ran it. Then yesterday I was catching up on my blog reading and saw this post from Oren discussing various people forgetting to call mockRepository.ReplayAll(), including Oren himself.

I thought to myself, Rhino Mocks has a very nice fluent interface, but doesn’t make its Record/Playback explicit. What would I want my code to look like if it did support explicit Record/Playback? So I grabbed the source from Subversion, put on my TDD hat, and came up with this failing test:

[Test]
public void CanRecordPlayback() {
    MockRepository mockRepository = new MockRepository();
    IFoo mockedFoo = mockRepository.CreateMock<IFoo>();
    using(mockRepository.Record()) {
        Expect.Call(mockedFoo.Bar()).Return(42);
    }
    using(mockRepository.Playback()) {
        Fooz fooz = new Fooz(mockedFoo);
        fooz.Barz();
    }
}

A few minutes later, I had working code for the Record and Playback methods, all the unit tests passed, I created a patch, and emailed it to Oren for his thoughts on the new syntax. He liked it so much that he included the new syntax in Rhino Mocks 3.0.5, which he just released today.

A few things to note about the new syntax. Expectations are grouped in the Record block. Exercising the mocks occurs in the Playback() block. ReplayAll() and VerifyAll() are called implicitly after the Playback() and Record() blocks, respectively.

Time between initial idea and production deployment: Less than 24 hours. How is that for great turn-around? Thanks, Oren. I’m proud to have committed to such a widely-used (and respected) project!

What can I say? I love ReSharper. I bought a copy with my own hard-earned cash because it made my life as a developer easier. TDD development without ReSharper is like GUI development in notepad. It can be done, but it ain’t pretty.

The JetBrains team, the folks behind ReSharper, is also incredibly helpful and open. When I was developing the VstsUnit Plugin for ReSharper, Oleg Stepanov – JetBrains’ Head .NET Project Manager – was kind enough to answer my questions about some integration challenges I was experiencing. His assistance saved me days of head-scratching, trying to figure out what exactly was going on.

So it’s pay-back time.  JetBrains is looking for feedback on ReSharper to help drive the product’s direction. How can JetBrains make ReSharper even better than it already is? Is there a killer feature you’d love them to implement? Thinking of buying ReSharper, but it’s missing your must-have feature? Take a few minutes and fill out their survey.

If you’re not a ReSharper user and are wondering what all of us TDDers are blithering about, come to the Calgary Code Camp on Saturday, April 28, 2007 and you’ll not only see ReSharper in action,* you could win a free copy! JetBrains is one of our sponsors and has graciously donated copies of their .NET Productivity Pack, which includes ReSharper and dotTrace**, as door prizes. You could be one of the lucky few to walk away with these great products.

* All the speakers in the Agile track are avid ReSharper users. So you’ll get a chance to see fingers and code flying. True art is watching Jean-Paul Boodhoo at the keyboard with ReSharper. He is THE master.

** dotTrace is a performance and memory profiling tool. I’ve tried out many of the major profiling tools on the market and dotTrace is definitely the easiest to use and has consistently provided great results. Straightforward answers with a minimum of fuss. Highly recommended.