The Greek philosopher Plato summed up the stand-off between writing and the oral tradition. In Phaedrus, he quoted from Socrates, who spoke about a conversation between Thamus and the god Thoth – Hermes, the god of letters: “You, who are the father of letters, have been led by your affection to ascribe to them a power the opposite of that which they really possess. For this invention will produce forgetfulness in the minds of those who learn to use it, because they will not practise their memory. Their trust in writing, produced by external characters which are not part of themselves, will discourage the use of their own memory within them. You have invented an elixir not of memory but of reminding; and you offer your pupils the appearance of wisdom, not true wisdom, for they will read many things without instruction and will therefore seem to know many things, when they are for the most part ignorant and hard to get along with, since they are not wise, but only appear wise.
Link: http://skysigal.xact-solutions.com/Blog/tabid/427/blogid/2/Default.aspx
But Adam, center aligned posts
Look like haiku’s.
Tis Spring, after all.
Links:
http://bit.ly/hLgMHz
Yes. I know. My website centre aligns in IE for some stinking unknown reason.
I haven’t had a chance to look into it. Please bear with us while we conveniently ignore it to get on with more pressing work…
I’ve been looking more closely at the XDT built into MSBuild.exe that WebDeploy uses…mostly because I’ve been more than irked that it works fine on the base web.config, but ignores configSource referenced files. That – IMHO – is not just an omission on the part of the team that developed the solution -- that’s a huge stinking battleship omission.
Note:
It’s doubly annoying to me because I did write a XSLT transformation solution that can work with configSource. But because it’s a different syntax than the XDT syntax, and XDT is here to stay, I thought it best to not muddy the waters with more than one solution, and fold early. If you can’t beat them...
The Problem
The problem is the age old one of how to get:
- Version controlled copies of the various environment settings (DEV, QAT, UAT, PROD)
- A merge (not just an replacement) of app setting values so that there are the least amount of settings that need to be changed between environments.
The Solution
The solution I’ve come up with is as follows, using XDT, the configSource attribute, and a little bit of the file attribute for good measure.
The result looks like:

What I’m doing here is that I start off with a web.config that has:
<appSettings configSource="configuration\DEV\appSettings.config"/>
<connectionStrings configSource="configuration\DEV\connectionStrings.config"/>
that will get modified by a webdeploy XDT file (in this example, web.UAT.config) that has the following transformation values:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings configSource="configuration\UAT\appSettings.config"
xdt:Transform="Replace"/>
<connectionStrings configSource="configuration\UAT\connectionStrings.config"
xdt:Transform="Replace" />
</configuration>
This in turn references \configuration\UAT\appSettings.config, which contains:
<appSettings file="..\CMN\appSettings.config">
<add key="AKey1" value="A configSource'ed QAT Value 1..."/>
<add key="AKey2" value="A configSource'ed QAT Value 2..."/>
<add key="AKey3" value="A configSource'ed QAT Value 3..."/>
<add key="AKey4" value="A configSource'ed QAT Value 4..."/>
</appSettings>
Note:
The bright and bushy tailed among you will have noticed the file attribute pointing off to a ‘common’ configuration file in configuration\CMN\appSettings.config
<appSettings>
<add key="AKey2" value="A configSource'ed CMN setting 2..."/>
</appSettings>
The file attribute is an interesting one.
It’s only available on appSettings (damn), but unlike configSource= which simplyredirects to another file, it *merges* values from another file. Woohoo. That gives us more possibilities.
The final result is that the above settings come together as follows:
Val1: A configSource'ed UAT Value 1...
Val2: A configSource'ed CMN setting 2...
Val3: A configSource'ed UAT Value 3...
Val4: A configSource'ed UAT Value 4...
[A configSource'd DEV ConnStr]
Conclusion
Are we done? Yes.
Is that perfect? No.
Is it as far as I can wrest the framework to my desires? I think so.
Any issues to be aware of? Yes:
- The above solution works because although one cannot have both the file attribute and configSource attribute on the appSettings element in the root web.config, .NET doesn’t seem to mind if one has the configSource attribute on the appSettings element in the base web.config, and the file attribute applied on the configSource’d appSettings element.
- The above point brings up an interesting situation. Although I now have merging exactly as I want --- with some common settings being merged with environment specific settings, it isn’t exactly as I would like. I would have preferred that the UAT environment values override the common CMN ones, rather than the other way around (where CMN overrides specific UAT variables) as in the above scenario.
- In other words, I’ve got most if not all that I want, technically speaking – but I now have a little risk associated with trying to track down why an environment setting is not taking (it will be because there’s a CMN variable that is overriding it).
Let me know about your installation experiences…
PS:
As for ApplicationSettings (not the same as AppSettings) it has to be done via XDT only.
They don't like having either the file or configSource attribute applied (VisualStudio's Designer blows up saying the Xml source file has been damaged because it can’t find it where it expected it – in the root config file).
So yeah. AppSettings is so yesterday...and ApplicationSettings is the more typed solution to settings,but they not only requires more complex configSettings, but also just won't play nicely with modularisation.
Links
http://stackoverflow.com/questions/1159975/conditional-net-application-settings
How am I doing this morning? With this thing due in 8 hours? Just Fine.
Freaked out, Insecure, Neurotic and Emotional.
In other words, it’s a beak down, tail up kind of ducky day…
Src: The Italian Job…
Just ran into a cute error message doing a join across two databases that had different collation:
Msg 468, Level 16, State 9, Line 15
Cannot resolve the collation conflict
between "Latin1_General_CI_AS"
and "Latin1_General_100_CI_AI"
in the equal to operation.
when I ran the following:
select top 10
BlahBlah
from Tbl1 c
left outer join Tbl2 a on c.ClientId = a.ClientId
inner join
[OTHERDB].dbo.NationalityLookup n
ON c.NationalityCode = n.NationalityCode
where a.id is null
Didn’t have the option of updating the datbase, so ….the quick solution was to add COLLATE as follows:
select top 10
BlahBlah
from Tbl1 c
left outer join Tbl2 a on c.ClientId = a.ClientId
inner join
[OTHERDB].dbo.NationalityLookup n
ON c.NationalityCode COLLATE Latin1_General_CI_AS = n.NationalityCode
where a.id is null
on the left side of the join.
Cute…
It’s not exactly pretty printed, but at least it’s indented:
//load the Xml doc
XPathDocument myXPathDoc = new XPathDocument(inputXmlFilePath);
//load the Xsl
XslCompiledTransform xslCompiledTransform =
new XslCompiledTransform();
xslCompiledTransform.Load(inputXslFilePath);
//create the output stream
using (XmlTextWriter xmlTextWriter =
new XmlTextWriter(outputXmlFilePath, null))
{
//This is the stuff to add to get pretty formatting:
xmlTextWriter.Formatting = Formatting.Indented;
xmlTextWriter.IndentChar = ' ';
xmlTextWriter.Indentation = 2;
//do the actual transform of Xml
xslCompiledTransform.Transform(
myXPathDoc, null, xmlTextWriter);
xmlTextWriter.Close();
}