代码之家  ›  专栏  ›  技术社区  ›  ZaDDaZ

配置文件中的DTD实体

  •  3
  • ZaDDaZ  · 技术社区  · 15 年前

    我试图在配置文件中使用实体定义来简化开发、qa、uat和生产版本之间的差异。以下是配置文件开头的示例:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE configuration [
        <!ENTITY MyStorageLocation "\\MyServer\MyStorageFolder">
        <!ENTITY MyDatabaseServer "devdb01">
    ]>
    <configuration>
        <configSections>
        <section name="MyCustomSection" type="MyCustomSectionHandler,MyAssembly"/>
            ...
        </configSections>
    <connectionStrings>
        <add name="MyConnectionString" providerName="System.Data.SqlClient" connectionString="Server=&MyDatabaseServer;;Database=MyDatabase;"/>
    </connectionStrings>
        ...
    <MyCustomSection>&MyStorageLocation;</MyCustomSection>
    </configuration>
    

    这似乎工作得很好,既然它是完全有效的XML,那么为什么不呢?只要我在一个自定义配置节中不使用这些实体中的任何一个,最后我将在该节上调用configurationmanager.getSection()。在连接字符串中使用“mydatabaseserver”实体不会导致任何问题。在提供的示例中,只要我不在myCustomSection元素中使用“myStorageLocation”实体,然后只在调用configurationManager.getSection()请求自定义节时遇到错误,一切都将正常工作。

    我最好的猜测是,configurationmanager类正在获取元素的原始源并尝试将其加载为xml,而忽略整个xml文件的声明实体。有没有更好的方法来做到这一点,不重新编码自定义配置节,以支持对设置的引用,而不是许多绝对设置?

    我收到的错误是:

    2009-01-27 14:00:53,474 [11936] ERROR MyCustomWindowsService [(null)] - Errors starting service -- shutting down
    System.Configuration.ConfigurationErrorsException: Reference to undeclared entity 'MyStorageLocation'. Line 183, position 19. (D:\...\MyCustomWindowsService.exe.config line 183) ---> System.Xml.XmlException: Reference to undeclared entity 'MyStorageLocation'. Line 183, position 19.
       at System.Xml.XmlTextReaderImpl.Throw(Exception e)
       at System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(String name, Boolean isInAttributeValue, Boolean pushFakeEntityIfNullResolver, Int32 entityStartLinePos)
       at System.Xml.XmlTextReaderImpl.ResolveEntity()
       at System.Xml.XmlTextReader.ResolveEntity()
       at System.Xml.XmlLoader.LoadEntityReferenceNode(Boolean direct)
       at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
       at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
       at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
       at System.Xml.XmlDocument.Load(XmlReader reader)
       at System.Configuration.ErrorInfoXmlDocument.LoadFromConfigXmlReader(ConfigXmlReader reader)
       at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.CreateSectionImpl(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentConfig, ConfigXmlReader reader)
       at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.CreateSectionWithRestrictedPermissions(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentConfig, ConfigXmlReader reader)
       at System.Configuration.RuntimeConfigurationRecord.CreateSection(Boolean inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentConfig, ConfigXmlReader reader)
       at System.Configuration.BaseConfigurationRecord.CallCreateSection(Boolean inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentConfig, ConfigXmlReader reader, String filename, Int32 line)
       --- End of inner exception stack trace ---
       at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)
       at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission)
       at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
       at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
       at System.Configuration.ConfigurationManager.GetSection(String sectionName)
       at MyCustomWindowsService.Monitor() in D:\...\MyCustomWindowsService.cs:line 207
       at MyCustomWindowsService.Start() in D:\...\MyCustomWindowsService.cs:line 178
    

    在配置管理器的内部深处…

    1 回复  |  直到 14 年前
        1
  •  0
  •   kmcorbett    15 年前

    也许您的XML处理器忽略了!实体声明,因为它们包含在否则为空的DTD中。

    您有可以用来验证此文档的DTD吗?如果缺少DTD或模式,就不能说文档是有效的。尝试通过在线XML验证服务运行它,如URL上的服务: http://www.validome.org/xml/validate/

    这是你的文件的修订版,上面有我加上去的DTD。看看这是否有用。


    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE configuration [
        <!ELEMENT configuration (configSections+, connectionStrings+, MyCustomSection)>
    
        <!ELEMENT configSections (section+)>
    
        <!ELEMENT section EMPTY>
        <!ATTLIST section name CDATA #REQUIRED>
        <!ATTLIST section type CDATA #REQUIRED>
    
        <!ELEMENT connectionStrings (add+)>
    
        <!ELEMENT add EMPTY>
        <!ATTLIST add name CDATA #REQUIRED>
        <!ATTLIST add providerName CDATA #REQUIRED>
        <!ATTLIST add connectionString CDATA #REQUIRED>
    
        <!ELEMENT MyCustomSection (#PCDATA)>
    
        <!ENTITY MyStorageLocation "\\MyServer\MyStorageFolder">
        <!ENTITY MyDatabaseServer "devdb01">
    ]>
    <configuration>
      <configSections>
        <section name="MyCustomSection" type="MyCustomSectionHandler,MyAssembly"/>
      </configSections>
      <connectionStrings>
        <add name="MyConnectionString" providerName="System.Data.SqlClient" connectionString="Server=&MyDatabaseServer;;Database=MyDatabase;"/>
      </connectionStrings>
      <MyCustomSection>&MyStorageLocation;</MyCustomSection>
    </configuration>