【问题标题】:Implementing custom configuration section handler实现自定义配置节处理程序
【发布时间】:2024-01-18 18:52:01
【问题描述】:

来自各种来源(包括 stackOverlflow)的收集,但是当我开始使用它时,我收到以下错误消息

“配置属性 'deviceconfig' 可能不是从 ConfigurationSection 派生的。”

我已经在一天的大部分时间里一直在努力解决这个问题,并且还没有更接近解决方案,因此我们将非常感谢您对此事的任何帮助。我是实施自定义配置部分的新手,所以请温柔对待我 :-)

app.config 文件如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="deviceconfig"  type="CNIMonitor.Core.CustomConfig.DeviceConfig,Core"/>
  </configSections>
<system.diagnostics>
    <sources>
        <!-- This section defines the logging configuration for My.Application.Log -->
        <source name="DefaultSource" switchName="DefaultSwitch">
            <listeners>
                <add name="FileLog"/>
                <!-- Uncomment the below section to write to the Application Event Log -->
                <!--<add name="EventLog"/>-->
            </listeners>
        </source>
    </sources>
    <switches>
        <add name="DefaultSwitch" value="Information" />
    </switches>
    <sharedListeners>
        <add name="FileLog"
             type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" 
             initializeData="FileLogWriter"/>
        <!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
        <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
    </sharedListeners>
</system.diagnostics>
<deviceconfig>
  <devices>          
      <device deviceid = "1" 
              name = "localhost" 
              ipaddress="127.0.0.1" 
              port="10000"
              status="not listening"
              message="no message"
      />
      <device deviceid ="2" 
              name ="2nd localhost" 
              ipaddress="127.0.0.1" 
              port="20000" 
              status="not listening"
              message="no message"
      />
  </devices>  
</deviceconfig>

Custom Section Handler 代码如下:

Imports System.Configuration

命名空间 CNIMonitor.Core.CustomConfig

Public Class DeviceConfig
    Inherits ConfigurationSection
    <ConfigurationProperty("deviceconfig")> _
    Public ReadOnly Property DeviceConfig() As DeviceConfig
        Get
            Return CType(MyBase.Item("deviceconfig"), DeviceConfig)
        End Get
    End Property
End Class

<ConfigurationCollectionAttribute(GetType(Device))> _
Public Class Devices
    Inherits ConfigurationElementCollection
    Protected Overrides Function CreateNewElement() As ConfigurationElement
        Return New Device
    End Function
    Protected Overrides Function GetElementKey _
    (ByVal element As ConfigurationElement) As Object
        Return CType(element, Device).DeviceID
    End Function
    Public Sub Add(ByVal element As Device)
        Me.BaseAdd(element)
    End Sub
End Class
Public Class Device
    Inherits ConfigurationElement
    <ConfigurationProperty("deviceid", DefaultValue:="", IsKey:=True, IsRequired:=True)> _
    Public Property DeviceID() As String
        Get
            Return CType(MyBase.Item("deviceid"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("deviceid") = value
        End Set
    End Property
    <ConfigurationProperty("hostname", DefaultValue:="", IsKey:=True, IsRequired:=False)> _
    Public Property HostName() As String
        Get
            Return CType(MyBase.Item("RegisteredDate"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("RegisteredDate") = value
        End Set
    End Property
    <ConfigurationProperty("ipaddress", DefaultValue:="", IsKey:=True, IsRequired:=False)> _
    Public Property IpAddress() As String
        Get
            Return CType(MyBase.Item("ipaddress"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("ipaddress") = value
        End Set
    End Property
    <ConfigurationProperty("port", DefaultValue:="", IsKey:=True, IsRequired:=False)> _
    Public Property Port() As String
        Get
            Return CType(MyBase.Item("port"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("port") = value
        End Set
    End Property
    <ConfigurationProperty("status", DefaultValue:="", IsKey:=False, IsRequired:=False)> _
    Public Property Status() As String
        Get
            Return CType(MyBase.Item("status"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("status") = value
        End Set
    End Property
    <ConfigurationProperty("message", DefaultValue:="", IsKey:=False, IsRequired:=False)> _
    Public Property Message() As String
        Get
            Return CType(MyBase.Item("message"), String)
        End Get
        Set(ByVal value As String)
            MyBase.Item("message") = value
        End Set
    End Property
End Class

End Namespace

【问题讨论】:

    标签: vb.net configuration configuration-files configurationmanager configsection


    【解决方案1】:

    顶层不需要 DeviceConfig 属性。您需要做的是为您的ConfigurationElementCollection 设备添加一个属性。我还会将您的 Devices 类重命名为不那么含糊的名称,例如 DeviceElementCollection。试试这个:

    Public Class DeviceConfig    
        Inherits ConfigurationSection    
    
        <ConfigurationProperty("Devices")> _    
        Public ReadOnly Property Devices() As DeviceElementCollection    
            Get    
                Return CType(Me("Devices"), DeviceElementCollection)    
            End Get    
        End Property    
    End Class    
    

    那么,在您对DeviceElementCollection 的定义中,如果不添加以下内容,您可能会遇到问题:

    Public Overrides ReadOnly Property CollectionType() As System.Configuration.ConfigurationElementCollectionType
        Get
            Return ConfigurationElementCollectionType.BasicMap
        End Get
    End Property
    
    Protected Overrides ReadOnly Property ElementName() As String
        Get
            Return "Device"
        End Get
    End Property
    

    我为类似问题写了一个很长的答案(抱歉,用 C#)here

    更新 - 如何在代码中使用

    Dim deviceConfiguration as DeviceConfig = ConfigurationManager.GetSection("deviceconfigs")
    For Each device As Device in deviceConfiguration.Devices
        '...whatever you need to do
    Next
    

    【讨论】:

    • AJ 感谢您的回复,根据您的建议更改了我的代码,代码现在可以编译,但是我不知道如何在应用程序中使用节处理程序。你有什么建议吗?我需要找到一种方法来迭代配置文件中指定的元素集合。
    • 将 deviceConfiguration 调暗为 DeviceConfig = ConfigurationManager.GetSection("deviceconfig") 将设备调暗为 deviceConfiguration.Devices 中每个设备的 ConfigurationElement Debug.WriteLine(device.ElementInformation.Properties.Item("deviceid").Value .ToString) Debug.WriteLine(device.ElementInformation.Properties.Item("hostname").Value.ToString) 下一个
    • 比我预期的要复杂一些 :-)
    • 您不必对 ElementInformation 进行显式强制转换。您可能必须在循环顶部将其从 ConfigurationElement 强制转换为 Device,但之后它的行为应该像具有属性的普通类。
    • 我同意设置很复杂,但是一旦定义了类,我发现自定义配置非常强大。哦,另外,您应该将我的答案标记为“正确”或回答您自己的问题并使用投票按钮下方的复选标记将其标记为正确。
    最近更新 更多