DefaultDependencyResolver
Default implementation for IDependencyResolver. This implementation is quite simple, but still should be useful for 99% of situations.
using Castle.Core;
using Castle.Core.Internal;
using Castle.MicroKernel.Context;
using Castle.MicroKernel.Handlers;
using Castle.MicroKernel.SubSystems.Conversion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Castle.MicroKernel.Resolvers
{
[Serializable]
public class DefaultDependencyResolver : IDependencyResolver, ISubDependencyResolver
{
private readonly IList<ISubDependencyResolver> subResolvers = new List<ISubDependencyResolver>();
private ITypeConverter converter;
private DependencyDelegate dependencyResolvingDelegate;
private IKernelInternal kernel;
public void AddSubResolver(ISubDependencyResolver subResolver)
{
if (subResolver == null)
throw new ArgumentNullException("subResolver");
subResolvers.Add(subResolver);
}
public void Initialize(IKernelInternal kernel, DependencyDelegate dependencyDelegate)
{
this.kernel = kernel;
converter = kernel.GetConversionManager();
dependencyResolvingDelegate = dependencyDelegate;
}
public void RemoveSubResolver(ISubDependencyResolver subResolver)
{
subResolvers.Remove(subResolver);
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
if (CanResolveFromContext(context, contextHandlerResolver, model, dependency))
return true;
if (CanResolveFromHandler(context, contextHandlerResolver, model, dependency))
return true;
if (CanResolveFromContextHandlerResolver(context, contextHandlerResolver, model, dependency))
return true;
if (CanResolveFromSubResolvers(context, contextHandlerResolver, model, dependency))
return true;
return CanResolveFromKernel(context, model, dependency);
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
if (!TryResolveCore(context, contextHandlerResolver, model, dependency, out object value)) {
if (dependency.HasDefaultValue)
value = dependency.DefaultValue;
else if (!dependency.IsOptional) {
throw new DependencyResolverException(string.Format("Could not resolve non-optional dependency for '{0}' ({1}). Parameter '{2}' type '{3}'", model.Name, (model.Implementation != (Type)null) ? model.Implementation.FullName : "-unknown-", dependency.DependencyKey, dependency.TargetType.FullName));
}
}
dependencyResolvingDelegate(model, dependency, value);
return value;
}
protected virtual bool CanResolveFromKernel(CreationContext context, ComponentModel model, DependencyModel dependency)
{
if (dependency.ReferencedComponentName != null)
return HasComponentInValidState(dependency.ReferencedComponentName, dependency, context);
if (dependency.Parameter != null)
return true;
if (typeof(IKernel).IsAssignableFrom(dependency.TargetItemType))
return true;
if (dependency.TargetItemType.IsPrimitiveType())
return false;
return HasAnyComponentInValidState(dependency.TargetItemType, dependency, context);
}
protected virtual CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
{
if (parameterType.GetTypeInfo().ContainsGenericParameters)
return current;
return new CreationContext(parameterType, current, false);
}
protected virtual object ResolveFromKernel(CreationContext context, ComponentModel model, DependencyModel dependency)
{
if (dependency.ReferencedComponentName != null)
return ResolveFromKernelByName(context, model, dependency);
if (dependency.Parameter != null)
return ResolveFromParameter(context, model, dependency);
if (typeof(IKernel).IsAssignableFrom(dependency.TargetItemType))
return kernel;
if (dependency.TargetItemType.IsPrimitiveType())
return null;
return ResolveFromKernelByType(context, model, dependency);
}
private bool CanResolveFromContext(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return context?.CanResolve(context, contextHandlerResolver, model, dependency) ?? false;
}
private bool CanResolveFromContextHandlerResolver(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return contextHandlerResolver?.CanResolve(context, contextHandlerResolver, model, dependency) ?? false;
}
private bool CanResolveFromHandler(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
IHandler handler = kernel.GetHandler(model.Name);
if (handler != null && handler != contextHandlerResolver)
return handler.CanResolve(context, contextHandlerResolver, model, dependency);
return false;
}
private bool CanResolveFromSubResolvers(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
if (subResolvers.Count > 0)
return subResolvers.Any((ISubDependencyResolver s) => s.CanResolve(context, contextHandlerResolver, model, dependency));
return false;
}
private bool HasAnyComponentInValidState(Type service, DependencyModel dependency, CreationContext context)
{
IHandler handler2 = (context == null || !context.IsResolving) ? kernel.GetHandler(service) : kernel.LoadHandlerByType(dependency.DependencyKey, service, context.AdditionalArguments);
if (handler2 == null)
return false;
if ((context == null || !handler2.IsBeingResolvedInContext(context)) && IsHandlerInValidState(handler2))
return true;
List<IHandler> list = (from handler in kernel.GetHandlers(service)
where !handler.IsBeingResolvedInContext(context)
select handler).ToList();
RebuildOpenGenericHandlersWithClosedGenericSubHandlers(service, context, list);
return list.Any((IHandler handler) => IsHandlerInValidState(handler));
}
private void RebuildOpenGenericHandlersWithClosedGenericSubHandlers(Type service, CreationContext context, List<IHandler> nonResolvingHandlers)
{
if (context.RequestedType != (Type)null && service.GetTypeInfo().IsGenericType) {
List<DefaultGenericHandler> genericHandlers = nonResolvingHandlers.OfType<DefaultGenericHandler>().ToList();
nonResolvingHandlers.RemoveAll((IHandler x) => genericHandlers.Contains(x));
CreationContext openGenericContext = RebuildContextForParameter(context, service);
List<IHandler> collection = (from x in genericHandlers
select x.ConvertToClosedGenericHandler(service, openGenericContext)).ToList();
nonResolvingHandlers.AddRange(collection);
}
}
private bool HasComponentInValidState(string key, DependencyModel dependency, CreationContext context)
{
IHandler handler = (context == null || !context.IsResolving) ? kernel.GetHandler(key) : kernel.LoadHandlerByName(key, dependency.TargetItemType, context.AdditionalArguments);
if (IsHandlerInValidState(handler))
return !handler.IsBeingResolvedInContext(context);
return false;
}
private bool TryResolveCore(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency, out object value)
{
if (CanResolveFromContext(context, contextHandlerResolver, model, dependency)) {
value = context.Resolve(context, contextHandlerResolver, model, dependency);
return true;
}
IHandler handler = kernel.GetHandler(model.Name);
if (handler != contextHandlerResolver && handler.CanResolve(context, contextHandlerResolver, model, dependency)) {
value = handler.Resolve(context, contextHandlerResolver, model, dependency);
return true;
}
if (CanResolveFromContextHandlerResolver(context, contextHandlerResolver, model, dependency)) {
value = contextHandlerResolver.Resolve(context, contextHandlerResolver, model, dependency);
return true;
}
if (subResolvers.Count > 0) {
for (int i = 0; i < subResolvers.Count; i++) {
ISubDependencyResolver subDependencyResolver = subResolvers[i];
if (subDependencyResolver.CanResolve(context, contextHandlerResolver, model, dependency)) {
value = subDependencyResolver.Resolve(context, contextHandlerResolver, model, dependency);
return true;
}
}
}
value = ResolveFromKernel(context, model, dependency);
return value != null;
}
private object ResolveFromKernelByName(CreationContext context, ComponentModel model, DependencyModel dependency)
{
IHandler handler = kernel.LoadHandlerByName(dependency.ReferencedComponentName, dependency.TargetItemType, context.AdditionalArguments);
if (handler == null)
throw new DependencyResolverException(string.Format("Missing dependency.{2}Component {0} has a dependency on component {1}, which was not registered.{2}Make sure the dependency is correctly registered in the container as a service.", model.Name, dependency.ReferencedComponentName, Environment.NewLine));
CreationContext context2 = RebuildContextForParameter(context, dependency.TargetItemType);
return handler.Resolve(context2);
}
private object ResolveFromKernelByType(CreationContext context, ComponentModel model, DependencyModel dependency)
{
if (!TryGetHandlerFromKernel(dependency, context, out IHandler handler)) {
if (dependency.HasDefaultValue)
return dependency.DefaultValue;
throw new DependencyResolverException(string.Format("Missing dependency.{2}Component {0} has a dependency on {1}, which could not be resolved.{2}Make sure the dependency is correctly registered in the container as a service, or provided as inline argument.", model.Name, dependency.TargetItemType, Environment.NewLine));
}
if (handler == null) {
if (dependency.HasDefaultValue)
return dependency.DefaultValue;
throw new DependencyResolverException(string.Format("Cycle detected in configuration.{2}Component {0} has a dependency on {1}, but it doesn't provide an override.{2}You must provide an override if a component has a dependency on a service that it - itself - provides.", model.Name, dependency.TargetItemType, Environment.NewLine));
}
context = RebuildContextForParameter(context, dependency.TargetItemType);
return handler.Resolve(context);
}
private object ResolveFromParameter(CreationContext context, ComponentModel model, DependencyModel dependency)
{
converter.Context.Push(model, context);
try {
if (dependency.Parameter.Value == null && (object)dependency.Parameter.ConfigValue != null)
return converter.PerformConversion(dependency.Parameter.ConfigValue, dependency.TargetItemType);
return converter.PerformConversion(dependency.Parameter.Value, dependency.TargetItemType);
} catch (ConverterException innerException) {
throw new DependencyResolverException($"""{dependency.Parameter.Name}""{dependency.TargetItemType.Name}""", innerException);
} finally {
converter.Context.Pop();
}
}
private bool TryGetHandlerFromKernel(DependencyModel dependency, CreationContext context, out IHandler handler)
{
try {
handler = kernel.LoadHandlerByType(dependency.DependencyKey, dependency.TargetItemType, context.AdditionalArguments);
} catch (HandlerException) {
handler = null;
}
if (handler == null)
return false;
if (!handler.IsBeingResolvedInContext(context))
return true;
IHandler[] handlers;
try {
handlers = kernel.GetHandlers(dependency.TargetItemType);
} catch (HandlerException) {
return false;
}
IHandler[] array = handlers;
foreach (IHandler handler2 in array) {
if (!handler2.IsBeingResolvedInContext(context)) {
handler = handler2;
break;
}
}
return true;
}
private static bool IsHandlerInValidState(IHandler handler)
{
if (handler == null)
return false;
return handler.CurrentState == HandlerState.Valid;
}
}
}