I have tried to define and use DTD entities inside my App.config
. For example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration [
<!ENTITY dataSource ".\SQLEXPRESS">
]>
<configuration>
<appSettings>
<add key="FooDataSource" value="&dataSource;" />
</appSettings>
<connectionStrings>
<add name="Foo" connectionString="Data Source=&dataSource;;Integrated Security=SSPI;" />
</connectionStrings>
</configuration>
Using System.Configuration.ConfigurationManager
to read appSettings
or connectionStrings
won't throw an error, but it also does not resolve the DTD entities.
(And sometimes the program will not execute at all. I have no idea why .NET complains only sometimes of a configuration error.)
Is my use of DTD incorrect, or does .NET not support custom DTD entities in App.config
?
System.Configuration uses a default XmlReaderSettings to determine how to read the .config file. Which has a ProhibitDtd property. You can see its default value with this bit of code:
Console.WriteLine(new XmlReaderSettings().ProhibitDtd);
Output: True
So that's a simple explanation why your .config file doesn't work. There isn't any way to configure it to override the setting.
Explaining why your program has trouble starting up requires more effort. The very first time the file is read is very early, before the CLR is even started. The bootstrapper needs to read the .config file to determine what version of the CLR to load, the <requestedRuntime>
element is important. It doesn't use a full blown XML parser, it is a very trimmed one that has all the DTD parsing bits removed. You can see it by downloading SSCLI20, the XML parser is stored in the clr/src/xmlparser subdirectory. Exactly what might go wrong isn't that clear, but if that parser has any trouble with the .config file then you are not going to find out what the problem might be. This happens way too early to allow any reasonable diagnostic to be generated. Check the Output window for a possible exit code number that gives a hint.
Your use of entity is correct; that's well-formed XML and there shouldn't be any issue using the attribute reference in the attributes.
It must be something with .NET* (which I have no knowledge of).
To demonstrate that the entity is correct, here's your XML passed through an XSLT identity transform which resolves the entities:
XML Input
<!DOCTYPE configuration [
<!ENTITY dataSource ".\SQLEXPRESS">
]>
<configuration>
<appSettings>
<add key="FooDataSource" value="&dataSource;" />
</appSettings>
<connectionStrings>
<add name="Foo" connectionString="Data Source=&dataSource;;Integrated Security=SSPI;" />
</connectionStrings>
</configuration>
XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<configuration>
<appSettings>
<add key="FooDataSource" value=".\SQLEXPRESS"/>
</appSettings>
<connectionStrings>
<add name="Foo"
connectionString="Data Source=.\SQLEXPRESS;Integrated Security=SSPI;"/>
</connectionStrings>
</configuration>
*Here are a few links I found that mention others not being able to get XML entities to work:
Reflector (on .NET 4.0) says that System.Configuration.ConfigXmlReader
(internal, sealed) is used to read configuration data, which is based on System.Xml.XmlTextReader
and calling it's constructor XmlTextReader(TextReader input)
, who creates internal XmlTextReaderImpl(TextReader input)
, and this constructor calls this(string.Empty, input, new NameTable())
which calls this(nt)
(with NameTable only) which initializes private field as this.entityHandling = EntityHandling.ExpandCharEntities;
MSDN says that ExpandCharEntities:
Expands character entities and returns general entities as EntityReference nodes.
So it looks that you can't use your own entities in .config file :(
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With