7

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?

stakx - no longer contributing
  • 77,057
  • 17
  • 151
  • 248

3 Answers3

4

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.

Hans Passant
  • 873,011
  • 131
  • 1,552
  • 2,371
1

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:

Community
  • 1
  • 1
Daniel Haley
  • 46,915
  • 4
  • 65
  • 89
1

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 :(

Dmitry
  • 13,497
  • 3
  • 52
  • 68