DefaultComponentActivator
Standard implementation of IComponentActivator. Handles the selection of the best constructor, fills the writable properties the component exposes, run the commission and
decommission lifecycles, etc.
using Castle.Core;
using Castle.Core.Internal;
using Castle.DynamicProxy;
using Castle.MicroKernel.Context;
using System;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
namespace Castle.MicroKernel.ComponentActivator
{
[Serializable]
public class DefaultComponentActivator : AbstractComponentActivator
{
private readonly bool useFastCreateInstance;
public DefaultComponentActivator(ComponentModel model, IKernelInternal kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
: base(model, kernel, onCreation, onDestruction)
{
useFastCreateInstance = (!model.Implementation.IsContextful && ((IPermission)new SecurityPermission(SecurityPermissionFlag.SerializationFormatter)).IsGranted());
}
protected override object InternalCreate(CreationContext context)
{
object obj = Instantiate(context);
context.SetContextualProperty(this, obj);
SetUpProperties(obj, context);
ApplyCommissionConcerns(obj);
return obj;
}
protected override void InternalDestroy(object instance)
{
ApplyDecommissionConcerns(instance);
}
protected virtual object Instantiate(CreationContext context)
{
ConstructorCandidate constructor = SelectEligibleConstructor(context);
object[] arguments = CreateConstructorArguments(constructor, context);
return CreateInstance(context, constructor, arguments);
}
protected virtual object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments)
{
object obj = null;
Type implementation = base.Model.Implementation;
bool num = base.Kernel.ProxyFactory.ShouldCreateProxy(base.Model);
if (!num && base.Model.Implementation.GetTypeInfo().IsAbstract)
throw new ComponentRegistrationException(string.Format("Type {0} is abstract.{2} As such, it is not possible to instansiate it as implementation of service '{1}'. Did you forget to proxy it?", base.Model.Implementation.FullName, base.Model.Name, Environment.NewLine));
bool flag = true;
if (num)
flag = base.Kernel.ProxyFactory.RequiresTargetInstance(base.Kernel, base.Model);
if (flag)
obj = CreateInstanceCore(constructor, arguments, implementation);
if (num)
try {
return base.Kernel.ProxyFactory.Create(base.Kernel, obj, base.Model, context, arguments);
} catch (Exception innerException) {
if (arguments != null) {
foreach (object instance in arguments) {
base.Kernel.ReleaseComponent(instance);
}
}
throw new ComponentActivatorException("ComponentActivator: could not proxy " + base.Model.Implementation.FullName, innerException, base.Model);
}
return obj;
}
protected object CreateInstanceCore(ConstructorCandidate constructor, object[] arguments, Type implType)
{
try {
if (!useFastCreateInstance)
return implType.CreateInstance<object>(arguments);
return FastCreateInstance(implType, arguments, constructor);
} catch (Exception ex) {
if (arguments != null) {
foreach (object instance in arguments) {
base.Kernel.ReleaseComponent(instance);
}
}
if (ex is ComponentActivatorException)
throw;
throw new ComponentActivatorException("ComponentActivator: could not instantiate " + base.Model.Implementation.FullName, ex, base.Model);
}
}
[SecuritySafeCritical]
private object FastCreateInstance(Type implType, object[] arguments, ConstructorCandidate constructor)
{
if (constructor == null || constructor.Constructor == (ConstructorInfo)null)
throw new ComponentActivatorException(string.Format("Could not find a public constructor for type {0}.{1}Windsor by default cannot instantiate types that don't expose public constructors.{1}To expose the type as a service add public constructor, or use custom component activator.", implType, Environment.NewLine), base.Model);
object uninitializedObject = FormatterServices.GetUninitializedObject(implType);
constructor.Constructor.Invoke(uninitializedObject, arguments);
return uninitializedObject;
}
protected virtual ConstructorCandidate SelectEligibleConstructor(CreationContext context)
{
if (base.Model.Constructors.Count == 0)
return null;
if (base.Model.Constructors.Count == 1)
return base.Model.Constructors[0];
ConstructorCandidate constructorCandidate = null;
int winnerPoints = 0;
foreach (ConstructorCandidate constructor in base.Model.Constructors) {
if (CheckCtorCandidate(constructor, context, out int candidatePoints) && BestScoreSoFar(candidatePoints, winnerPoints, constructorCandidate)) {
if (BestPossibleScore(constructor, candidatePoints))
return constructor;
constructorCandidate = constructor;
winnerPoints = candidatePoints;
}
}
if (constructorCandidate == null)
throw new NoResolvableConstructorFoundException(base.Model.Implementation, base.Model);
return constructorCandidate;
}
private static bool BestScoreSoFar(int candidatePoints, int winnerPoints, ConstructorCandidate winnerCandidate)
{
if (winnerCandidate != null)
return winnerPoints < candidatePoints;
return true;
}
private static bool BestPossibleScore(ConstructorCandidate candidate, int candidatePoints)
{
return candidatePoints == candidate.Dependencies.Length * 100;
}
private bool CheckCtorCandidate(ConstructorCandidate candidate, CreationContext context, out int candidatePoints)
{
candidatePoints = 0;
ConstructorDependencyModel[] dependencies = candidate.Dependencies;
foreach (ConstructorDependencyModel constructorDependencyModel in dependencies) {
if (CanSatisfyDependency(context, constructorDependencyModel))
candidatePoints += 100;
else {
if (!constructorDependencyModel.HasDefaultValue) {
candidatePoints = 0;
return false;
}
candidatePoints++;
}
}
return true;
}
protected virtual bool CanSatisfyDependency(CreationContext context, DependencyModel dependency)
{
return base.Kernel.Resolver.CanResolve(context, context.Handler, base.Model, dependency);
}
protected virtual object[] CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context)
{
if (constructor == null)
return null;
int num = constructor.Dependencies.Length;
if (num != 0) {
object[] array = new object[num];
try {
for (int i = 0; i < num; i++) {
array[i] = base.Kernel.Resolver.Resolve(context, context.Handler, base.Model, constructor.Dependencies[i]);
}
return array;
} catch {
object[] array2 = array;
foreach (object instance in array2) {
base.Kernel.ReleaseComponent(instance);
}
throw;
}
}
return null;
}
protected virtual void SetUpProperties(object instance, CreationContext context)
{
instance = ProxyUtil.GetUnproxiedInstance(instance);
IDependencyResolver resolver = base.Kernel.Resolver;
foreach (PropertySet property in base.Model.Properties) {
object obj = ObtainPropertyValue(context, property, resolver);
if (obj != null) {
MethodInfo setMethod = property.Property.GetSetMethod();
try {
setMethod.Invoke(instance, new object[1] {
obj
});
} catch (Exception innerException) {
throw new ComponentActivatorException(string.Format("Error setting property {1}.{0} in component {2}. See inner exception for more information.{4}If you don't want Windsor to set this property you can do it by either decorating it with {3} or via registration API.{4}Alternatively consider making the setter non-public.", property.Property.Name, instance.GetType().Name, base.Model.Name, typeof(DoNotWireAttribute).Name, Environment.NewLine), innerException, base.Model);
}
}
}
}
private object ObtainPropertyValue(CreationContext context, PropertySet property, IDependencyResolver resolver)
{
if (!property.Dependency.IsOptional || resolver.CanResolve(context, context.Handler, base.Model, property.Dependency))
try {
return resolver.Resolve(context, context.Handler, base.Model, property.Dependency);
} catch (Exception exception) {
if (!property.Dependency.IsOptional)
throw;
base.Kernel.Logger.Warn($"""{property.Dependency}""{base.Model.Name}""", exception);
}
return null;
}
}
}