Relative path to config file in BIDS/SSIS 2008 package configurations

As we know using absolute paths in our code can complicate things from a deployment point of view, so it’s best to use relative paths were possible. In business intelligence studio 2008 however the package configuration wizard doesn’t allow you to enter relative paths when pointing to configuration files. If you attempt to type a relative path in, clicking next will replace it with the absolute path, so we appear to have a problem here.

package-configuration

There is an easy work around however, rather than using the GUI just edit the .dtsx file directly to point to the relative path. For example if in BIDS package configuration window you have entered the path as ‘c:\SSIS\active.dtsconfig’, simply change that to ‘..\SSIS\active.dtsconfig’ using a text editor and next time you open the wizard the relative path will be used.

Discouraging use of the var keyword and ternary if operator

I would always favour typing more code to make it more explicit, more readable and to ensure consistency in style throughout a software system. Minimising the bytes and lines needed to do something shouldn’t take preference over readability. My two pet hates in this regard are the var keyword and ternary (?) if operator.

I know var is just syntactical sugar and everything is still type safe, but for me it just moves C# in the direction of a non type safe language at least in regard to syntax style and personally I just don’t like using it. I spoke to another developer about it recently and he was very dogmatic that it is a good thing as its shorter and more concise. I agree in some instances that that can certainly be the case but because it’s not appropriate for all declarations such as:

var myVariable = System.IO.File.Open("test.txt", FileMode.Create);

or

var id = GetId();

it means a developer will either a) use var everywhere including in statements like the above where the type is in fact not obvious or b) use explicit declarations for statements like above and use var declarations for statements such as:

var names = new List<string>();

which means you either have many instances of variable declarations which are hard to understand or inconsistent coding style. If var is used at all another developer will no doubt come along and use it inappropriately so I prefer to discourage its use.

As far as ternary operator (?) ifs are concerned, again I prefer not to use them. I’d rather just use a standard multi-line if through the whole system, this way everything is explicit and the judgement call of whether the use of ? actually makes a particular if statement easier to understand or not is eliminated. I mean for simple expressions they can be neat but the problem is that in a team environment the precedent set by using them at all results in their overuse by less skilled developers. For example it definitely wouldn’t surprise me to see statements like the below:

int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;

pop up in a code base which has instances of ? already for simple expressions. Again then for reasons related to removing ambiguity about the appropriateness or not of its use, I discourage writing if statements with the ternary operator.

Code is read much more than its written so don’t save a couple of seconds using c# shorthand when writing it if it’s possible this will slow down those maintaining it.

Using MSBuild to publish a website just like in Visual Studio

Right clicking on a web project or a WCF project (others too I’m sure) in Visual Studio presents you with a publish option which when run basically drops all files needed to deploy your project into a single folder. The publish action will use any web transform files so settings included in the to be deployed web.config are settings relevant to whatever configuration was selected when you ran the publish command.

For smaller deployments this might be fine, but if you have multiple projects and/or you need to do some pre or post work (such as FTP or IIS related) your likely to want to put everything you need into a single MSBuild script so the deployment is repeatable, quicker and safer.

If you have Visual Studio 2010 installed you can get the same functionality that Visual Studio provides through the GUI via MSBuild with a snippet like following:

msbuild-publish

In this instance I’m asking MSBuild to publish a project called MSBuildExamples.Web to a folder called Production in the location where the build script is being called from. Depending on the publish options contained within MSBuildExamples.Web.csproj the files in the generated Production folder may contain raw *.cs files and *.dlls or just the *.dlls needed to run the project.

The most important part is the targets attribute which is highlighted above. This uses a target called PipelinePreDeployCopyAllFilesToOneFolder which is a Visual Studio 2010 (and 2012 presumably) target, not a built in MSBuild one. The target is imported in MSBuildExamples.Web.csproj with the following line:

msbuild-publish2

which Visual Studio will automatically add when you create either a Web or WCF project. Running the PipelinePreDeployCopyAllFilesToOneFolder task against a project in MSBuild does exactly the same thing as running publish against the same project in the Visual Studio GUI.

Using a connectionStrings section connection with log4net now supported

Just upgraded to Version 1.2.11 of log4net due to the fact that one of the improvements in this version is the support for the use of a connectionStringName which references a connection from the connectionStrings configuration section.

log4net

Previously this was not part of the core release so you either had to take extra steps (it didn’t just work) or use an explicit connection string in your log4net setting. It’s nice for maintenance if your 3rd party tools can just reference a connectionString rather than explicitly define one themselves.

Sharing connectionStrings and appSettings between multiple projects

My last post talked about how to do this for appSettings via the file attribute however as I mentioned in that post the connectionStrings section unfortunately does not have a file attribute. It along with most other config sections only supports configSource which can only point to a config file in the current project. I did a bit more research and it seems configSource may be up to the job after all but only in conjunction with either Visual Studio file linking or build events to explicitly copy the master setting files.

Create your ‘master’ *.config files

OK first create a physical folder in your solution root called ‘Config’ for instance and lash your settings files in there. These are the master files you will be editing. Also replicate the physical structure with a Visual Studio solution folder as this is recommended so you can then easily manage the files via solution explorer. Additionally you should not have to explicitly tell TFS (if that’s what your using) about your new files if your replicate the physical structure with a solution folder.

Your structure might look something like the following:

Config
localhost.appSettings.config
localhost.connectionStrings.config
dev.appSettings.config
dev.connectionStrings.config
live.appSettings.config
live.connectionStrings.config

Use the .config extension for security reasons as files with that extension won’t be served via a HTTP request.

Sharing config files by linking to them from consuming projects

For each project that needs to consume these master settings add a link to each of them. You can do this to each project directly or if like me you’d rather not clutter your root up you can create a dummy ‘Config’ folder (unfortunately virtual folders like solution folders do not exist on the project level) and add them as links to that folder. How links are added is very similar to the way regular existing items are added, however instead of just clicking ‘Add’ one must expand the dropdown and click ‘Add as Link’ instead.

link

After you have added the files as links your dummy physical folder will look very similar to folders with regular files but the files/links within it will have a slightly different icon beside them.

linked-in-solution

Now update your web/app.config and point your appSettings or connectionStrings section configSource to “config\localhost.appSettings.config” for example…

configSource

Now try two things.

Publish your project and notice how the linked files are ‘pulled in’ from the actual location for the purposes of deployment. In conjunction with a simple web transform to go from config\locahost.appSettings to config\live.appSettings etc. this means happy days, all works fine there.

Run your project in the IDE. It will fail at run time. That is because configSource is not able to follow links. It must point to an actual file and unlike during deployment Visual Studio does not ‘pull in’ the actual files (even temporarily) to the location that they are being link to from.

tooutputIf on each of the linked files we set the Copy to Output Directory property to “Copy if newer” or “Copy always” VS will put them into the bin/config folder. We can then prepend ‘bin’ to all our configSource references and VS will find the config files fine. I’d rather not have to point my configSource to anything in bin but this approach essentially solves what I’m trying to do.

When you publish again you will of course have a ‘Config’ folder in the package root itself but also in the package bin folder. You can remove the ‘Config’ folder from the root of the package by selecting “None” for the Build Action property on each of the links if you like.

Sharing config files by copying them with a pre build event

If you add the below XCOPY command into the pre build events box for project XYZ, Visual Studio or more precisely MSBuild will copy all files from the master ‘Config’ folder you created above to a folder called ‘Config’ in the XYZ directory.

build

If you point your configSource back to “config\localhost.appSettings” etc. Visual Studio will run fine because the physical files exist there.

Now however the problem is with the deployment.  When using the publish tool the ‘Items to deploy..‘ default of ‘Only files needed to run this application’ will not recognize the XYZ config folder with all the *.config’s in it as ‘needed’ as the XYZ project knows nothing about it and thus the package won’t have the required settings files to run correctly.

You can get around this easily by changing the ‘Items to deploy..‘ drop down box to “All files in this project folder“. This will work but personally I don’t like this though as it clutters the package and delivers the source code as is, not compiled into .dlls.

todeploy

You could alternatively actually add a physical XYZ/Config folder and add copies of all the master config files to that folder and hence the project to ‘trick’ Visual Studio into recognizing the files in that folder as required. Of course the files in the XYZ/Config folder would always be overridden with files from the master config folder via the pre build event.

Which approach to choose. Link and Copy to bin or XCOPY to Config

I’m sure there are other ways to do this, and I have seen people wrap abstracted settings in class files but in terms of the above two well which method to choose really depends on your situation.

Both at the end of the day require copying of the master config files to somewhere where the configSource attribute can read them. It seems that if you go the linking route both deployment and running via Visual Studio will work fine if your OK with having your configSource’s pointing to bin. There’s also the small price to pay of needing a dummy physical folder as a hook to add the links to (I suggest adding a readme to this folder so other devs know what’s going on). Additionally ‘links’ don’t physically exist in your regular solution so you won’t have any problems with source control.

Choosing to copy settings files to arbitrary locations in the projects that need them has the potential to complicate deployment and force you to change the way you package up your files. Of course if you don’t deploy via Visual Studio or simply deploy everything in a project folder regardless of what Visual Studio has included in your project then everything is fine. With the build event approach the XCOPY copies all master settings each time you build, you don’t have to remember to explicitly link new settings files (localhost.nhibernate.config for example) from each project that needs them. Again source control will not be a problem as even though XCOPY does create actual files they will not be looked at by TFS or most other source control systems unless those files are explicitly added.