2010-01-04 8 views
8

Ich mag würde eine XML-Konfigurationsdatei haben, wie folgt:Wie eine Sammlung in einem benutzerdefinierten configSection angeben

<?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> 

Wie genau vereinbare ich das Zusammenspiel zwischen den PluginsConfigurations, UsePluginCollection und UsePlugin Klassen in meinem Code ?

Ich fand this tutorial online, aber es würde ein Element innerhalb von Plugins, die die Verwendung Sammlung umgibt, und ich brauche das nicht.

This ist, was ich bisher habe, aber es ist nicht ganz richtig

Antwort

16

Wenn MyApp.PluginsConfiguration ein Configuration ist, dann können Sie eine neue Klasse definieren, die von Configuration erbt und die neue Klasse

prüfen this article für einige vertiefte Informationen über eine Configuration von MyApp.PluginsConfiguration machen diese Arten. Ich auch blogged about geschachtelte Eigenschaften, aber nicht speziell für Sammlungen.

Edit: Hier mit etwas Code. Gegeben ist dieses Bit im web.config:

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

Hier sind die Klassen um das zu ermöglichen. Beachten Sie, dass möglicherweise NullReferenceExceptions behandelt werden müssen.

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; 
      } 
     } 
    } 
} 

Und es zugreifen kann, sollten diese Code-Schnipsel helfen:

 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(); 

Grundsätzlich haben wir eine Configuration, die das Plug-ins-Element behandelt. In diesem geben wir eine ConfigurationElementCollection-Eigenschaft an und deklarieren sie als die Standard-Sammlung (Sie könnten theoretisch mehrere verschiedene Sammlungen unter einem Stammknoten haben).

PluginsElementCollection implementiert die ConfigurationElementCollection. ElementName muss der Name des Tags sein, in unserem Fall "use". Außerdem muss GetElementKey außer Kraft gesetzt werden und ein Attribut zurückgeben, das unter den Einträgen eindeutig ist.

PluginsElement implementiert dann ein einmal verwendbares Tag. Wir definieren nur eine Eigenschaft: AssemblyName, die dem assembly-Attribut zugeordnet ist.

Ich behaupte nicht vollständig, dies alles zu verstehen (vor allem Configuration und es verschiedene BaseAdd, BaseGet usw. Eigenschaften nicht wirklich hier erforscht), aber ich kann behaupten, dass dies funktioniert :)

auch an, verwendet keine Attribute. Ich hasse Attribute - zum Glück können alle diese Attribute in den richtigen Code umgewandelt werden. Du könntest das eine oder das andere (oder beide) benutzen.

+0

Auch wenn Sie wollen, schauen Sie sich System.Web.Configuration.CustomErrorsSection und andere mit entweder Reflektor oder der Debugging-Server. Wenn man sich ansieht, wie Microsoft diese (IMHO ziemlich komplizierten) Klassen implementiert, gibt das einen guten Einblick. –

+0

Besser als MSDN-Dokumente! thanx – Aliostad

+0

Definitiv besser als MSDN. Vielen Dank! – Sergejs

4

Basierend auf dem Tutorial, könnte man leicht eine XML-Konfiguration wie folgt erstellen:

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

Was ich durchaus akzeptabel finden. Gibt es einen Grund, warum das nicht akzeptabel wäre?

Edit:

Ich bin nicht sicher, wie genau mit dem Tutorial, das zu tun. Sie würden eine Art von Zwischenelement benötigen (wie das Tutorial hat „Aktionen“) - George Mauer

Ok, versuchen Sie dies für die Größe auf. Ich habe vielleicht einige Tippfehler, da ich einen Code kopiere/einfüge/bearbeite, den ich benutzt habe, der das tut, was du willst, aber er sollte mit dem XML funktionieren, das ich oben definiert habe.

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

Ich bin nicht sicher, wie genau das mit dem Tutorial zu tun. Sie benötigen eine Art Zwischenelement (wie im Tutorial "Aktionen"). –

+1

Bei diesem Ansatz sollten Sie in der Lage sein, den internen NameValueSectionHandler zu verwenden: http://msdn.microsoft.com/en-us/library/system. configuration.namevaluesectionhandler.aspx - Entschuldigung, ich weiß nicht genau, wie (würde ich meine ehrlich zu rollen), aber Google würde hier helfen :) –

Verwandte Themen