कैसे एक विन्यास के कार्यान्वयन के लिए एक विन्यास के साथ


166

मैं एक परियोजना में एक कस्टम कॉन्फ़िगरेशन अनुभाग को लागू करने की कोशिश कर रहा हूं और मैं उन अपवादों के खिलाफ भाग रहा हूं जिन्हें मैं नहीं समझता हूं। मैं उम्मीद कर रहा हूं कि कोई यहां खाली जगह भर सकता है।

मेरे पास App.configऐसा दिखता है:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="ServicesSection" type="RT.Core.Config.ServicesConfigurationSectionHandler, RT.Core"/>
    </configSections>
    <ServicesSection type="RT.Core.Config.ServicesSection, RT.Core">
            <Services>
                <AddService Port="6996" ReportType="File" />
                <AddService Port="7001" ReportType="Other" />
            </Services>
        </ServicesSection>
</configuration>

मेरे पास एक ServiceConfigतत्व परिभाषित है जैसे:

public class ServiceConfig : ConfigurationElement
  {
    public ServiceConfig() {}

    public ServiceConfig(int port, string reportType)
    {
      Port = port;
      ReportType = reportType;
    }

    [ConfigurationProperty("Port", DefaultValue = 0, IsRequired = true, IsKey = true)]
    public int Port 
    {
      get { return (int) this["Port"]; }
      set { this["Port"] = value; }
    }

    [ConfigurationProperty("ReportType", DefaultValue = "File", IsRequired = true, IsKey = false)]
    public string ReportType
    {
      get { return (string) this["ReportType"]; }
      set { this["ReportType"] = value; }
    }
  }

और मेरे पास एक ServiceCollectionपरिभाषित है:

public class ServiceCollection : ConfigurationElementCollection
  {
    public ServiceCollection()
    {
      Console.WriteLine("ServiceCollection Constructor");
    }

    public ServiceConfig this[int index]
    {
      get { return (ServiceConfig)BaseGet(index); }
      set
      {
        if (BaseGet(index) != null)
        {
          BaseRemoveAt(index);
        }
        BaseAdd(index, value);
      }
    }

    public void Add(ServiceConfig serviceConfig)
    {
      BaseAdd(serviceConfig);
    }

    public void Clear()
    {
      BaseClear();
    }

    protected override ConfigurationElement CreateNewElement()
    {
      return new ServiceConfig();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
      return ((ServiceConfig) element).Port;
    }

    public void Remove(ServiceConfig serviceConfig)
    {
      BaseRemove(serviceConfig.Port);
    }

    public void RemoveAt(int index)
    {
      BaseRemoveAt(index);
    }

    public void Remove(string name)
    {
      BaseRemove(name);
    }
  }

जो हिस्सा मुझे याद आ रहा है वह हैंडलर के लिए क्या करना है। मूल रूप से, मैंने IConfigurationSectionHandlerदो चीजों को लागू करने की कोशिश की :

  1. यह काम नहीं किया
  2. यह पदावनत है।

मैं अब पूरी तरह से खो गया हूं कि मुझे क्या करना है ताकि मैं अपने डेटा को कॉन्फिग से पढ़ सकूं। कोई मदद कृपया!


मैं यह काम नहीं कर सकता। मैं RT.Core.Config.ServicesSection देखना पसंद करूंगा। मुझे स्वीकार किए गए उत्तर के साथ ही कोड का उपयोग करने के बावजूद मुझे गैर-मान्यता प्राप्त तत्व 'AddService' मिलता है।
सिरदक

मैंने इसे पहले भी याद किया - यह भाग: [कॉन्फ़िगरेशनकॉलिनेशन (टाइपऑफ़ (सर्विसकॉलिज़न), AddItemName = "जोड़ें", ClearItemsName = "clear", RemoveItemName = "remove"]] AddItemName को मिलान करना होगा ताकि यदि आप "ऐड" बदल सकें तो मिलान हो सके। "addService" यह काम करेगा
हीदर

जवाबों:


188

पिछला उत्तर सही है लेकिन मैं आपको सभी कोड भी दूंगा।

आपका app.config इस तरह दिखना चाहिए:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <section name="ServicesSection" type="RT.Core.Config.ServiceConfigurationSection, RT.Core"/>
   </configSections>
   <ServicesSection>
      <Services>
         <add Port="6996" ReportType="File" />
         <add Port="7001" ReportType="Other" />
      </Services>
   </ServicesSection>
</configuration>

आपकी ServiceConfigऔर ServiceCollectionकक्षाएं अपरिवर्तित रहती हैं।

आपको एक नया वर्ग चाहिए:

public class ServiceConfigurationSection : ConfigurationSection
{
   [ConfigurationProperty("Services", IsDefaultCollection = false)]
   [ConfigurationCollection(typeof(ServiceCollection),
       AddItemName = "add",
       ClearItemsName = "clear",
       RemoveItemName = "remove")]
   public ServiceCollection Services
   {
      get
      {
         return (ServiceCollection)base["Services"];
      }
   }
}

और वह चाल चलनी चाहिए। इसका उपयोग करने के लिए आप इसका उपयोग कर सकते हैं:

ServiceConfigurationSection serviceConfigSection =
   ConfigurationManager.GetSection("ServicesSection") as ServiceConfigurationSection;

ServiceConfig serviceConfig = serviceConfigSection.Services[0];

10
[Add|Remove|Clear]ItemNameपर गुण ConfigurationCollectionविशेषता क्योंकि "जोड़ें" / "स्पष्ट" / "निकालें" पहले से ही XML तत्वों के डिफ़ॉल्ट नाम हैं, वास्तव में इस मामले में आवश्यक नहीं हैं।
विम कोएन

2
मैं इसे कैसे काम कर सकता हूं ताकि टैग न जोड़े जाएं? यह केवल अगर वे जोड़ रहे हैं काम करने लगता है। यह होगा काम नहीं करता है, तो यह <सेवा पोर्ट = "6996" ReportType = "फ़ाइल" /> या <सेवा पोर्ट = "7001" ReportType = "अन्य" /> था
JonathanWolfson

7
@JonathanWolfson: बस AddItemName = "Add" को AddItemName = "सेवा" में
बदलें

क्या यह अभी भी .NET 4.5 के लिए दृष्टिकोण है?
क्रश

6
@ क्रश: हाँ, .NET के इस धूल भरे कोने में ज्यादा बदलाव नहीं।
रसेल मैकक्लेर

84

यदि आप निम्नलिखित जैसे एक कस्टम कॉन्फ़िगरेशन अनुभाग की तलाश कर रहे हैं

<CustomApplicationConfig>
        <Credentials Username="itsme" Password="mypassword"/>
        <PrimaryAgent Address="10.5.64.26" Port="3560"/>
        <SecondaryAgent Address="10.5.64.7" Port="3570"/>
        <Site Id="123" />
        <Lanes>
          <Lane Id="1" PointId="north" Direction="Entry"/>
          <Lane Id="2" PointId="south" Direction="Exit"/>
        </Lanes> 
</CustomApplicationConfig>

फिर आप विन्यास अनुभाग के मेरे कार्यान्वयन का उपयोग कर सकते हैं ताकि आप System.Configurationअपनी परियोजना में विधानसभा संदर्भ जोड़ सकें

मेरे द्वारा उपयोग किए गए प्रत्येक नेस्टेड तत्वों को देखो, पहले एक दो विशेषताओं के साथ क्रेडेंशियल है इसलिए पहले इसे जोड़ने दें

साख तत्व

public class CredentialsConfigElement : System.Configuration.ConfigurationElement
    {
        [ConfigurationProperty("Username")]
        public string Username
        {
            get 
            {
                return base["Username"] as string;
            }
        }

        [ConfigurationProperty("Password")]
        public string Password
        {
            get
            {
                return base["Password"] as string;
            }
        }
    }

प्राइमरीएजेंट और सेकेंडरीएजेंट

दोनों में समान विशेषताएं हैं और यह प्राथमिक और एक विफलता के लिए सर्वर के एक सेट के लिए एक पते की तरह लगता है, इसलिए आपको बस उन दोनों के लिए एक तत्व वर्ग बनाने की आवश्यकता है

public class ServerInfoConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("Address")]
        public string Address
        {
            get
            {
                return base["Address"] as string;
            }
        }

        [ConfigurationProperty("Port")]
        public int? Port
        {
            get
            {
                return base["Port"] as int?;
            }
        }
    }

मैं इस पोस्ट में बाद में एक वर्ग के साथ दो अलग-अलग तत्वों का उपयोग करने का तरीका बताता हूँ, आइए हम SiteId को छोड़ दें क्योंकि इसमें कोई अंतर नहीं है। आपको सिर्फ एक वर्ग बनाना है, जो केवल एक संपत्ति के साथ ऊपर है। आइए देखें कि लेन संग्रह को कैसे लागू किया जाए

इसे दो भागों में विभाजित किया गया है पहले आपको एक तत्व कार्यान्वयन वर्ग बनाना होगा फिर आपको संग्रह तत्व वर्ग बनाना होगा

LaneConfigElement

public class LaneConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("Id")]
        public string Id
        {
            get
            {
                return base["Id"] as string;
            }
        }

        [ConfigurationProperty("PointId")]
        public string PointId
        {
            get
            {
                return base["PointId"] as string;
            }
        }

        [ConfigurationProperty("Direction")]
        public Direction? Direction
        {
            get
            {
                return base["Direction"] as Direction?;
            }
        }
    }

    public enum Direction
    { 
        Entry,
        Exit
    }

आप देख सकते हैं कि एक विशेषता LanElementएन्यूमरेशन है और यदि आप कॉन्फ़िगरेशन में किसी अन्य मान का उपयोग करने का प्रयास करते हैं जो एन्यूमरेशन एप्लिकेशन में परिभाषित नहीं है, तो System.Configuration.ConfigurationErrorsExceptionस्टार्टअप पर फेंक देगा । ओके कलेक्शन डेफिनिशन को आगे बढ़ने देता है

[ConfigurationCollection(typeof(LaneConfigElement), AddItemName = "Lane", CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class LaneConfigCollection : ConfigurationElementCollection
    {
        public LaneConfigElement this[int index]
        {
            get { return (LaneConfigElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }
                BaseAdd(index, value);
            }
        }

        public void Add(LaneConfigElement serviceConfig)
        {
            BaseAdd(serviceConfig);
        }

        public void Clear()
        {
            BaseClear();
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new LaneConfigElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((LaneConfigElement)element).Id;
        }

        public void Remove(LaneConfigElement serviceConfig)
        {
            BaseRemove(serviceConfig.Id);
        }

        public void RemoveAt(int index)
        {
            BaseRemoveAt(index);
        }

        public void Remove(String name)
        {
            BaseRemove(name);
        }

    }

आप देख सकते हैं कि मैंने AddItemName = "Lane"आपको सेट कर दिया है कि आप अपने संग्रह प्रविष्टि आइटम के लिए जो भी चाहें, चुन सकते हैं, मैं डिफ़ॉल्ट रूप से "जोड़ना" का उपयोग करना पसंद करता हूं लेकिन मैंने इसे केवल इस पोस्ट के लिए बदल दिया है।

अब हमारे सभी नेस्टेड एलिमेंट्स को लागू कर दिया गया है, अब हमें उन सभी को एक क्लास में एग्रीगेट करना चाहिए जिन्हें लागू करना है System.Configuration.ConfigurationSection

CustomApplicationConfigSection

public class CustomApplicationConfigSection : System.Configuration.ConfigurationSection
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(CustomApplicationConfigSection));
        public const string SECTION_NAME = "CustomApplicationConfig";

        [ConfigurationProperty("Credentials")]
        public CredentialsConfigElement Credentials
        {
            get
            {
                return base["Credentials"] as CredentialsConfigElement;
            }
        }

        [ConfigurationProperty("PrimaryAgent")]
        public ServerInfoConfigElement PrimaryAgent
        {
            get
            {
                return base["PrimaryAgent"] as ServerInfoConfigElement;
            }
        }

        [ConfigurationProperty("SecondaryAgent")]
        public ServerInfoConfigElement SecondaryAgent
        {
            get
            {
                return base["SecondaryAgent"] as ServerInfoConfigElement;
            }
        }

        [ConfigurationProperty("Site")]
        public SiteConfigElement Site
        {
            get
            {
                return base["Site"] as SiteConfigElement;
            }
        }

        [ConfigurationProperty("Lanes")]
        public LaneConfigCollection Lanes
        {
            get { return base["Lanes"] as LaneConfigCollection; }
        }
    }

अब आप देख सकते हैं कि हमारे पास नाम के साथ दो गुण हैं PrimaryAgentऔर SecondaryAgentदोनों के पास एक ही प्रकार है अब आप आसानी से समझ सकते हैं कि हमारे पास अपने दो तत्व के खिलाफ केवल एक कार्यान्वयन वर्ग क्यों था।

इससे पहले कि आप अपने app.config (या web.config) में इस नए आविष्कार किए गए कॉन्फ़िगरेशन सेक्शन का उपयोग कर सकें, आपको बस आपको यह बताना होगा कि आपने अपने स्वयं के कॉन्फ़िगरेशन सेक्शन का आविष्कार किया है और इसे कुछ सम्मान दिया है, ऐसा करने के लिए आपको निम्नलिखित पंक्तियों को जोड़ना होगा। app.config में (रूट टैग की शुरुआत के बाद सही हो सकता है)।

<configSections>
    <section name="CustomApplicationConfig" type="MyNameSpace.CustomApplicationConfigSection, MyAssemblyName" />
  </configSections>

नोट: MyAssemblyName बिना होना चाहिए। यदि आप असेंबली फ़ाइल का नाम myDll.dll है तो myDll.dll के बजाय myDll का उपयोग करें

इस कॉन्फ़िगरेशन को पुनः प्राप्त करने के लिए कोड का अनुसरण करें, जहां आपके आवेदन में कोई भी हो

CustomApplicationConfigSection config = System.Configuration.ConfigurationManager.GetSection(CustomApplicationConfigSection.SECTION_NAME) as CustomApplicationConfigSection;

मुझे उम्मीद है कि पोस्ट के ऊपर आपको कुछ जटिल प्रकार के कस्टम कॉन्फ़िगरेशन अनुभागों के साथ आरंभ करने में मदद मिलेगी।

हैप्पी कोडिंग :)

**** संपादित करें **** LaneConfigCollectionआपको LINQ सक्षम करने के लिए कार्यान्वित करना होगाIEnumerable<LaneConfigElement>

और के कार्यान्वयन के बाद जोड़ें GetEnumerator

public new IEnumerator<LaneConfigElement> GetEnumerator()
        {
            int count = base.Count;
            for (int i = 0; i < count; i++)
            {
                yield return base.BaseGet(i) as LaneConfigElement;
            }
        }

उन लोगों के लिए जो अभी भी इस उलझन में हैं कि उपज वास्तव में कैसे काम करती है इस अच्छे लेख को पढ़ें

उपरोक्त लेख से लिए गए दो मुख्य बिंदु हैं

यह वास्तव में विधि के निष्पादन को समाप्त नहीं करता है। यील्ड रिटर्न विधि के निष्पादन को रोक देता है और अगली बार जब आप इसे (अगले गणना मूल्य के लिए) कहते हैं, तो विधि अंतिम उपज रिटर्न कॉल से निष्पादित होती रहेगी। मुझे लगता है कि यह थोड़ा भ्रमित करने वाला है ... (शे फ्राइडमैन)

यील्ड .Net रनटाइम की विशेषता नहीं है। यह सिर्फ C # भाषा की विशेषता है जो C # कंपाइलर द्वारा सरल IL कोड में संकलित की जाती है। (लार्स कॉर्नेलिसेन)


3
एक पूर्ण उदाहरण प्रदान करने के लिए धन्यवाद, यह वास्तव में बहुत मदद करता है!
जॉन लेडिग्रेन

46

कॉन्फ़िगरेशन संग्रह के लिए यह सामान्य कोड है:

public class GenericConfigurationElementCollection<T> :   ConfigurationElementCollection, IEnumerable<T> where T : ConfigurationElement, new()
{
    List<T> _elements = new List<T>();

    protected override ConfigurationElement CreateNewElement()
    {
        T newElement = new T();
        _elements.Add(newElement);
        return newElement;
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return _elements.Find(e => e.Equals(element));
    }

    public new IEnumerator<T> GetEnumerator()
    {
        return _elements.GetEnumerator();
    }
}

आपके पास होने के बाद GenericConfigurationElementCollection, आप इसे कॉन्फ़िगर अनुभाग में उपयोग कर सकते हैं (यह मेरे डिस्पैचर से एक उदाहरण है):

public class  DispatcherConfigurationSection: ConfigurationSection
{
    [ConfigurationProperty("maxRetry", IsRequired = false, DefaultValue = 5)]
    public int MaxRetry
    {
        get
        {
            return (int)this["maxRetry"];
        }
        set
        {
            this["maxRetry"] = value;
        }
    }

    [ConfigurationProperty("eventsDispatches", IsRequired = true)]
    [ConfigurationCollection(typeof(EventsDispatchConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
    public GenericConfigurationElementCollection<EventsDispatchConfigurationElement> EventsDispatches
    {
        get { return (GenericConfigurationElementCollection<EventsDispatchConfigurationElement>)this["eventsDispatches"]; }
    }
}

विन्यास तत्व यहाँ कॉन्फ़िगर है:

public class EventsDispatchConfigurationElement : ConfigurationElement
{
    [ConfigurationProperty("name", IsRequired = true)]
    public string Name
    {
        get
        {
            return (string) this["name"];
        }
        set
        {
            this["name"] = value;
        }
    }
}

कॉन्फ़िगरेशन फ़ाइल इस तरह दिखाई देगी:

<?xml version="1.0" encoding="utf-8" ?>
  <dispatcherConfigurationSection>
    <eventsDispatches>
      <add name="Log" ></add>
      <add name="Notification" ></add>
      <add name="tester" ></add>
    </eventsDispatches>
  </dispatcherConfigurationSection>

आशा है कि यह मदद करेगा!


ठंडा! उसी के बारे में सोच रहा था और पाया कि मैं अकेला नहीं हूँ। विश एमएस लागू करें कि सभी एफसीएल
विन्यास के लिए

कैसे आइटम के लिए एक बुनियादी मानचित्र के साथ ऐसा करने के लिए कोई सुझाव? अगर मैं इससे बच सकता हूं तो मैं Add को लागू नहीं करना चाहता।
SpaceCowboy74

28

उन लोगों के लिए एक आसान विकल्प जो उन सभी कॉन्फ़िगरेशन बॉयलरप्लेट को मैन्युअल रूप से नहीं लिखना पसंद करेंगे ...

1) NuGet से Nerdle.AutoConfig स्थापित करें

2) अपने ServiceConfig प्रकार को परिभाषित करें (या तो एक ठोस वर्ग या सिर्फ एक इंटरफ़ेस, या तो करेंगे)

public interface IServiceConfiguration
{
    int Port { get; }
    ReportType ReportType { get; }
}

3) आपको संग्रह रखने के लिए एक प्रकार की आवश्यकता होगी, जैसे

public interface IServiceCollectionConfiguration
{
    IEnumerable<IServiceConfiguration> Services { get; } 
}

4) विन्यास अनुभाग को इस तरह जोड़ें (नोट कैमलकेस नामकरण)

<configSections>
  <section name="serviceCollection" type="Nerdle.AutoConfig.Section, Nerdle.AutoConfig"/>
</configSections>

<serviceCollection>
  <services>
    <service port="6996" reportType="File" />
    <service port="7001" reportType="Other" />
  </services>
</serviceCollection>

5) AutoConfig के साथ नक्शा

var services = AutoConfig.Map<IServiceCollectionConfiguration>();

5
इस उत्तर के लिए भगवान को धन्यवाद
Svend

उन लोगों के लिए जो बस काम करना चाहते हैं और जरूरी नहीं कि सब कुछ खरोंच से बनाया जाए, यही असली जवाब है :)
संहिता

5

कॉन्फ़िगरेशन से इनहेरिट करने का प्रयास करें । फिल हैक की इस ब्लॉग पोस्ट का एक उदाहरण है।

IConfigurationSectionHandler के दस्तावेज़ीकरण की पुष्टि :

.NET फ्रेमवर्क संस्करण 2.0 और इसके बाद के संस्करण में, आपको संबंधित कॉन्फ़िगरेशन अनुभाग हैंडलर को लागू करने के लिए कॉन्फ़िगरेशनसेक्शन वर्ग से प्राप्त करना होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.