User: xtoff
Date: 2009/11/15 03:40 PM
Added:
/InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
LazyLoadingTestCase.cs
/InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/
ILazyComponentLoader.cs
Modified:
/InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
Castle.MicroKernel.Tests-vs2008.csproj
/InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/
MyLifestyleHandler.cs
/InversionOfControl/trunk/src/Castle.MicroKernel/
Castle.MicroKernel-vs2008.csproj, DefaultKernel.cs, DefaultKernel_Resolve.cs
/InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/
AbstractHandler.cs, DefaultHandler.cs
Log:
- fixed IOC-ISSUE-161 - Add hook to allow resolution of unregistered
components.
File Changes:
Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/
============================================================
File [modified]: Castle.MicroKernel-vs2008.csproj
Delta lines: +21 -9
===================================================================
--- InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel.cs
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -727,7 +727,7 @@
/// <param name="serviceType">An object that specifies the type
of service object to get. </param>
public object GetService(Type serviceType)
{
- if (!HasComponent(serviceType))
+ if (!HasComponent(serviceType) &&
!LazyLoadComponent(null, serviceType))
{
return null;
}
@@ -744,14 +744,7 @@
/// </returns>
public T GetService<T>() where T : class
{
- Type serviceType = typeof(T);
-
- if (!HasComponent(serviceType))
- {
- return null;
- }
-
- return (T)Resolve(serviceType);
+ return (T)GetService(typeof(T));
}
#endregion
@@ -951,5 +944,24 @@
#endif
#endregion
+
+ private bool LazyLoadComponent(string key, Type service)
+ {
+ if (key == null && service == null)
+ {
+ throw new ArgumentException("At least one - key
or service must not be a null reference.");
+ }
+
+ foreach (var loader in
ResolveAll<ILazyComponentLoader>())
+ {
+ var registration = loader.Load(key, service);
+ if (registration != null)
+ {
+ registration.Register(this);
+ return true;
+ }
+ }
+ return false;
+ }
}
File [modified]: DefaultKernel.cs
Delta lines: +6 -6
===================================================================
--- InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel_Resolve.cs
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel_Resolve.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -91,7 +91,7 @@
{
if (key == null) throw new
ArgumentNullException("key");
- if (!HasComponent(key))
+ if (!HasComponent(key) &&
!LazyLoadComponent(key, null))
{
throw new
ComponentNotFoundException(key);
}
@@ -108,7 +108,7 @@
{
if (service == null) throw new
ArgumentNullException("service");
- if (!HasComponent(service))
+ if (!HasComponent(service) &&
!LazyLoadComponent(null, service))
{
throw new
ComponentNotFoundException(service);
}
@@ -219,7 +219,7 @@
if (service == null) throw new
ArgumentNullException("service");
if (arguments == null) throw new
ArgumentNullException("arguments");
- if (!HasComponent(service))
+ if (!HasComponent(service) && !LazyLoadComponent(null,
service))
{
throw new ComponentNotFoundException(service);
}
@@ -253,7 +253,7 @@
if (key == null) throw new ArgumentNullException("key");
if (arguments == null) throw new
ArgumentNullException("arguments");
- if (!HasComponent(key))
+ if (!HasComponent(key) && !LazyLoadComponent(key, null))
{
throw new ComponentNotFoundException(key);
}
@@ -286,7 +286,7 @@
if (key == null) throw new ArgumentNullException("key");
if (service == null) throw new
ArgumentNullException("service");
- if (!HasComponent(key))
+ if (!HasComponent(key) && !LazyLoadComponent(key,
service))
{
throw new ComponentNotFoundException(key);
}
@@ -319,7 +319,7 @@
if (key == null) throw new ArgumentNullException("key");
if (service == null) throw new
ArgumentNullException("service");
- if (!HasComponent(key))
+ if (!HasComponent(key) &&
!LazyLoadComponent(key,service))
{
throw new ComponentNotFoundException(key);
File [modified]: DefaultKernel_Resolve.cs
Delta lines: +22 -21
===================================================================
--- InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/AbstractHandler.cs
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/AbstractHandler.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -16,6 +16,7 @@
{
using System;
using System.Collections;
+ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text;
@@ -36,12 +37,12 @@
/// <summary>
/// Dictionary of Type to a list of <see
cref="DependencyModel"/>
/// </summary>
- private IDictionary dependenciesByService;
+ private IDictionary<Type, DependencyModel>
dependenciesByService;
/// <summary>
/// Dictionary of key (string) to <see cref="DependencyModel"/>
/// </summary>
- private IDictionary dependenciesByKey;
+ private IDictionary<string, DependencyModel> dependenciesByKey;
/// <summary>
/// Custom dependencies values associated with the handler
@@ -292,9 +293,9 @@
{
sb.Append("\r\nKeys (components with specific
keys)\r\n");
- foreach (DictionaryEntry entry in
DependenciesByKey)
+ foreach (var dependency in DependenciesByKey)
{
- String key = entry.Key.ToString();
+ String key = dependency.Key;
IHandler handler =
Kernel.GetHandler(key);
@@ -486,14 +487,14 @@
if (dependency.DependencyType == DependencyType.Service
&& dependency.TargetType != null)
{
- if
(DependenciesByService.Contains(dependency.TargetType))
+ if
(DependenciesByService.ContainsKey(dependency.TargetType))
{
return;
}
DependenciesByService.Add(dependency.TargetType, dependency);
}
- else if
(!DependenciesByKey.Contains(dependency.DependencyKey))
+ else if
(!DependenciesByKey.ContainsKey(dependency.DependencyKey))
{
DependenciesByKey.Add(dependency.DependencyKey,
dependency);
}
@@ -552,11 +553,11 @@
// Check within the Kernel
- foreach (DictionaryEntry kvp in new
Hashtable(DependenciesByService))
+ foreach (var pair in new
Dictionary<Type,DependencyModel>(DependenciesByService))
{
- Type service = (Type)kvp.Key;
- DependencyModel dependencyModel =
(DependencyModel)kvp.Value;
- if (HasValidComponent(service, dependencyModel))
+ Type service = pair.Key;
+ DependencyModel dependency = pair.Value;
+ if (HasValidComponent(service, dependency))
{
DependenciesByService.Remove(service);
IHandler dependingHandler =
kernel.GetHandler(service);
@@ -565,14 +566,14 @@
}
}
- foreach (DictionaryEntry kvp in new
Hashtable(DependenciesByKey))
+ foreach (var pair in new
Dictionary<string,DependencyModel>(DependenciesByKey))
{
- string compKey = (string)kvp.Key;
- DependencyModel dependency =
(DependencyModel)kvp.Value;
- if (HasValidComponent(compKey, dependency) ||
HasCustomParameter(compKey))
+ string key = pair.Key;
+ DependencyModel dependency = pair.Value;
+ if (HasValidComponent(key, dependency) ||
HasCustomParameter(key))
{
- DependenciesByKey.Remove(compKey);
- IHandler dependingHandler =
kernel.GetHandler(compKey);
+ DependenciesByKey.Remove(key);
+ IHandler dependingHandler =
kernel.GetHandler(key);
if(dependingHandler!=null)//may not be
real handler, if we are using sub resovler
AddGraphDependency(dependingHandler.ComponentModel);
}
@@ -648,25 +649,25 @@
state = newState;
}
- protected IDictionary DependenciesByService
+ protected IDictionary<Type,DependencyModel>
DependenciesByService
{
get
{
if (dependenciesByService == null)
{
- dependenciesByService = new
HybridDictionary();
+ dependenciesByService = new
Dictionary<Type, DependencyModel>();
}
return dependenciesByService;
}
}
- protected IDictionary DependenciesByKey
+ protected IDictionary<string, DependencyModel> DependenciesByKey
{
get
{
if (dependenciesByKey == null)
{
- dependenciesByKey = new
HybridDictionary();
+ dependenciesByKey = new
Dictionary<string, DependencyModel>();
}
return dependenciesByKey;
}
@@ -727,7 +728,7 @@
ComponentModel.AddDependent(model);
}
- private DependencyModel[] Union(ICollection firstset,
ICollection secondset)
+ private DependencyModel[] Union(ICollection<DependencyModel>
firstset, ICollection<DependencyModel> secondset)
{
DependencyModel[] result = new
DependencyModel[firstset.Count + secondset.Count];
Directory: /InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
==================================================================
File [modified]: Castle.MicroKernel.Tests-vs2008.csproj
Delta lines: +139 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/LazyLoadingTestCase.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/LazyLoadingTestCase.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -0,0 +1,139 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.MicroKernel.Tests
+{
+ using System;
+
+ using Castle.MicroKernel.Registration;
+ using Castle.MicroKernel.Resolvers;
+
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class LazyLoadingTestCase
+ {
+ private IKernel kernel;
+
+ [SetUp]
+ public void SetUp()
+ {
+ kernel = new DefaultKernel();
+
kernel.AddComponent<Loader>(typeof(ILazyComponentLoader));
+ }
+
+ [Test]
+ public void Can_Lazily_resolve_component()
+ {
+
+ var service = kernel.Resolve("foo",
typeof(IHasDefaultImplementation));
+ Assert.IsNotNull(service);
+ Assert.IsInstanceOf<Implementation>(service);
+ }
+
+ [Test]
+ public void Can_lazily_resolve_dependency()
+ {
+ kernel.AddComponent<UsingLazyComponent>();
+ var component = kernel.Resolve<UsingLazyComponent>();
+ Assert.IsNotNull(component.Dependency);
+ }
+
+ [Test]
+ [Ignore("Not sure how to do this in an elegant way... plus I
don't think it's the right place for this anyway.")]
+ public void Can_lazily_resolve_parameters()
+ {
+ kernel.AddComponent<UsingString>();
+ var component = kernel.Resolve<UsingString>();
+ Assert.AreEqual("Foo", component.Parameter);
+ }
+ }
+
+ public class Loader : ILazyComponentLoader
+ {
+
+ public IRegistration Load(string key, Type service)
+ {
+ if (!Attribute.IsDefined(service,
typeof(DefaultImplementationAttribute)))
+ {
+ return null;
+ }
+
+ var attributes =
service.GetCustomAttributes(typeof(DefaultImplementationAttribute), false);
+ var attribute = attributes[0] as
DefaultImplementationAttribute;
+ return
Component.For(service).ImplementedBy(attribute.Implementation).Named(key);
+ }
+ }
+
+ public class UsingString
+ {
+ private readonly string parameter;
+
+ public UsingString(string parameter)
+ {
+ this.parameter = parameter;
+ }
+
+ public string Parameter
+ {
+ get { return parameter; }
+ }
+ }
+
+
+ public class UsingLazyComponent
+ {
+ private IHasDefaultImplementation dependency;
+
+ public UsingLazyComponent(IHasDefaultImplementation dependency)
+ {
+ this.dependency = dependency;
+ }
+
+ public IHasDefaultImplementation Dependency
+ {
+ get { return dependency; }
+ }
+ }
+
+ [DefaultImplementation(typeof(Implementation))]
+ public interface IHasDefaultImplementation
+ {
+ void Foo();
+ }
+
+ public class Implementation : IHasDefaultImplementation
+ {
+ public void Foo()
+ {
+
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Interface,AllowMultiple = false)]
+ public class DefaultImplementationAttribute:Attribute
+ {
+ private readonly Type implementation;
+
+ public DefaultImplementationAttribute(Type implementation)
+ {
+ this.implementation = implementation;
+ }
+
+ public Type Implementation
+ {
+ get { return implementation; }
+ }
+ }
+}
File [added]: LazyLoadingTestCase.cs
Delta lines: +4 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/MyLifestyleHandler.cs
2009-11-15 22:33:44 UTC (rev 6334)
+++
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/MyLifestyleHandler.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -18,6 +18,10 @@
public class MyLifestyleHandler : AbstractLifestyleManager
{
+ public MyLifestyleHandler()
+ {
+ }
+
public override void Dispose()
{
Directory:
/InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/
=======================================================================================
File [modified]: MyLifestyleHandler.cs
Delta lines: +0 -0
===================================================================
Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/
=====================================================================
File [modified]: AbstractHandler.cs
Delta lines: +33 -4
===================================================================
--- InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/DefaultHandler.cs
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/DefaultHandler.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -16,7 +16,11 @@
{
using System;
using System.Collections;
+ using System.Linq;
+
using Castle.Core;
+ using Castle.MicroKernel.Resolvers;
+ using Castle.MicroKernel.SubSystems.Naming;
/// <summary>
/// Summary description for DefaultHandler.
@@ -66,18 +70,24 @@
if (context.HandlerIsCurrentlyBeingResolved(this))
return false;
- foreach (Type service in DependenciesByService.Keys)
+ foreach (var dependency in
DependenciesByService.Values.ToArray())
{
// a self-dependency is not allowed
- var handler = Kernel.GetHandler(service);
+ var handler =
Kernel.GetHandler(dependency.TargetType);
if (handler == this)
return false;
// ask the kernel
- if (!Kernel.HasComponent(service))
+ if (Kernel.HasComponent(dependency.TargetType))
continue;
+
+ // let's try to lazy load the dependency...
+ if
(!LazyLoadComponent(dependency.DependencyKey, dependency.TargetType))
return false;
+ // and see if we can have it this time around
+ // if the previous call returned true we always
should
+ if (!Kernel.HasComponent(dependency.TargetType))
+ return false;
}
-
return DependenciesByKey.Count == 0;
}
@@ -102,5 +112,24 @@
throw new HandlerException(message);
}
}
+
+ private bool LazyLoadComponent(string dependencyKey, Type
targetType)
+ {
+ if (dependencyKey == null && targetType == null)
+ {
+ throw new ArgumentException("At least one -
dependencyKey or targetType must not be a null reference.");
+ }
+
+ foreach (var loader in
Kernel.ResolveAll<ILazyComponentLoader>())
+ {
+ var registration = loader.Load(dependencyKey,
targetType);
+ if (registration != null)
+ {
+ registration.Register(Kernel);
+ return true;
+ }
+ }
+ return false;
+ }
}
File [modified]: DefaultHandler.cs
Delta lines: +45 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/ILazyComponentLoader.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/ILazyComponentLoader.cs
2009-11-15 22:40:29 UTC (rev 6335)
@@ -0,0 +1,45 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.MicroKernel.Resolvers
+{
+ using System;
+
+ using Castle.MicroKernel.Registration;
+
+ /// <summary>
+ /// Provides lazy registration capabilities to the container.
+ /// </summary>
+ /// <remarks>
+ /// When a component is requested from a container, that has not been
registered
+ /// container loads up all the implementers of this interface and asks
them in turn
+ /// whethere they can provide that component, until it finds one that
will.
+ /// </remarks>
+ public interface ILazyComponentLoader
+ {
+ /// <summary>
+ /// Used by container to allow the loader gister component for
given <paramref name="key"/> and <paramref name="service"/> to the container at
the time when it is requested
+ /// </summary>
+ /// <param name="key">Key of the requested component or
null</param>
+ /// <param name="service">Type of requested service or
null</param>
+ /// <returns>Registration that registers component for given
key and/or service or null.</returns>
+ /// <remarks>
+ /// While both key and service can be null reference it is
guaranteed that at least one of them will not be null.
+ /// When implementer opts in to provide the requested component
(by returning not-null registration) it is required
+ /// to register component for requested key/service combination
(when one of the elements is null, it should be ignored as well).
+ /// When implementer does not want to register the requested
component it nust return null.
+ /// </remarks>
+ IRegistration Load(string key, Type service);
+ }
+}
Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/
======================================================================
File [added]: ILazyComponentLoader.cs
Delta lines: +1 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Castle.MicroKernel.Tests-vs2008.csproj
2009-11-15 22:33:44 UTC (rev 6334)
+++
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Castle.MicroKernel.Tests-vs2008.csproj
2009-11-15 22:40:29 UTC (rev 6335)
@@ -229,6 +229,7 @@
<Compile Include="GraphTestCase.cs">
<SubType>Code</SubType>
</Compile>
+ <Compile Include="LazyLoadingTestCase.cs" />
<Compile Include="Lifecycle\Components\HttpFakeServer.cs">
<SubType>Code</SubType>
--
You received this message because you are subscribed to the Google Groups
"Castle Project Commits" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/castle-project-commits?hl=.