Monday, July 30, 2012

Running Powershell files from TeamCity

I've come across an amazingly easy way to get past the issue where TeamCity balks at executing powershell scripts. By default, on a brand new server TeamCity will not have access to execute powershell scripts as files, instead throwing an error message such as
zzz cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.
To get around it, the traditional way is to call Set-ExecutionPolicy RemoteSigned, but that can be difficult too, since you need to set it for the same user and architecture (x86 or x64) that TeamCity is running under. Rather then mess with that, Powershell's command line offers a five-second workaround:

-ExecutionPolicy ByPass

In the teamcity powershell build step, just add -ExecutionPolicy ByPass to the command line arguments, and you will be able to execute ps1 files to your heart's content.

Monday, July 16, 2012

Web.Config Tips - File vs ConfigSource

Today I would like to share some things I've learned about two useful attributes in web.config: file and configSource. Both of these attributes are invaluable in setting up modular web sites, because both of them let you break up your web.config file into many pieces. I've looked into both the mono and .Net (through reflector) implementations, to see what makes this tick. Here is a summary of what found:

configSource: ConfigSource is built into all ConfigurationSection elements and simply allows you to move a section to an external file. This works for custom sections too, as long as they inherit ConfigurationSection. When using configSource, unfortunately everything must be specified in the external file. Additionally, this didn't seem to play nice with a <?xml /> header, so just keep that line out.
<mySection configSource="newfile.xml" />
<mySection>
  <item value="1" />
  <item value="2" /> 
</mySection>
file: File is only built specifically into the AppSettingsSection. This is a major bummer, since file lets you specify attributes both in the external file, and in web.config itself. If there are conflicts, the external file always wins. This is great for some scenarios - If you have a external file that is replaced in production or QA phase, this lets you ignore web.config changes and only replace the external file.
<appSettings file="newfile.xml" >
  <add key="first" value="true" />
  <add key="second" value="true" />
</appSettings>
<appSettings>
  <add key="second" value="true" />
  <add key="third" value="true" />
</appSetttings>
Unfortuanely, there are two downsides that I've found with the file attribute. First of all, why is this only present in AppSettingsSection? While it doesn't work for all sections, it would be great for the <connectionStrings /> element, as well as many custom sections.

Secondly, if you want to use web.config transforms to separate debug and release builds, this could provide the opposite behavior from what is desired. For example, say a project kept all of it's app settings in a separate file, but for debug builds, you wanted to change some values of the app config, it would be nice to be able to specify the changed appsettings in the web.debug.config transform.

So what if these aren't enough?

If you are creating a custom ConfigSection, your only built-in option is the wholesale-replacement ConfigSource. If you want to mimic functionality provided by "file" (or even create an external file that is overridden by web.config properties), you have one choice:

Build it yourself.

The easiest way to get started is to have a look at the excellent Mono Project, particualry it's implementation of AppSettingsSection. The key method you should look at is DeserializeElement. Unfortunately, Mono seems to have some significant issues in it's implementation of "file". For one, pathing is broken, at least when I use a standard XmlTextReader insted of the mono specific ConfigXmlTextReader. This can be fixed by looking up the file path manually, probably by parsing out from ElementInformation.Source.

Secondly, base.DeserializeElement will be expecting the reader to be positioned inside the wrapper element, so you may need to do a little extra xml reading to get to the first item inside the wrapper. Beyond that, it's up to you how you want your custom external file process to behave.

I'll leave the final implementation as an exercise to the reader, so have fun with it.