2011-08-15 23 views
9

Tôi đang cố gắng viết một phần cấu hình tùy chỉnh rất đơn giản cho một ứng dụng .NET4. Mục tiêu của tôi là thế này:Cấu hình tùy chỉnh đơn giản với bộ sưu tập trong .NET4

<configuration> 
    <configSections> 
    <section name="myServices" type="My.ConfigSection, My.Assembly" /> 
    </configSections> 
    <myServices> 
    <add name="First" /> 
    <add name="Second" /> 
    </myServices> 
</configuration> 

Tuy nhiên, tôi cứ bị một ConfigurationErrorsException: 'yếu tố không được nhận 'thêm'' khi tôi gọi ConfigurationManager.GetSection("myServices"). Tôi đã nhìn chằm chằm vào nó một lúc rồi nhưng chưa tìm ra điều tôi đang làm sai. Dưới đây là mã của tôi. Đó là ba lớp: ConfigSection, MyServiceSettingsCollectionMyServiceSettings.

Đầu tiên là lớp đại diện cho toàn bộ phần cấu hình. Nó có bộ sưu tập mặc định không tên loại MyServiceSettingsCollection. Thuộc tính IsDefaultCollection sẽ cho phép tôi 'thêm' trực tiếp vào bộ sưu tập của tôi từ phần tử gốc.

public sealed class ConfigSection : ConfigurationSection 
{ 
    private static readonly ConfigurationProperty _propMyServices; 

    private static readonly ConfigurationPropertyCollection _properties; 

    public static ConfigSection Instance { get { return _instance; } } 

    static ConfigSection() 
    { 
    _propMyServices = new ConfigurationProperty(
      null, typeof(MyServiceSettingsCollection), null, 
      ConfigurationPropertyOptions.IsDefaultCollection); 
    _properties = new ConfigurationPropertyCollection { _propMyServices }; 
    } 

    [ConfigurationProperty("", IsDefaultCollection = true)] 
    public MyServiceSettingsCollection MyServices 
    { 
    get { return (MyServiceSettingsCollection) base[_propMyServices]; } 
    set { base[_propMyServices] = value; } 
    } 

    protected override ConfigurationPropertyCollection Properties 
    { get { return _properties; } } 
} 

Tiếp theo, chính lớp thu thập. Nó thuộc loại AddRemoveClearMap.

[ConfigurationCollection(typeof(MyServiceSettings), 
    CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)] 
public sealed class MyServiceSettingsCollection : ConfigurationElementCollection 
{ 
    public MyServiceSettings this[int index] 
    { 
    get { return (MyServiceSettings) BaseGet(index); } 
    set 
    { 
     if (BaseGet(index) != null) { BaseRemoveAt(index); } 
     BaseAdd(index, value); 
    } 
    } 

    public new MyServiceSettings this[string key] 
    { 
    get { return (MyServiceSettings) BaseGet(key); } 
    } 

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

    protected override object GetElementKey(ConfigurationElement element) 
    { 
    return ((MyServiceSettings) element).Key; 
    } 
} 

Và cuối cùng là lớp cho các phần tử trong bộ sưu tập. Bây giờ, lớp này có một thuộc tính nhưng sẽ có nhiều hơn sau này (điều này ngăn cản tôi sử dụng NameValueSectionHandler).

public class MyServiceSettings : ConfigurationElement 
{ 
    private static readonly ConfigurationProperty _propName; 

    private static readonly ConfigurationPropertyCollection properties; 

    static MyServiceSettings() 
    { 
    _propName = new ConfigurationProperty("name", typeof(string), null, null, 
              new StringValidator(1), 
              ConfigurationPropertyOptions.IsRequired | 
              ConfigurationPropertyOptions.IsKey); 
    properties = new ConfigurationPropertyCollection { _propName }; 
    } 

    [ConfigurationProperty("name", DefaultValue = "", 
     Options = ConfigurationPropertyOptions.IsRequired | 
        ConfigurationPropertyOptions.IsKey)] 
    public string Name 
    { 
     get { return (string) base[_propKey]; } 
     set { base[_propKey] = value; } 
    } 

    protected override ConfigurationPropertyCollection Properties 
    { get { return properties; } } 
} 

Trả lời

11

Ok, tôi thấy việc sửa chữa dường như ngẫu nhiên. Thay vì điều này:

[ConfigurationProperty("", IsDefaultCollection = true)] 
public ProvisiorServiceSettingsCollection ProvisiorServices 
{ ... } 

bạn nên sử dụng:

[ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)] 
public ProvisiorServiceSettingsCollection ProvisiorServices 
{ ... } 

Không có ý tưởng gì là sự khác biệt giữa hai người. Đối với tôi, họ trông khá giống nhau ... hoặc ít nhất, không có đề nghị nào ở bất cứ đâu tại sao người ta lại ưa thích cái kia hơn.

+0

nhưng tốt để biết cách hoạt động - sẽ có điều gì đó tương tự để đạt được trong các tuần tới, vì vậy cảm ơn :-) – Yahia

+0

Điều đó thật lạ. Cả hai 'IsDefaultCollection' và' Options' làm việc cho tôi. Nhưng có chuỗi rỗng cho tên tài sản có vẻ là bắt buộc. –

+0

Nhìn vào nguồn tham chiếu cho ConfigurationPropertyAttribute.cs, thuộc tính IsDefaultCollection chỉ là một trình bao bọc trong thuộc tính Tùy chọn cờ - http://referencesource.microsoft.com/#System.Configuration/System/Configuration/ConfigurationPropertyAttribute.cs,62 –

3

có vẻ như bạn đang thiếu một cái gì đó tương tự như sau

[ConfigurationProperty("urls", IsDefaultCollection = false)] 
    [ConfigurationCollection(typeof(UrlsCollection), 
     AddItemName = "add", 
     ClearItemsName = "clear", 
     RemoveItemName = "remove")] 

để biết thêm thông tin, xem http://msdn.microsoft.com/en-us/library/system.configuration.configurationcollectionattribute.aspx

+0

Đã thử điều đó và nó không hoạt động. Tôi đã tìm thấy câu trả lời, sẽ sớm thêm câu trả lời. –

+0

một tùy chọn khác - xem mục nhập cuối cùng tại http://www.sitepoint.com/forums/net-141/problem-custom-config-section-419546.html – Yahia

+0

Đã xem bài đăng trên diễn đàn đó. Trước khi đặt câu hỏi này, tôi đã sử dụng tất cả các kỹ năng của Google để tìm câu trả lời :) –

3

Kể từ khi tôi đã dành một số lượng tốt của thời gian về vấn đề này, nghĩ rằng tôi muốn thêm một ví dụ thế giới thực tôi chỉ thực hiện trong cam kết này: https://github.com/rhythmagency/formulate/commit/4d2a95e1a82eb6b3500ab0869b8f8b15bd3deaa9

Dưới đây là mục tiêu của tôi cho web.config của tôi (mà tôi đã có thể để đạt được):

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <sectionGroup name="formulateConfiguration"> 
     <section name="templates" type="formulate.app.Configuration.TemplatesConfigSection, formulate.app" requirePermission="false"/> 
    </sectionGroup> 
    </configSections> 
    <formulateConfiguration> 
    <templates> 
     <template name="Responsive" path="~/Views/Formulate/Responsive.Bootstrap.Angular.cshtml" /> 
    </templates> 
    </formulateConfiguration> 
</configuration> 

Đây là lớp học cho các cấp cao nhất "mẫu" phần cấu hình:

namespace formulate.app.Configuration 
{ 

    // Namespaces. 
    using System.Configuration; 


    /// <summary> 
    /// A configuration section for Formulate templates. 
    /// </summary> 
    public class TemplatesConfigSection : ConfigurationSection 
    { 

     #region Properties 

     /// <summary> 
     /// The templates in this configuration section. 
     /// </summary> 
     [ConfigurationProperty("", IsDefaultCollection = true)] 
     [ConfigurationCollection(typeof(TemplateCollection), AddItemName = "template")] 
     public TemplateCollection Templates 
     { 
      get 
      { 
       return base[""] as TemplateCollection; 
      } 
     } 

     #endregion 

    } 

} 

Đây là cấp độ tiếp theo xuống, bộ sưu tập lớp:

namespace formulate.app.Configuration 
{ 

    // Namespaces. 
    using System.Configuration; 


    /// <summary> 
    /// A collection of templates from the configuration. 
    /// </summary> 
    [ConfigurationCollection(typeof(TemplateElement))] 
    public class TemplateCollection : ConfigurationElementCollection 
    { 

     #region Methods 

     /// <summary> 
     /// Creates a new template element. 
     /// </summary> 
     /// <returns>The template element.</returns> 
     protected override ConfigurationElement CreateNewElement() 
     { 
      return new TemplateElement(); 
     } 


     /// <summary> 
     /// Gets the key for an element. 
     /// </summary> 
     /// <param name="element">The element.</param> 
     /// <returns>The key.</returns> 
     protected override object GetElementKey(ConfigurationElement element) 
     { 
      return (element as TemplateElement).Name; 
     } 

     #endregion 

    } 

} 

Và đây là lớp mức sâu nhất (các mẫu cá nhân):

namespace formulate.app.Configuration 
{ 

    // Namespaces. 
    using System.Configuration; 


    /// <summary> 
    /// A "template" configuration element. 
    /// </summary> 
    public class TemplateElement : ConfigurationElement 
    { 

     #region Constants 

     private const string DefaultPath = "~/*Replace Me*.cshtml"; 

     #endregion 


     #region Properties 

     /// <summary> 
     /// The name of the template. 
     /// </summary> 
     [ConfigurationProperty("name", IsRequired = true)] 
     public string Name 
     { 
      get 
      { 
       return base["name"] as string; 
      } 
      set 
      { 
       this["name"] = value; 
      } 
     } 


     /// <summary> 
     /// The path to this template. 
     /// </summary> 
     /// <remarks> 
     /// Should start with "~" and end with ".cshtml". 
     /// </remarks> 
     [ConfigurationProperty("path", IsRequired = true, DefaultValue = DefaultPath)] 
     [RegexStringValidator(@"^~.*\.[cC][sS][hH][tT][mM][lL]$")] 
     public string Path 
     { 
      get 
      { 
       var result = base["path"] as string; 
       return result == DefaultPath ? null : result; 
      } 
      set 
      { 
       this["path"] = value; 
      } 
     } 

     #endregion 

    } 

} 

Các bit quan trọng đối với tôi là để có chuỗi rỗng trong ConfigurationPropertyAttribute và thiết IsDefaultCollection là true.Bằng cách này, tôi đặt cấu hình của tôi trong một tập tin bên ngoài trông như thế này:

<?xml version="1.0" encoding="utf-8" ?> 
<templates> 
    <template name="Responsive" path="~/Views/Formulate/Responsive.Bootstrap.Angular.cshtml" /> 
</templates> 

Và trong trường hợp đó, web.config của tôi trông như thế này:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <sectionGroup name="formulateConfiguration"> 
     <section name="templates" type="formulate.app.Configuration.TemplatesConfigSection, formulate.app" requirePermission="false"/> 
    </sectionGroup> 
    </configSections> 
    <formulateConfiguration> 
    <templates configSource="config\Formulate\templates.config"/> 
    </formulateConfiguration> 
</configuration> 

đặn tôi muốn đề cập đến đó trong trường hợp ai đó đang cố gắng thêm nó vào một tệp bên ngoài (có phần không trực quan là mục cấp gốc trong tệp bên ngoài cũng giống như phần tử bên ngoài từ web.config).

Các vấn đề liên quan