/// <summary> /// Tries to create the service with the specified constructor using the specified parameters. /// <para /> /// This method will not throw an exception when the invocation fails. /// </summary> /// <param name="typeToConstruct">Type of the service.</param> /// <param name="constructor">The constructor info.</param> /// <param name="parameters">The parameters to pass into the constructor.</param> /// <param name="checkConstructor">if set to <c>true</c>, check whether the constructor can be used before using it.</param> /// <param name="hasMoreConstructorsLeft">if set to <c>true</c>, more constructors are left so don't throw exceptions.</param> /// <returns>The instantiated service or <c>null</c> if the instantiation fails.</returns> /// <remarks>Note that this method does not require an implementation of /// <see cref="TypeRequestPath" /> because this already has the parameter values /// and thus cannot lead to invalid circular dependencies.</remarks> private object TryCreateToConstruct(Type typeToConstruct, ConstructorInfo constructor, object[] parameters, bool checkConstructor, bool hasMoreConstructorsLeft) { // Check if this constructor is even possible if (checkConstructor) { if (!CanConstructorBeUsed(constructor, true, parameters)) { return null; } } try { var finalParameters = new List<object>(parameters); var ctorParameters = constructor.GetParameters(); for (int i = parameters.Length; i < ctorParameters.Length; i++) { var ctorParameterValue = _serviceLocator.ResolveType(ctorParameters[i].ParameterType); finalParameters.Add(ctorParameterValue); } var finalParametersArray = finalParameters.ToArray(); Log.Debug("Calling constructor.Invoke with the right parameters"); var instance = constructor.Invoke(finalParametersArray); InitializeAfterConstruction(instance); return instance; } #if NET catch (MissingMethodException) { // Ignore, we accept this } #endif catch (TargetParameterCountException) { // Ignore, we accept this } catch (CircularDependencyException) { // Only handle CircularDependencyExceptions we throw ourselves because we support generic types such as // Dictionary<TKey, TValue> which has a constructor with IDictionary<TKey, TValue> if (!hasMoreConstructorsLeft) //if (string.Equals(TypeRequestPathName, ex.TypePath.Name, StringComparison.Ordinal)) { throw; } } catch (Exception ex) { // Real exceptions bubble up, otherwise return null Log.Error(ex, "Failed to instantiate type '{0}', but this was an unexpected error", typeToConstruct.FullName); throw; } Log.Debug("Failed to create instance using dependency injection for type '{0}' using constructor '{1}'", typeToConstruct.FullName, constructor.GetSignature()); return null; }
/// <summary> /// Tries to create the service with the specified constructor using the specified parameters. /// <para /> /// This method will not throw an exception when the invocation fails. /// </summary> /// <remarks> /// Note that this method does not require an implementation of <see cref="TypeRequestPath"/> because this already has the parameter values /// and thus cannot lead to invalid circular dependencies. /// </remarks> /// <param name="typeToConstruct">Type of the service.</param> /// <param name="constructorInfo">The constructor info.</param> /// <param name="parameters">The parameters to pass into the constructor.</param> /// <returns>The instantiated service or <c>null</c> if the instantiation fails.</returns> private object TryCreateWithConstructorInjectionWithParameters(Type typeToConstruct, ConstructorInfo constructorInfo, object[] parameters) { if (constructorInfo.IsStatic) { Log.Debug("Cannot use static constructor to initialize type '{0}'", typeToConstruct.FullName); return null; } try { var instance = constructorInfo.Invoke(parameters); InitializeAfterConstruction(instance); return instance; } #if NET catch (MissingMethodException) { // Ignore, we accept this } #endif catch (TargetParameterCountException) { // Ignore, we accept this } catch (Exception ex) { // Real exceptions bubble up, otherwise return null Log.Error(ex, "Failed to instantiate type '{0}', but this was an unexpected error", typeToConstruct.FullName); throw ex.InnerException ?? ex; } Log.Debug("Failed to create instance using dependency injection for type '{0}' using constructor '{1}'", typeToConstruct.FullName, constructorInfo.GetSignature()); return null; }
/// <summary> /// Determines whether the specified constructor can be used for dependency injection. /// </summary> /// <param name="constructor">The constructor.</param> /// <param name="autoCompleteDependencies">if set to <c>true</c>, additional dependencies can be completed from the <see cref="IServiceLocator"/>.</param> /// <param name="parameters">The parameters.</param> /// <returns><c>true</c> if this instance [can constructor be used] the specified constructor; otherwise, <c>false</c>.</returns> private bool CanConstructorBeUsed(ConstructorInfo constructor, bool autoCompleteDependencies, params object[] parameters) { Log.Debug("Checking if constructor '{0}' can be used", constructor.GetSignature()); if (constructor.IsStatic) { Log.Debug("Constructor is not valid because it is static"); return false; } bool validConstructor = true; var ctorParameters = constructor.GetParameters(); for (int i = 0; i < parameters.Length; i++) { var ctorParameter = ctorParameters[i]; var ctorParameterType = ctorParameter.ParameterType; if (!IsValidParameterValue(ctorParameterType, parameters[i])) { Log.Debug("Constructor is not valid because value '{0}' cannot be used for parameter '{0}'", ObjectToStringHelper.ToString(parameters[i]), ctorParameter.Name); validConstructor = false; break; } } if (validConstructor && autoCompleteDependencies) { if (ctorParameters.Length > parameters.Length) { // check if all the additional parameters are registered in the service locator for (int j = parameters.Length; j < ctorParameters.Length; j++) { var parameterToResolve = ctorParameters[j]; var parameterTypeToResolve = parameterToResolve.ParameterType; if (!_serviceLocator.IsTypeRegistered(parameterTypeToResolve)) { Log.Debug("Constructor is not valid because parameter '{0}' cannot be resolved from the dependency resolver", parameterToResolve.Name); validConstructor = false; break; } } } } Log.Debug("The constructor is valid and can be used"); return validConstructor; }
/// <summary> /// Tries to create the service with the specified constructor using the specified parameters. /// <para /> /// This method will not throw an exception when the invocation fails. /// </summary> /// <remarks> /// Note that this method does not require an implementation of <see cref="TypeRequestPath"/> because this already has the parameter values /// and thus cannot lead to invalid circular dependencies. /// </remarks> /// <param name="typeToConstruct">Type of the service.</param> /// <param name="constructor">The constructor info.</param> /// <param name="parameters">The parameters to pass into the constructor.</param> /// <returns>The instantiated service or <c>null</c> if the instantiation fails.</returns> private object TryCreateWithConstructorInjectionWithParameters(Type typeToConstruct, ConstructorInfo constructor, object[] parameters) { if (constructor.IsStatic) { Log.Debug("Cannot use static constructor to initialize type '{0}'", typeToConstruct.FullName); return null; } try { var finalParameters = new List<object>(parameters); var ctorParameters = constructor.GetParameters(); for (int i = parameters.Length; i < ctorParameters.Length; i++) { var ctorParameterValue = _dependencyResolver.Resolve(ctorParameters[i].ParameterType); if (ctorParameterValue == null) { return null; } finalParameters.Add(ctorParameterValue); } var finalParametersArray = finalParameters.ToArray(); Log.Debug("Calling constructor.Invoke with the right parameters"); var instance = constructor.Invoke(finalParametersArray); //Log.Debug("Called constructor.Invoke with the right parameters"); InitializeAfterConstruction(instance); return instance; } #if NET catch (MissingMethodException) { // Ignore, we accept this } #endif catch (TargetParameterCountException) { // Ignore, we accept this } catch (CircularDependencyException ex) { // Only handle CircularDependencyExceptions we throw ourselves if (string.Equals(TypeRequestPathName, ex.TypePath.Name, StringComparison.Ordinal)) { throw; } } catch (Exception ex) { // Real exceptions bubble up, otherwise return null Log.Error(ex, "Failed to instantiate type '{0}', but this was an unexpected error", typeToConstruct.FullName); throw ex.InnerException ?? ex; } Log.Debug("Failed to create instance using dependency injection for type '{0}' using constructor '{1}'", typeToConstruct.FullName, constructor.GetSignature()); return null; }