2010-01-04 33 views
8

Tôi muốn có một tập tin cấu hình xml như sau:Làm thế nào để xác định một bộ sưu tập trong một configSection tùy chỉnh

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
<configSections> 
    <section name="plugins" type="MyApp.PluginsConfiguration, MyApp"/> 
</configSections> 

<plugins> 
    <use assembly="MyApp.Plugin1.dll" /> 
    <use assembly="MyApp.Plugin2.dll" /> 
</plugins> 
</configuration> 

Làm thế nào chính xác để tôi sắp xếp hưởng lẫn nhau giữa các PluginsConfigurations, UsePluginCollection, và các lớp UsePlugin trong mã của tôi ?

Tôi đã tìm thấy this tutorial trực tuyến nhưng nó sẽ giới thiệu một phần tử bên trong các plugin bao quanh bộ sưu tập sử dụng và tôi không cần điều này.

This là những gì tôi có cho đến nay nhưng nó không hoàn toàn đúng

Trả lời

16

Nếu MyApp.PluginsConfiguration là một ConfigurationSection, sau đó bạn có thể định nghĩa một lớp mới được thừa kế từ ConfigurationElementCollection và làm cho lớp mới một ConfigurationProperty của MyApp.PluginsConfiguration

Kiểm tra this article đối với một số sâu thông tin về những loại đó. Tôi cũng blogged about có thuộc tính lồng nhau, nhưng không dành riêng cho bộ sưu tập.

Chỉnh sửa: Đây với một số mã. Given là bit này trong web.config:

<configSections> 
    <section name="plugins" 
      type="WebApplication1.PluginsConfiguration, WebApplication1"/> 
</configSections> 
<plugins> 
    <use assembly="MyApp.Plugin1.dll"/> 
    <use assembly="MyApp.Plugin2.dll"/> 
</plugins> 

Đây là các lớp để thực hiện điều đó. Lưu ý rằng có thể NullReferenceExceptions cần phải được xử lý.

namespace WebApplication1 
{ 
    public class PluginsConfiguration : ConfigurationSection 
    { 
     private static ConfigurationPropertyCollection properties; 
     private static ConfigurationProperty propPlugins; 

     static PluginsConfiguration() 
     { 
      propPlugins = new ConfigurationProperty(null, typeof(PluginsElementCollection), 
                  null, 
                  ConfigurationPropertyOptions.IsDefaultCollection); 
      properties = new ConfigurationPropertyCollection { propPlugins }; 
     } 

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

     public PluginsElementCollection Plugins 
     { 
      get 
      { 
       return this[propPlugins] as PluginsElementCollection; 
      } 
     } 
    } 

    public class PluginsElementCollection : ConfigurationElementCollection 
    { 
     public PluginsElementCollection() 
     { 
      properties = new ConfigurationPropertyCollection(); 
     } 

     private static ConfigurationPropertyCollection properties; 

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

     public override ConfigurationElementCollectionType CollectionType 
     { 
      get 
      { 
       return ConfigurationElementCollectionType.BasicMap; 
      } 
     } 

     protected override string ElementName 
     { 
      get 
      { 
       return "use"; 
      } 
     } 

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

     protected override object GetElementKey(ConfigurationElement element) 
     { 
      var elm = element as PluginsElement; 
      if (elm == null) throw new ArgumentNullException(); 
      return elm.AssemblyName; 
     } 
    } 

    public class PluginsElement : ConfigurationElement 
    { 
     private static ConfigurationPropertyCollection properties; 
     private static ConfigurationProperty propAssembly; 

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

     public PluginsElement() 
     { 
      propAssembly = new ConfigurationProperty("assembly", typeof(string), 
                  null, 
                  ConfigurationPropertyOptions.IsKey); 
      properties = new ConfigurationPropertyCollection { propAssembly }; 
     } 

     public PluginsElement(string assemblyName) 
      : this() 
     { 
      AssemblyName = assemblyName; 
     } 

     public string AssemblyName 
     { 
      get 
      { 
       return this[propAssembly] as string; 
      } 
      set 
      { 
       this[propAssembly] = value; 
      } 
     } 
    } 
} 

Và để truy cập vào nó, đoạn mã này sẽ giúp:

 var cfg = WebConfigurationManager.GetWebApplicationSection("plugins") as PluginsConfiguration; 
     var sb = new StringBuilder(); 
     foreach(PluginsElement elem in cfg.Plugins) 
     { 
      sb.AppendFormat("{0}<br/>", elem.AssemblyName); 
     } 
     testLabel.Text = sb.ToString(); 

Về cơ bản chúng tôi có một ConfigurationSection để xử lý các phần tử plugins. Trong đó, chúng tôi chỉ định một thuộc tính ConfigurationElementCollection và khai báo nó là Bộ sưu tập Mặc định (bạn có thể trong lý thuyết có nhiều bộ sưu tập khác nhau dưới một nút gốc).

PluginsElementCollection triển khai ConfigurationElementCollection. ElementName phải là tên của thẻ, trong trường hợp "sử dụng" của chúng tôi. Ngoài ra, GetElementKey cần phải được ghi đè và phải trả về một thuộc tính duy nhất trong số các mục nhập.

PluginsElement sau đó triển khai một thẻ sử dụng duy nhất. Chúng tôi chỉ xác định một thuộc tính: AssemblyName, được ánh xạ tới thuộc tính assembly.

Tôi không khẳng định hoàn toàn hiểu được tất cả điều này (Đặc biệt ConfigurationElementCollection và nó khác nhau BaseAdd, BaseGet, vv thuộc tính không thực sự khám phá ở đây), nhưng tôi có thể khẳng định rằng công trình này :)

Ngoài ra, Nó không sử dụng bất kỳ thuộc tính nào. Tôi ghét thuộc tính - may mắn thay, tất cả các thuộc tính này có thể được chuyển đổi thành mã thích hợp. Bạn có thể sử dụng một hoặc khác (hoặc cả hai).

+0

Ngoài ra nếu bạn muốn, hãy xem System.Web.Configuration.CustomErrorsSection và những người khác bằng cách sử dụng hoặc là Reflector hoặc Debugging Server. Nhìn vào cách Microsoft triển khai các lớp học (IMHO khá phức tạp) này mang lại cái nhìn sâu sắc. –

+0

Tốt hơn tài liệu MSDN! thanx – Aliostad

+0

Chắc chắn tốt hơn MSDN. Cảm ơn rất nhiều! – Sergejs

4

Dựa trên hướng dẫn, bạn có thể dễ dàng tạo ra một cấu hình XML như sau:

<MyApp> 
    <Plugins> 
    <add assembly="MyApp.Plugin1.dll" /> 
    <add assembly="MyApp.Plugin2.dll" /> 
    </Plugins> 
</MyApp> 

Mà tôi thấy hoàn toàn chấp nhận được. Có lý do nào không thể chấp nhận được không?

Edit:

Tôi không chắc chắn chính xác như thế nào để làm điều đó với hướng dẫn. Bạn sẽ cần một số loại phần tử trung gian (như hướng dẫn có "hành động") - George Mauer

Ok, hãy thử kích thước này. Tôi có thể có một số lỗi chính tả vì tôi sao chép/dán/chỉnh sửa một số mã mà tôi đã sử dụng để thực hiện những gì bạn muốn, nhưng nó sẽ hoạt động với XML mà tôi đã định nghĩa ở trên.

public sealed class MyAppConfiguration : ConfigurationSection 
{ 
    public const string MyAppConfigurationTagName = "MyApp"; 
    [ConfigurationProperty(MyAppConfigurationTagName, IsRequired = true)] 
    public PluginConfigurationCollection Plugins 
    { 
     get 
     { 
      return this[MyAppConfigurationTagName] as PluginConfigurationCollection; 
     } 
     set 
     { 
      this[MyAppConfigurationTagName] = value; 
     } 
    } 
} 

public sealed class PluginConfigurationItem : ConfigurationElement 
{ 
    // repeat this pattern for each additional attribute you want in the <add /> tag. 
    // Only the assembly="foo.dll" portion is defined in this class, and is accessed 
    // via the AssemblyName property. 
    public const string AssemblyPropertyName = "assembly"; 
    [ConfigurationProperty(AssemblyPropertyName, IsRequired = true, IsKey = true)] 
    public string AssemblyName 
    { 
     get 
     { 
      return this[AssemblyPropertyName] as string; 
     } 
     set 
     { 
      this[AssemblyPropertyName] = value; 
     } 
    } 
} 

public class PluginConfigurationCollection : ConfigurationElementCollection, IEnumerable<PluginConfigurationItem> 
{ 
    public const string PluginsElementName = "Plugins"; 

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

    protected override object GetElementKey(ConfigurationElement element) 
    { 
     return ((PluginConfigurationItem)element).AssemblyName; 
    } 

    protected override string ElementName 
    { 
     get 
     { 
      return PluginsElementName; 
     } 
    } 

    // this is extraneous, but I find it very useful for enumerating over a configuration collection in a type-safe manner. 
    #region IEnumerable<PluginConfigurationItem> Members 

    public new IEnumerator<PluginConfigurationItem> GetEnumerator() 
    { 
     foreach(PluginConfigurationItem item in (this as IEnumerable)) 
     { 
      yield return item; 
     } 
    } 

    #endregion 
} 
+0

Tôi không chắc chắn chính xác cách thực hiện điều đó với hướng dẫn. Bạn sẽ cần một số loại phần tử trung gian (như hướng dẫn có "hành động") –

+1

Trong phương pháp này, bạn sẽ có thể sử dụng NameValueSectionHandler bên trong: http://msdn.microsoft.com/en-us/library/system. configuration.namevaluesectionhandler.aspx - Xin lỗi, không biết chính xác làm cách nào (tôi sẽ tự mình cuộn thành thật), nhưng Google cũng sẽ trợ giúp ở đây :) –

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