Here is a working implementation of Avalon.Net: I would like to hear from you about a few design decisions I made. To understand a little more, explore the code while you read the following sections. The zip file is attached to another post (I posted yesterday but the mailer refused it)
-= The beginning =- Keeping the XP principles attached to my monitor, I created a simple DefaultContainer class. The standard use is a simple instantiantion: DefaultContainer container = new DefaultContainer(); This kind of use tries to obtain the configuration from ConfigurationSettings .Net class. If it can't be done, an exception is throwed. The user can construct a config by himself and pass on to DefaultContainer: String configFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; ContainerConfiguration config = new ContainerConfiguration(configFile); DefaultContainer container = new DefaultContainer(config); -= Configuration section =- The configuration is handled by Apache.Avalon.Container.Configuration.ContainerConfiguration / Apache.Avalon.Container.Configuration.ContainerConfigurationSectionHandler pair. The format follows .Net standards: <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="avalon.container" type="Apache.Avalon.Container.Configuration.ContainerConfigurationSectionHan dler, Apache.Avalon.Container" /> </configSections> <avalon.container> <components> <assembly type="Apache.Avalon.Container.Test" /> <component configurationName="Samples.Components\Authentication" > <username>JohnDoe</username> </component> </components> </avalon.container> </configuration> The assembly element adds assemblies to container. The container considers true Avalon components/services classes which holds attribute AvalonServiceAttribute. Others importants details are exposed by AvalonComponentAttribute (should be apart?) The configuration name maps what the component itself told us about it's configuration, like: [AvalonService( typeof(IAuthentication) )] [AvalonComponent( @"Samples.Components\Authentication", Lifestyle.Transient, LoggerName="AuthLog" )] public class Authentication : IAuthentication, IInitializable, ILogEnabled, IConfigurable, IDisposable <...> So one should feel free to use any convention he wants. -= Lyfestyle =- Lyfestyle are managed by AbstractComponentFactory. I don't like this way - used in Fortress - cause is too fragile, but didn't have time to think in another way without using proxies. I added a new lifestyle named Custom but a Field is missing to allow the component to tell us which Type is the factory for it. Currently Lifestyles supported are: * Transient (Duh!) * Singleton * Thread -= ComponentFactory =- As stated in the TO DO List, the factories aren't considered true components, so no "events" are fired to them (yet). Anyway they are de-coupled (I think its the wrong word!) from container code. In fact the class FactoryBuilder searchs the current assembly for types which holds the LyfestyleTargetAttribute attribute. Optionally a factory can tell which Builder manages it. Using an associated Builder was fine and permitted clean factories implementations. Factories which don't supports Custom Builder are handled by a common Builder (FactoryBuilder). For instance this is the SingletonComponentFactory implementation: /// <summary> /// Summary description for SingletonComponentFactory. /// </summary> [CustomBuilder(typeof(SingletonComponentFactoryBuilder))] [LifestyleTarget(Lifestyle.Singleton)] internal class SingletonComponentFactory : AbstractComponentFactory { public SingletonComponentFactory(Type componentType) : base(componentType) { } public override bool IsReusable { get { return true; } } public override object Create(ComponentEntry entry) { if (m_instance == null) { return base.Create(entry); } return m_instance; } public override void Destroy(object componentInstance) { // Can't call Dispose in a singleton component } } /// <summary> /// <see cref="SingletonComponentFactoryBuilder"/> is a <see cref="FactoryBuilder"/> /// implementation for <see cref="SingletonComponentFactory"/> that /// keep instances of factories /// </summary> internal sealed class SingletonComponentFactoryBuilder : FactoryBuilder { private static Hashtable factories = new Hashtable(); public SingletonComponentFactoryBuilder() { } public override IComponentFactory GetFactory(Type componentType) { IComponentFactory factory = null; lock(factories) { factory = (IComponentFactory) factories[componentType]; if (factory == null) { factory = new SingletonComponentFactory(componentType); factories[componentType] = factory; } } return factory; } } And to implement the ThreadComponentFactory was even simpler: /// <summary> /// Summary description for ThreadComponentFactory. /// </summary> [CustomBuilder(typeof(ThreadComponentFactoryBuilder))] [LifestyleTarget(Lifestyle.Thread)] internal class ThreadComponentFactory : SingletonComponentFactory { public ThreadComponentFactory(Type componentType) : base(componentType) { } } /// <summary> /// /// </summary> internal sealed class ThreadComponentFactoryBuilder : FactoryBuilder { private static readonly LocalDataStoreSlot threadSlot = Thread.AllocateDataSlot(); public ThreadComponentFactoryBuilder() { } public override IComponentFactory GetFactory(Type componentType) { // TODO: Add syncronization code // TODO: Could be easily refactored to // extend SingletonComponentFactoryBuilder Hashtable factories = (Hashtable) Thread.GetData(threadSlot); if (factories == null) { factories = new Hashtable(); Thread.SetData(threadSlot, factories); } IComponentFactory factory = null; lock(factories) { factory = (IComponentFactory) factories[componentType]; if (factory == null) { factory = new SingletonComponentFactory(componentType); factories[componentType] = factory; } } return factory; } } I hope you guys like it :-) -= Extensions =- I didn't write any extensions or some supported to them neither. But it should be easy to add them in the next day as soon as Logger/Lookup works in a decent way. -= Samples =- I added two projects as samples. A Web project and a components project. Web uses the components project. I'm focusing the Web cause it will be my primary use, with cross process boundaries issues. By now there is not NAnt build files yet. -= Code conventions =- I tried hard to follow Avalon conventions despite the fact it differs from MS recomendations (Pascal case and Camel case). Avalon seems to use a mix of Hungarian notation and Java convention. Also I used the Jeffrey Ritcher recommended style for declaring "using": namespace Apache.Avalon.Container { using System; using System.Xml; using System.Collections; using System.Collections.Specialized; using Apache.Avalon.Framework; /// <summary> /// /// </summary> public class ComponentEntry Didn't know what to do about constants (CAPITALIZE?) and static fields so I used the convetion I'm used to. -= CVS =- Don't know if it is the right time to upload it to avalon-sandbox, but for sure it's the right time to criticize it and make suggestions. Anyway I'm attaching a ZIP file (last time I used CVS diff I had a CR/LF problem) I made several modifications in framework project and pratically rewritten the container project, so it's now using a different project tree: cscontainer + AvalonContainer . Attributes . Configuration . Factory . Lookup . Util . AvalonContainerTest + Samples . Components . Web . bin (binary, pdb and config files used by Test Cases) csframework . AvalonFramework . AvalonFrameworkTest . bin This tree is humam readable and integrated with VS.Net. You'll find a TO DO List.txt in cscontainer\AvalonConainer directory. Regards, hammett --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]