Added testcase for generic registrations and a workaround for the CLR GetInterfaces...
[castle.git] / InversionOfControl / Castle.MicroKernel / DefaultKernel.cs
blobf2782f2fcdd591fc73614722f42dbf66fc6d6a2a
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MicroKernel
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Reflection;
21 using System.Runtime.Serialization;
22 using Castle.Core;
23 using Castle.Core.Internal;
24 using Castle.MicroKernel.ComponentActivator;
25 using Castle.MicroKernel.Handlers;
26 using Castle.MicroKernel.ModelBuilder;
27 using Castle.MicroKernel.Proxy;
28 using Castle.MicroKernel.Registration;
29 using Castle.MicroKernel.Releasers;
30 using Castle.MicroKernel.Resolvers;
31 using Castle.MicroKernel.SubSystems.Configuration;
32 using Castle.MicroKernel.SubSystems.Conversion;
33 using Castle.MicroKernel.SubSystems.Naming;
34 using Castle.MicroKernel.SubSystems.Resource;
36 /// <summary>
37 /// Default implementation of <see cref="IKernel"/>.
38 /// This implementation is complete and also support a kernel
39 /// hierarchy (sub containers).
40 /// </summary>
41 [Serializable]
42 public class DefaultKernel : KernelEventSupport, IKernel, IDeserializationCallback
44 #region Fields
46 /// <summary>
47 /// The parent kernel, if exists.
48 /// </summary>
49 private IKernel parentKernel;
51 /// <summary>
52 /// The implementation of <see cref="IHandlerFactory"/>
53 /// </summary>
54 private IHandlerFactory handlerFactory;
56 /// <summary>
57 /// The implementation of <see cref="IComponentModelBuilder"/>
58 /// </summary>
59 private IComponentModelBuilder modelBuilder;
61 /// <summary>
62 /// The dependency resolver.
63 /// </summary>
64 private IDependencyResolver resolver;
66 /// <summary>
67 /// Implements a policy to control component's
68 /// disposal that the usef forgot.
69 /// </summary>
70 private IReleasePolicy releaserPolicy;
72 /// <summary>
73 /// Holds the implementation of <see cref="IProxyFactory"/>
74 /// </summary>
75 private IProxyFactory proxyFactory;
77 /// <summary>
78 /// List of <see cref="IFacility"/> registered.
79 /// </summary>
80 private IList facilities;
82 /// <summary>
83 /// Map of subsystems registered.
84 /// </summary>
85 private IDictionary subsystems;
87 /// <summary>
88 /// List of sub containers.
89 /// </summary>
90 private IList childKernels;
92 #endregion
94 #region Constructors
96 /// <summary>
97 /// Constructs a DefaultKernel with no component
98 /// proxy support.
99 /// </summary>
100 public DefaultKernel() : this(new NotSupportedProxyFactory())
104 /// <summary>
105 /// Constructs a DefaultKernel with the specified
106 /// implementation of <see cref="IProxyFactory"/> and <see cref="IDependencyResolver"/>
107 /// </summary>
108 /// <param name="resolver"></param>
109 /// <param name="proxyFactory"></param>
110 public DefaultKernel(IDependencyResolver resolver, IProxyFactory proxyFactory)
111 : this(proxyFactory)
113 this.resolver = resolver;
114 this.resolver.Initialize(RaiseDependencyResolving);
117 /// <summary>
118 /// Constructs a DefaultKernel with the specified
119 /// implementation of <see cref="IProxyFactory"/>
120 /// </summary>
121 public DefaultKernel(IProxyFactory proxyFactory)
123 this.proxyFactory = proxyFactory;
125 childKernels = new ArrayList();
126 facilities = new ArrayList();
127 subsystems = new Hashtable();
129 RegisterSubSystems();
131 releaserPolicy = new LifecycledComponentsReleasePolicy();
132 handlerFactory = new DefaultHandlerFactory(this);
133 modelBuilder = new DefaultComponentModelBuilder(this);
134 resolver = new DefaultDependencyResolver(this);
135 resolver.Initialize(new DependencyDelegate(RaiseDependencyResolving));
138 public DefaultKernel(SerializationInfo info, StreamingContext context)
139 : base(info, context)
141 MemberInfo[] members = FormatterServices.GetSerializableMembers(GetType(), context);
143 object[] kernelmembers = (object[])info.GetValue("members", typeof(object[]));
145 FormatterServices.PopulateObjectMembers(this, members, kernelmembers);
148 #endregion
150 #region Overridables
152 protected virtual void RegisterSubSystems()
154 AddSubSystem(SubSystemConstants.ConfigurationStoreKey,
155 new DefaultConfigurationStore());
157 AddSubSystem(SubSystemConstants.ConversionManagerKey,
158 new DefaultConversionManager());
160 AddSubSystem(SubSystemConstants.NamingKey,
161 new DefaultNamingSubSystem());
163 AddSubSystem(SubSystemConstants.ResourceKey,
164 new DefaultResourceSubSystem());
167 #endregion
169 #region IKernel Members
171 public virtual void AddComponent(String key, Type classType)
173 AddComponent(key, classType, classType);
176 /// <summary>
177 /// Adds a concrete class
178 /// as a component with the specified <paramref name="lifestyle"/>.
179 /// </summary>
180 /// <param name="key">The key with which to index the component.</param>
181 /// <param name="classType">The <see cref="Type"/> of the component.</param>
182 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
183 /// <remarks>
184 /// If you have indicated a lifestyle for the specified <paramref name="classType"/> using
185 /// attributes, this method will not overwrite that lifestyle. To do that, use the
186 /// <see cref="IKernel.AddComponent(string,Type,LifestyleType,bool)"/> method.
187 /// </remarks>
188 /// <exception cref="ArgumentNullException">
189 /// Thrown if <paramref name="key"/> or <paramref name="classType"/>
190 /// are <see langword="null"/>.
191 /// </exception>
192 /// <exception cref="ArgumentException">
193 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
194 /// </exception>
195 public void AddComponent(string key, Type classType, LifestyleType lifestyle)
197 AddComponent(key, classType, classType, lifestyle);
200 /// <summary>
201 /// Adds a concrete class
202 /// as a component with the specified <paramref name="lifestyle"/>.
203 /// </summary>
204 /// <param name="key">The key with which to index the component.</param>
205 /// <param name="classType">The <see cref="Type"/> of the component.</param>
206 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
207 /// <param name="overwriteLifestyle">
208 /// If <see langword="true"/>, then ignores all other configurations
209 /// for lifestyle and uses the value in the <paramref name="lifestyle"/> parameter.
210 /// </param>
211 /// <remarks>
212 /// If you have indicated a lifestyle for the specified <paramref name="classType"/> using
213 /// attributes, this method will not overwrite that lifestyle. To do that, use the
214 /// <see cref="IKernel.AddComponent(string,Type,Type,LifestyleType,bool)"/> method.
215 /// </remarks>
216 /// <exception cref="ArgumentNullException">
217 /// Thrown if <paramref name="key"/> or <paramref name="classType"/>
218 /// are <see langword="null"/>.
219 /// </exception>
220 /// <exception cref="ArgumentException" />
221 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
222 public void AddComponent(string key, Type classType, LifestyleType lifestyle, bool overwriteLifestyle)
224 AddComponent(key, classType, classType, lifestyle, overwriteLifestyle);
227 public virtual void AddComponent(String key, Type serviceType, Type classType)
229 AddComponent(key, serviceType, classType, LifestyleType.Singleton);
232 /// <summary>
233 /// Adds a concrete class and an interface
234 /// as a component with the specified <paramref name="lifestyle"/>.
235 /// </summary>
236 /// <param name="key">The key with which to index the component.</param>
237 /// <param name="serviceType">The service <see cref="Type"/> that this component implements.</param>
238 /// <param name="classType">The <see cref="Type"/> of the component.</param>
239 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
240 /// <remarks>
241 /// If you have indicated a lifestyle for the specified <paramref name="classType"/> using
242 /// attributes, this method will not overwrite that lifestyle. To do that, use the
243 /// <see cref="AddComponent(string,Type,Type,LifestyleType,bool)"/> method.
244 /// </remarks>
245 /// <exception cref="ArgumentNullException">
246 /// Thrown if <paramref name="key"/>, <paramref name="serviceType"/>, or <paramref name="classType"/>
247 /// are <see langword="null"/>.
248 /// </exception>
249 /// <exception cref="ArgumentException">
250 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
251 /// </exception>
252 public void AddComponent(string key, Type serviceType, Type classType, LifestyleType lifestyle)
254 AddComponent(key, serviceType, classType, lifestyle, false);
257 /// <summary>
258 /// Adds a concrete class and an interface
259 /// as a component with the specified <paramref name="lifestyle"/>.
260 /// </summary>
261 /// <param name="key">The key with which to index the component.</param>
262 /// <param name="serviceType">The service <see cref="Type"/> that this component implements.</param>
263 /// <param name="classType">The <see cref="Type"/> of the component.</param>
264 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
265 /// <param name="overwriteLifestyle">
266 /// If <see langword="true"/>, then ignores all other configurations
267 /// for lifestyle and uses the value in the <paramref name="lifestyle"/> parameter.
268 /// </param>
269 /// <remarks>
270 /// If you have indicated a lifestyle for the specified <paramref name="classType"/> using
271 /// attributes, this method will not overwrite that lifestyle. To do that, use the
272 /// <see cref="AddComponent(string,Type,Type,LifestyleType,bool)"/> method.
273 /// </remarks>
274 /// <exception cref="ArgumentNullException">
275 /// Thrown if <paramref name="key"/>, <paramref name="serviceType"/>, or <paramref name="classType"/>
276 /// are <see langword="null"/>.
277 /// </exception>
278 /// <exception cref="ArgumentException">
279 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
280 /// </exception>
281 public void AddComponent(string key, Type serviceType, Type classType, LifestyleType lifestyle,
282 bool overwriteLifestyle)
284 if (key == null) throw new ArgumentNullException("key");
285 if (serviceType == null) throw new ArgumentNullException("serviceType");
286 if (classType == null) throw new ArgumentNullException("classType");
287 if (LifestyleType.Undefined == lifestyle)
288 throw new ArgumentException("The specified lifestyle must be Thread, Transient, or Singleton.", "lifestyle");
290 ComponentModel model = ComponentModelBuilder.BuildModel(key, serviceType, classType, null);
292 if (overwriteLifestyle || LifestyleType.Undefined == model.LifestyleType)
294 model.LifestyleType = lifestyle;
297 RaiseComponentModelCreated(model);
299 IHandler handler = HandlerFactory.Create(model);
300 RegisterHandler(key, handler);
303 /// <summary>
304 ///
305 /// </summary>
306 /// <param name="key"></param>
307 /// <param name="classType"></param>
308 /// <param name="parameters"></param>
309 public virtual void AddComponentWithExtendedProperties(String key, Type classType, IDictionary parameters)
311 if (key == null) throw new ArgumentNullException("key");
312 if (parameters == null) throw new ArgumentNullException("parameters");
313 if (classType == null) throw new ArgumentNullException("classType");
315 ComponentModel model = ComponentModelBuilder.BuildModel(key, classType, classType, parameters);
316 RaiseComponentModelCreated(model);
317 IHandler handler = HandlerFactory.Create(model);
318 RegisterHandler(key, handler);
321 /// <summary>
322 ///
323 /// </summary>
324 /// <param name="key"></param>
325 /// <param name="serviceType"></param>
326 /// <param name="classType"></param>
327 /// <param name="parameters"></param>
328 public virtual void AddComponentWithExtendedProperties(String key, Type serviceType, Type classType,
329 IDictionary parameters)
331 if (key == null) throw new ArgumentNullException("key");
332 if (parameters == null) throw new ArgumentNullException("parameters");
333 if (serviceType == null) throw new ArgumentNullException("serviceType");
334 if (classType == null) throw new ArgumentNullException("classType");
336 ComponentModel model = ComponentModelBuilder.BuildModel(key, serviceType, classType, parameters);
337 RaiseComponentModelCreated(model);
338 IHandler handler = HandlerFactory.Create(model);
339 RegisterHandler(key, handler);
342 /// <summary>
343 ///
344 /// </summary>
345 /// <param name="model"></param>
346 public virtual void AddCustomComponent(ComponentModel model)
348 if (model == null) throw new ArgumentNullException("model");
350 RaiseComponentModelCreated(model);
351 IHandler handler = HandlerFactory.Create(model);
353 object skipRegistration = model.ExtendedProperties[ComponentModel.SkipRegistration];
355 if (skipRegistration != null)
357 RegisterHandler(model.Name, handler, (bool)skipRegistration);
359 else
361 RegisterHandler(model.Name, handler);
365 /// <summary>
366 /// Used mostly by facilities. Adds an instance
367 /// to be used as a component.
368 /// </summary>
369 /// <param name="key"></param>
370 /// <param name="instance"></param>
371 public void AddComponentInstance(String key, object instance)
373 if (key == null) throw new ArgumentNullException("key");
374 if (instance == null) throw new ArgumentNullException("instance");
376 Type classType = instance.GetType();
378 ComponentModel model = new ComponentModel(key, classType, classType);
379 model.CustomComponentActivator = typeof(ExternalInstanceActivator);
380 model.ExtendedProperties["instance"] = instance;
382 RaiseComponentModelCreated(model);
383 IHandler handler = HandlerFactory.Create(model);
384 RegisterHandler(key, handler);
387 /// <summary>
388 /// Used mostly by facilities. Adds an instance
389 /// to be used as a component.
390 /// </summary>
391 /// <param name="key"></param>
392 /// <param name="serviceType"></param>
393 /// <param name="instance"></param>
394 public void AddComponentInstance(String key, Type serviceType, object instance)
396 AddComponentInstance(key, serviceType, instance.GetType(), instance);
399 public void AddComponentInstance(string key, Type serviceType, Type classType, object instance)
401 if (key == null) throw new ArgumentNullException("key");
402 if (serviceType == null) throw new ArgumentNullException("serviceType");
403 if (instance == null) throw new ArgumentNullException("instance");
404 if (classType == null) throw new ArgumentNullException("classType");
406 ComponentModel model = new ComponentModel(key, serviceType, classType);
407 model.CustomComponentActivator = typeof(ExternalInstanceActivator);
408 model.ExtendedProperties["instance"] = instance;
410 RaiseComponentModelCreated(model);
411 IHandler handler = HandlerFactory.Create(model);
412 RegisterHandler(key, handler);
415 /// <summary>
416 /// Adds a concrete class as a component
417 /// </summary>
418 public void AddComponent<T>()
420 Type classType = typeof(T);
421 AddComponent(classType.FullName, classType);
424 /// <summary>
425 /// Adds a concrete class
426 /// as a component with the specified <paramref name="lifestyle"/>.
427 /// </summary>
428 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
429 /// <remarks>
430 /// If you have indicated a lifestyle for the specified T using
431 /// attributes, this method will not overwrite that lifestyle. To do that, use the
432 /// <see cref="AddComponent(string,Type,LifestyleType,bool)"/> method.
433 /// </remarks>
434 /// <exception cref="ArgumentException">
435 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
436 /// </exception>
437 public void AddComponent<T>(LifestyleType lifestyle)
439 Type classType = typeof(T);
440 AddComponent(classType.FullName, classType, lifestyle);
443 /// <summary>
444 /// Adds a concrete class
445 /// as a component with the specified <paramref name="lifestyle"/>.
446 /// </summary>
447 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
448 /// <param name="overwriteLifestyle">If <see langword="true"/>, then ignores all other configurations
449 /// for lifestyle and uses the value in the <paramref name="lifestyle"/> parameter.</param>
450 /// <remarks>
451 /// If you have indicated a lifestyle for the specified T using
452 /// attributes, this method will not overwrite that lifestyle. To do that, use the
453 /// <see cref="AddComponent(string,Type,LifestyleType,bool)"/> method.
454 /// </remarks>
455 /// <exception cref="ArgumentException"/>
456 /// Thrown if
457 /// <paramref name="lifestyle"/>
458 /// is
459 /// <see cref="LifestyleType.Undefined"/>
460 /// .
461 public void AddComponent<T>(LifestyleType lifestyle, bool overwriteLifestyle)
463 Type classType = typeof(T);
464 AddComponent(classType.FullName, classType, lifestyle, overwriteLifestyle);
467 /// <summary>
468 /// Adds a concrete class and an interface
469 /// as a component
470 /// </summary>
471 /// <param name="serviceType">The service <see cref="Type"/> that this component implements.</param>
472 public void AddComponent<T>(Type serviceType)
474 Type classType = typeof(T);
475 AddComponent(classType.FullName, serviceType, classType);
478 /// <summary>
479 /// Adds a concrete class and an interface
480 /// as a component with the specified <paramref name="lifestyle"/>.
481 /// </summary>
482 /// <param name="serviceType">The service <see cref="Type"/> that this component implements.</param>
483 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
484 /// <remarks>
485 /// If you have indicated a lifestyle for the specified T using
486 /// attributes, this method will not overwrite that lifestyle. To do that, use the
487 /// <see cref="AddComponent(string,Type,Type,LifestyleType,bool)"/> method.
488 /// </remarks>
489 /// <exception cref="ArgumentNullException">
490 /// are <see langword="null"/>.
491 /// </exception>
492 /// <exception cref="ArgumentException">
493 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
494 /// </exception>
495 public void AddComponent<T>(Type serviceType, LifestyleType lifestyle)
497 Type classType = typeof(T);
498 AddComponent(classType.FullName, serviceType, classType, lifestyle);
501 /// <summary>
502 /// Adds a concrete class and an interface
503 /// as a component with the specified <paramref name="lifestyle"/>.
504 /// </summary>
505 /// <param name="serviceType">The service <see cref="Type"/> that this component implements.</param>
506 /// <param name="lifestyle">The specified <see cref="LifestyleType"/> for the component.</param>
507 /// <param name="overwriteLifestyle">If <see langword="true"/>, then ignores all other configurations
508 /// for lifestyle and uses the value in the <paramref name="lifestyle"/> parameter.</param>
509 /// <remarks>
510 /// attributes, this method will not overwrite that lifestyle. To do that, use the
511 /// <see cref="AddComponent(string,Type,Type,LifestyleType,bool)"/> method.
512 /// </remarks>
513 /// <exception cref="ArgumentNullException">
514 /// are <see langword="null"/>.
515 /// </exception>
516 /// <exception cref="ArgumentException">
517 /// Thrown if <paramref name="lifestyle"/> is <see cref="LifestyleType.Undefined"/>.
518 /// </exception>
519 public void AddComponent<T>(Type serviceType, LifestyleType lifestyle, bool overwriteLifestyle)
521 Type classType = typeof(T);
522 AddComponent(classType.FullName, serviceType, classType, lifestyle, overwriteLifestyle);
525 /// <summary>
526 /// Used mostly by facilities. Adds an instance
527 /// to be used as a component.
528 /// </summary>
529 /// <param name="instance"></param>
530 public void AddComponentInstance<T>(object instance)
532 Type serviceType = typeof(T);
533 AddComponentInstance(serviceType.FullName, serviceType, instance);
536 /// <summary>
537 /// Used mostly by facilities. Adds an instance
538 /// to be used as a component.
539 /// </summary>
540 /// <param name="serviceType"></param>
541 /// <param name="instance"></param>
542 public void AddComponentInstance<T>(Type serviceType, object instance)
544 Type classType = typeof(T);
545 AddComponentInstance(classType.FullName, serviceType, classType, instance);
548 /// <summary>
549 /// Registers the components described by the <see cref="ComponentRegistration{S}"/>s
550 /// with the <see cref="IKernel"/>.
551 /// <param name="registrations">The component registrations.</param>
552 /// <returns>The kernel.</returns>
553 /// </summary>
554 public IKernel Register(params IRegistration[] registrations)
556 if (registrations == null)
558 throw new ArgumentNullException("registrations");
561 foreach(IRegistration registration in registrations)
563 registration.Register(this);
566 return this;
569 /// <summary>
570 /// Returns the component instance by the service type
571 /// using dynamic arguments
572 /// </summary>
573 /// <param name="arguments"></param>
574 /// <returns></returns>
575 public T Resolve<T>(IDictionary arguments)
577 Type serviceType = typeof(T);
578 return (T)Resolve(serviceType, arguments);
581 /// <summary>
582 /// Returns the component instance by the service type
583 /// using dynamic arguments
584 /// </summary>
585 /// <param name="argumentsAsAnonymousType"></param>
586 /// <returns></returns>
587 public T Resolve<T>(object argumentsAsAnonymousType)
589 return Resolve<T>(new ReflectionBasedDictionaryAdapter(argumentsAsAnonymousType));
592 /// <summary>
593 /// Returns the component instance by the component key
594 /// </summary>
595 /// <returns></returns>
596 public T Resolve<T>()
598 Type serviceType = typeof(T);
599 return (T)Resolve(serviceType);
602 /// <summary>
603 /// Returns true if the specified component was
604 /// found and could be removed (i.e. no other component depends on it)
605 /// </summary>
606 /// <param name="key">The component's key</param>
607 /// <returns></returns>
608 public virtual bool RemoveComponent(String key)
610 if (key == null) throw new ArgumentNullException("key");
612 if (NamingSubSystem.Contains(key))
614 IHandler handler = GetHandler(key);
616 if (handler.ComponentModel.Dependers.Length == 0)
618 NamingSubSystem.UnRegister(key);
620 IHandler[] assignableHandlers = GetAssignableHandlers(handler.ComponentModel.Service);
621 if (assignableHandlers.Length > 0)
623 NamingSubSystem[handler.ComponentModel.Service] = assignableHandlers[0];
625 else
627 NamingSubSystem.UnRegister(handler.ComponentModel.Service);
630 foreach (ComponentModel model in handler.ComponentModel.Dependents)
632 model.RemoveDepender(handler.ComponentModel);
635 RaiseComponentUnregistered(key, handler);
637 DisposeHandler(handler);
639 return true;
641 else
643 // We can't remove this component as there are
644 // others which depends on it
646 return false;
650 if (Parent != null)
652 return Parent.RemoveComponent(key);
655 return false;
658 public virtual bool HasComponent(String key)
660 if (key == null) throw new ArgumentNullException("key");
662 if (NamingSubSystem.Contains(key))
664 return true;
667 if (Parent != null)
669 return Parent.HasComponent(key);
672 return false;
675 public virtual bool HasComponent(Type serviceType)
677 if (serviceType == null) throw new ArgumentNullException("serviceType");
679 if (NamingSubSystem.Contains(serviceType))
681 return true;
684 if (serviceType.IsGenericType && NamingSubSystem.Contains(serviceType.GetGenericTypeDefinition()))
686 return true;
689 if (Parent != null)
691 return Parent.HasComponent(serviceType);
694 return false;
697 public virtual object this[String key]
701 if (key == null) throw new ArgumentNullException("key");
703 if (!HasComponent(key))
705 throw new ComponentNotFoundException(key);
708 IHandler handler = GetHandler(key);
710 return ResolveComponent(handler);
714 public virtual object this[Type service]
718 if (service == null) throw new ArgumentNullException("service");
720 if (!HasComponent(service))
722 throw new ComponentNotFoundException(service);
725 IHandler handler = GetHandler(service);
727 return ResolveComponent(handler, service);
731 /// <summary>
732 /// Returns the component instance by the service type
733 /// </summary>
734 public object Resolve(Type service)
736 if (service == null) throw new ArgumentNullException("service");
738 return this[service];
741 /// <summary>
742 /// Returns all the valid component instances by
743 /// the service type
744 /// </summary>
745 /// <param name="service">The service type</param>
746 /// <param name="arguments">Arguments to resolve the services</param>
747 public Array ResolveAll(Type service, IDictionary arguments)
749 ArrayList list = new ArrayList();
750 IHandler[] handlers = GetAssignableHandlers(service);
751 foreach (IHandler handler in handlers)
753 object component = ResolveComponent(handler, service, arguments);
754 list.Add(component);
756 return list.ToArray(service);
759 /// <summary>
760 /// Returns all the valid component instances by
761 /// the service type
762 /// </summary>
763 /// <param name="service">The service type</param>
764 /// <param name="argumentsAsAnonymousType">Arguments to resolve the services</param>
765 public Array ResolveAll(Type service, object argumentsAsAnonymousType)
767 return ResolveAll(service, new ReflectionBasedDictionaryAdapter(argumentsAsAnonymousType));
770 /// <summary>
771 /// Returns the component instance by the service type
772 /// using dynamic arguments
773 /// </summary>
774 /// <param name="service"></param>
775 /// <param name="arguments"></param>
776 /// <returns></returns>
777 public object Resolve(Type service, IDictionary arguments)
779 if (service == null) throw new ArgumentNullException("service");
780 if (arguments == null) throw new ArgumentNullException("arguments");
782 if (!HasComponent(service))
784 throw new ComponentNotFoundException(service);
787 IHandler handler = GetHandler(service);
789 return ResolveComponent(handler, service, arguments);
792 /// <summary>
793 /// Returns the component instance by the service type
794 /// using dynamic arguments
795 /// </summary>
796 /// <param name="service"></param>
797 /// <param name="argumentsAsAnonymousType"></param>
798 /// <returns></returns>
799 public object Resolve(Type service, object argumentsAsAnonymousType)
801 return Resolve(service, new ReflectionBasedDictionaryAdapter(argumentsAsAnonymousType));
804 /// <summary>
805 /// Returns the component instance by the component key
806 /// using dynamic arguments
807 /// </summary>
808 /// <param name="key"></param>
809 /// <param name="arguments"></param>
810 /// <returns></returns>
811 public object Resolve(string key, IDictionary arguments)
813 if (key == null) throw new ArgumentNullException("key");
814 if (arguments == null) throw new ArgumentNullException("arguments");
816 if (!HasComponent(key))
818 throw new ComponentNotFoundException(key);
821 IHandler handler = GetHandler(key);
823 return ResolveComponent(handler, arguments);
826 /// <summary>
827 /// Returns the component instance by the component key
828 /// using dynamic arguments
829 /// </summary>
830 /// <param name="key"></param>
831 /// <param name="argumentsAsAnonymousType"></param>
832 /// <returns></returns>
833 public object Resolve(string key, object argumentsAsAnonymousType)
835 return Resolve(key, new ReflectionBasedDictionaryAdapter(argumentsAsAnonymousType));
838 /// <summary>
839 /// Associates objects with a component handler,
840 /// allowing it to use the specified dictionary
841 /// when resolving dependencies
842 /// </summary>
843 /// <param name="service"></param>
844 /// <param name="dependencies"></param>
845 public void RegisterCustomDependencies(Type service, IDictionary dependencies)
847 IHandler handler = GetHandler(service);
849 foreach (DictionaryEntry entry in dependencies)
851 handler.AddCustomDependencyValue(entry.Key.ToString(), entry.Value);
855 /// <summary>
856 /// Associates objects with a component handler,
857 /// allowing it to use the specified dictionary
858 /// when resolving dependencies
859 /// </summary>
860 /// <param name="service"></param>
861 /// <param name="dependenciesAsAnonymousType"></param>
862 public void RegisterCustomDependencies(Type service, object dependenciesAsAnonymousType)
864 RegisterCustomDependencies(service, new ReflectionBasedDictionaryAdapter(dependenciesAsAnonymousType));
867 /// <summary>
868 /// Associates objects with a component handler,
869 /// allowing it to use the specified dictionary
870 /// when resolving dependencies
871 /// </summary>
872 /// <param name="key"></param>
873 /// <param name="dependencies"></param>
874 public void RegisterCustomDependencies(String key, IDictionary dependencies)
876 IHandler handler = GetHandler(key);
878 foreach (DictionaryEntry entry in dependencies)
880 handler.AddCustomDependencyValue(entry.Key.ToString(), entry.Value);
884 /// <summary>
885 /// Associates objects with a component handler,
886 /// allowing it to use the specified dictionary
887 /// when resolving dependencies
888 /// </summary>
889 /// <param name="key"></param>
890 /// <param name="dependenciesAsAnonymousType"></param>
891 public void RegisterCustomDependencies(String key, object dependenciesAsAnonymousType)
893 RegisterCustomDependencies(key, new ReflectionBasedDictionaryAdapter(dependenciesAsAnonymousType));
896 /// <summary>
897 /// Returns a component instance by the key
898 /// </summary>
899 /// <param name="key"></param>
900 /// <param name="service"></param>
901 /// <returns></returns>
902 public virtual object Resolve(String key, Type service)
904 if (key == null) throw new ArgumentNullException("key");
905 if (service == null) throw new ArgumentNullException("service");
907 if (!HasComponent(key))
909 throw new ComponentNotFoundException(key);
912 IHandler handler = GetHandler(key);
914 return ResolveComponent(handler, service);
918 public TService[] ResolveServices<TService>()
920 List<TService> services = new List<TService>();
921 IHandler[] handlers = GetHandlers(typeof(TService));
923 foreach (IHandler handler in handlers)
925 if (handler.CurrentState == HandlerState.Valid)
927 services.Add((TService)ResolveComponent(handler));
931 return services.ToArray();
934 /// <summary>
935 /// Returns a component instance by the key
936 /// </summary>
937 /// <param name="key"></param>
938 /// <param name="service"></param>
939 /// <param name="arguments"></param>
940 /// <returns></returns>
941 public virtual object Resolve(String key, Type service, IDictionary arguments)
943 if (key == null) throw new ArgumentNullException("key");
944 if (service == null) throw new ArgumentNullException("service");
946 if (!HasComponent(key))
948 throw new ComponentNotFoundException(key);
951 IHandler handler = GetHandler(key);
953 return ResolveComponent(handler, service, arguments);
956 /// <summary>
957 /// Resolves the specified key.
958 /// </summary>
959 /// <param name="key">The key.</param>
960 /// <param name="service">The service.</param>
961 /// <param name="argumentsAsAnonymousType">Type of the arguments as anonymous.</param>
962 /// <returns></returns>
963 public virtual object Resolve(String key, Type service, object argumentsAsAnonymousType)
965 return Resolve(key, service, new ReflectionBasedDictionaryAdapter(argumentsAsAnonymousType));
968 /// <summary>
969 /// Releases a component instance. This allows
970 /// the kernel to execute the proper decomission
971 /// lifecycles on the component instance.
972 /// </summary>
973 /// <param name="instance"></param>
974 public virtual void ReleaseComponent(object instance)
976 if (ReleasePolicy.HasTrack(instance))
978 ReleasePolicy.Release(instance);
980 else
982 if (Parent != null)
984 Parent.ReleaseComponent(instance);
989 public IHandlerFactory HandlerFactory
991 get { return handlerFactory; }
994 public IComponentModelBuilder ComponentModelBuilder
996 get { return modelBuilder; }
997 set { modelBuilder = value; }
1000 public IProxyFactory ProxyFactory
1002 get { return proxyFactory; }
1003 set { proxyFactory = value; }
1006 public virtual IConfigurationStore ConfigurationStore
1008 get { return GetSubSystem(SubSystemConstants.ConfigurationStoreKey) as IConfigurationStore; }
1009 set { AddSubSystem(SubSystemConstants.ConfigurationStoreKey, value); }
1012 public virtual IHandler GetHandler(String key)
1014 if (key == null) throw new ArgumentNullException("key");
1016 IHandler handler = NamingSubSystem.GetHandler(key);
1018 if (handler == null && Parent != null)
1020 handler = WrapParentHandler(Parent.GetHandler(key));
1023 return handler;
1026 public virtual IHandler GetHandler(Type service)
1028 if (service == null) throw new ArgumentNullException("service");
1030 IHandler handler = NamingSubSystem.GetHandler(service);
1032 if (handler == null && service.IsGenericType)
1034 handler = NamingSubSystem.GetHandler(service.GetGenericTypeDefinition());
1037 if (handler == null && Parent != null)
1039 handler = WrapParentHandler(Parent.GetHandler(service));
1042 return handler;
1045 /// <summary>
1046 /// Return handlers for components that
1047 /// implements the specified service.
1048 /// </summary>
1049 /// <param name="service"></param>
1050 /// <returns></returns>
1051 public virtual IHandler[] GetHandlers(Type service)
1053 IHandler[] result = NamingSubSystem.GetHandlers(service);
1055 // a complete generic type, Foo<Bar>, need to check if Foo<T> is registered
1056 if (service.IsGenericType && !service.IsGenericTypeDefinition)
1058 IHandler[] genericResult = NamingSubSystem.GetHandlers(service.GetGenericTypeDefinition());
1060 if (result.Length > 0)
1062 IHandler[] mergedResult = new IHandler[result.Length + genericResult.Length];
1063 result.CopyTo(mergedResult, 0);
1064 genericResult.CopyTo(mergedResult, result.Length);
1065 result = mergedResult;
1067 else
1069 result = genericResult;
1073 // If a parent kernel exists, we merge both results
1074 if (Parent != null)
1076 IHandler[] parentResult = Parent.GetHandlers(service);
1078 if (parentResult.Length > 0)
1080 IHandler[] newResult = new IHandler[result.Length + parentResult.Length];
1081 result.CopyTo(newResult, 0);
1082 parentResult.CopyTo(newResult, result.Length);
1083 result = newResult;
1087 return result;
1090 /// <summary>
1091 /// Return handlers for components that
1092 /// implements the specified service.
1093 /// The check is made using IsAssignableFrom
1094 /// </summary>
1095 /// <param name="service"></param>
1096 /// <returns></returns>
1097 public virtual IHandler[] GetAssignableHandlers(Type service)
1099 return NamingSubSystem.GetAssignableHandlers(service);
1102 public virtual IReleasePolicy ReleasePolicy
1104 get { return releaserPolicy; }
1105 set { releaserPolicy = value; }
1108 public virtual void AddFacility(String key, IFacility facility)
1110 if (key == null) throw new ArgumentNullException("key");
1111 if (facility == null) throw new ArgumentNullException("facility");
1113 facility.Init(this, ConfigurationStore.GetFacilityConfiguration(key));
1115 facilities.Add(facility);
1118 /// <summary>
1119 /// Returns the facilities registered on the kernel.
1120 /// </summary>
1121 /// <returns></returns>
1122 public virtual IFacility[] GetFacilities()
1124 IFacility[] list = new IFacility[facilities.Count];
1125 facilities.CopyTo(list, 0);
1126 return list;
1129 public virtual void AddSubSystem(String key, ISubSystem subsystem)
1131 if (key == null) throw new ArgumentNullException("key");
1132 if (subsystem == null) throw new ArgumentNullException("facility");
1134 subsystem.Init(this);
1135 subsystems[key] = subsystem;
1138 public virtual ISubSystem GetSubSystem(String key)
1140 if (key == null) throw new ArgumentNullException("key");
1142 return subsystems[key] as ISubSystem;
1145 public virtual void AddChildKernel(IKernel childKernel)
1147 if (childKernel == null) throw new ArgumentNullException("childKernel");
1149 childKernel.Parent = this;
1150 childKernels.Add(childKernel);
1153 public virtual IKernel Parent
1155 get { return parentKernel; }
1158 // TODO: should the raise add/removed as child kernel methods be invoked from within the subscriber/unsubscribe methods?
1160 if (value == null)
1162 if (parentKernel != null)
1164 UnsubscribeFromParentKernel();
1165 RaiseRemovedAsChildKernel();
1168 parentKernel = null;
1170 else
1172 if ((parentKernel != value) && (parentKernel != null))
1174 throw new KernelException(
1175 "You can not change the kernel parent once set, use the RemoveChildKernel and AddChildKernel methods together to achieve this.");
1177 parentKernel = value;
1178 SubscribeToParentKernel();
1179 RaiseAddedAsChildKernel();
1184 public IDependencyResolver Resolver
1186 get { return resolver; }
1189 public virtual IComponentActivator CreateComponentActivator(ComponentModel model)
1191 if (model == null) throw new ArgumentNullException("model");
1193 IComponentActivator activator;
1195 if (model.CustomComponentActivator == null)
1197 activator = new DefaultComponentActivator(model, this,
1198 new ComponentInstanceDelegate(RaiseComponentCreated),
1199 new ComponentInstanceDelegate(RaiseComponentDestroyed));
1201 else
1205 activator = (IComponentActivator)
1206 Activator.CreateInstance(model.CustomComponentActivator,
1207 new object[]
1209 model,
1210 this,
1211 new ComponentInstanceDelegate(RaiseComponentCreated),
1212 new ComponentInstanceDelegate(RaiseComponentDestroyed)
1215 catch (Exception e)
1217 throw new KernelException("Could not instantiate custom activator", e);
1221 return activator;
1224 /// <summary>
1225 /// Graph of components and iteractions.
1226 /// </summary>
1227 public GraphNode[] GraphNodes
1231 GraphNode[] nodes = new GraphNode[NamingSubSystem.ComponentCount];
1233 int index = 0;
1235 IHandler[] handlers = NamingSubSystem.GetHandlers();
1237 foreach (IHandler handler in handlers)
1239 nodes[index++] = handler.ComponentModel;
1242 return nodes;
1246 public virtual void RemoveChildKernel(IKernel childKernel)
1248 if (childKernel == null) throw new ArgumentNullException("childKernel");
1249 childKernel.Parent = null;
1250 childKernels.Remove(childKernel);
1253 #endregion
1255 #region IServiceProviderEx Members
1257 /// <summary>
1258 /// Gets the service object of the specified type.
1259 /// </summary>
1261 /// <returns>
1262 /// A service object of type serviceType.
1263 /// </returns>
1265 /// <param name="serviceType">An object that specifies the type of service object to get. </param>
1266 public object GetService(Type serviceType)
1268 if (!HasComponent(serviceType))
1270 return null;
1273 return Resolve(serviceType);
1276 /// <summary>
1277 /// Gets the service object of the specified type.
1278 /// </summary>
1280 /// <returns>
1281 /// A service object of type serviceType.
1282 /// </returns>
1283 public T GetService<T>() where T : class
1285 Type serviceType = typeof(T);
1287 if (!HasComponent(serviceType))
1289 return null;
1292 return (T)Resolve(serviceType);
1295 #endregion
1297 #region IDisposable Members
1299 /// <summary>
1300 /// Starts the process of component disposal.
1301 /// </summary>
1302 public virtual void Dispose()
1304 DisposeSubKernels();
1305 TerminateFacilities();
1306 DisposeComponentsInstancesWithinTracker();
1307 DisposeHandlers();
1308 UnsubscribeFromParentKernel();
1311 private void TerminateFacilities()
1313 foreach (IFacility facility in facilities)
1315 facility.Terminate();
1319 private void DisposeHandlers()
1321 GraphNode[] nodes = GraphNodes;
1322 IVertex[] vertices = TopologicalSortAlgo.Sort(nodes);
1324 for (int i = 0; i < vertices.Length; i++)
1326 ComponentModel model = (ComponentModel)vertices[i];
1328 // Prevent the removal of a component that belongs
1329 // to other container
1330 if (!NamingSubSystem.Contains(model.Name)) continue;
1332 RemoveComponent(model.Name);
1336 private void UnsubscribeFromParentKernel()
1338 if (parentKernel != null)
1340 parentKernel.HandlerRegistered -= new HandlerDelegate(HandlerRegisteredOnParentKernel);
1341 parentKernel.ComponentRegistered -= new ComponentDataDelegate(RaiseComponentRegistered);
1342 parentKernel.ComponentUnregistered -= new ComponentDataDelegate(RaiseComponentUnregistered);
1346 private void SubscribeToParentKernel()
1348 if (parentKernel != null)
1350 parentKernel.HandlerRegistered += new HandlerDelegate(HandlerRegisteredOnParentKernel);
1351 parentKernel.ComponentRegistered += new ComponentDataDelegate(RaiseComponentRegistered);
1352 parentKernel.ComponentUnregistered += new ComponentDataDelegate(RaiseComponentUnregistered);
1356 private void HandlerRegisteredOnParentKernel(IHandler handler, ref bool stateChanged)
1358 RaiseHandlerRegistered(handler);
1361 private void DisposeComponentsInstancesWithinTracker()
1363 ReleasePolicy.Dispose();
1366 private void DisposeSubKernels()
1368 foreach (IKernel childKernel in childKernels)
1370 childKernel.Dispose();
1374 protected void DisposeHandler(IHandler handler)
1376 if (handler == null) return;
1378 if (handler is IDisposable)
1380 ((IDisposable)handler).Dispose();
1384 #endregion
1386 #region Protected members
1388 protected virtual IHandler WrapParentHandler(IHandler parentHandler)
1390 if (parentHandler == null) return null;
1392 // This has a very destructive side-effect. While the goal is to resolve on same-level containers,
1393 // the resolver will invoke GetHandler recursively, leading to stack overflows
1394 // return new ParentHandlerWithChildResolver(parentHandler, Resolver);
1395 return parentHandler;
1398 protected INamingSubSystem NamingSubSystem
1400 get { return GetSubSystem(SubSystemConstants.NamingKey) as INamingSubSystem; }
1403 protected void RegisterHandler(String key, IHandler handler)
1405 RegisterHandler(key, handler, false);
1408 protected void RegisterHandler(String key, IHandler handler, bool skipRegistration)
1410 if (!skipRegistration)
1412 NamingSubSystem.Register(key, handler);
1415 base.RaiseHandlerRegistered(handler);
1416 base.RaiseComponentRegistered(key, handler);
1419 protected object ResolveComponent(IHandler handler)
1421 return ResolveComponent(handler, handler.ComponentModel.Service);
1424 protected object ResolveComponent(IHandler handler, Type service)
1426 return ResolveComponent(handler, service, null);
1429 protected object ResolveComponent(IHandler handler, IDictionary additionalArguments)
1431 return ResolveComponent(handler, handler.ComponentModel.Service, additionalArguments);
1434 protected object ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments)
1436 CreationContext context = CreateCreationContext(handler, service, additionalArguments);
1438 object instance = handler.Resolve(context);
1440 ReleasePolicy.Track(instance, handler);
1442 return instance;
1445 protected CreationContext CreateCreationContext(IHandler handler, Type typeToExtractGenericArguments,
1446 IDictionary additionalArguments)
1448 return new CreationContext(handler, typeToExtractGenericArguments, additionalArguments);
1451 #endregion
1453 #region Serialization and Deserialization
1455 public override void GetObjectData(SerializationInfo info, StreamingContext context)
1457 base.GetObjectData(info, context);
1459 MemberInfo[] members = FormatterServices.GetSerializableMembers(GetType(), context);
1461 object[] kernelmembers = FormatterServices.GetObjectData(this, members);
1463 info.AddValue("members", kernelmembers, typeof(object[]));
1466 void IDeserializationCallback.OnDeserialization(object sender)
1470 #endregion