/// <summary> /// Resolves the type from a known container. /// </summary> /// <param name="serviceType">Type of the service.</param> /// <param name="tag">The tag to register the service with. The default value is <c>null</c>.</param> /// <returns>An instance of the type registered on the service.</returns> /// <exception cref="ArgumentNullException">The <paramref name="serviceType"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">The type is not found in any container.</exception> private object ResolveTypeFromKnownContainer(Type serviceType, object tag) { Argument.IsNotNull("serviceType", serviceType); lock (this) { var typeRequestInfo = new TypeRequestInfo(serviceType); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: "ServiceLocator"); _currentTypeRequestPath.IgnoreDuplicateRequestsDirectlyAfterEachother = false; } else { _currentTypeRequestPath.PushType(typeRequestInfo, false); if (!_currentTypeRequestPath.IsValid) { // Reset path for next types that are being resolved var typeRequestPath = _currentTypeRequestPath; _currentTypeRequestPath = null; typeRequestPath.ThrowsExceptionIfInvalid(); } } var serviceInfo = new ServiceInfo(serviceType, tag); var registeredTypeInfo = _registeredTypes[serviceInfo]; object instance = registeredTypeInfo.CreateServiceFunc(registeredTypeInfo); if (instance == null) { ThrowTypeNotRegisteredException(serviceType); } if (IsTypeRegisteredAsSingleton(serviceType, tag)) { RegisterInstance(serviceType, instance, tag, this); } CompleteTypeRequestPathIfRequired(typeRequestInfo); return(instance); } }
public void RemovesTypeRangeUntilSpecificType() { var path = new TypeRequestPath(new TypeRequestInfo(typeof(X))); path.PushType(new TypeRequestInfo(typeof(object)), false); path.PushType(new TypeRequestInfo(typeof(Y)), false); path.PushType(new TypeRequestInfo(typeof(object)), false); path.PushType(new TypeRequestInfo(typeof(Z)), false); path.MarkTypeAsNotCreated(new TypeRequestInfo(typeof(Y))); Assert.AreEqual(2, path.TypeCount); Assert.AreEqual(new TypeRequestInfo(typeof(X)), path.AllTypes[0]); Assert.AreEqual(new TypeRequestInfo(typeof(object)), path.AllTypes[1]); }
public void DoesNotThrowCircularDependencyExceptionForDuplicateTypeIfNotSpecified() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); path.PushType(new TypeRequestInfo(typeof(X)), false); Assert.IsFalse(path.IsValid); }
public void DoesNotIgnoreValueTypesIfIgnoreValueTypesIsFalse() { var firstType = new TypeRequestInfo(typeof(X)); var path = new TypeRequestPath(firstType, false); path.PushType(new TypeRequestInfo(typeof(DateTime)), false); Assert.AreEqual(typeof(DateTime), path.LastType.Type); path.PushType(new TypeRequestInfo(typeof(double)), false); Assert.AreEqual(typeof(double), path.LastType.Type); path.PushType(new TypeRequestInfo(typeof(int)), false); Assert.AreEqual(typeof(int), path.LastType.Type); }
public void DoesThrowCircularDependencyExceptionForDuplicateTypeIfSpecified() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); ExceptionTester.CallMethodAndExpectException<CircularDependencyException>(() => path.PushType(new TypeRequestInfo(typeof(X)), true)); }
public void ThrowsArgumentNullExceptionForNullTypeRequestInfo() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => path.PushType(null, false)); }
/// <summary> /// Creates an instance of the specified type using the specified parameters as injection values. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <param name="parameters">The parameters to inject.</param> /// <param name="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <param name="preventCircularDependencies">if set to <c>true</c>, prevent circular dependencies using the <see cref="TypeRequestPath"/>.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct" /> is <c>null</c>.</exception> private object CreateInstanceWithSpecifiedParameters(Type typeToConstruct, object[] parameters, bool autoCompleteDependencies, bool preventCircularDependencies = true) { Argument.IsNotNull("typeToConstruct", typeToConstruct); if (parameters == null) { parameters = new object[] { }; } lock (_serviceLocator) { TypeRequestInfo typeRequestInfo = null; try { if (preventCircularDependencies) { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } } var constructorCache = GetConstructorCache(autoCompleteDependencies); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, parameters); if (constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, cachedConstructor, parameters, false, false); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}' using specific parameters. No constructor found in the cache, so searching for the right one", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(parameters.Count(), !autoCompleteDependencies); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, constructor, parameters, true, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } // We found a constructor that works, cache it constructorCache[constructorCacheKey] = constructor; // Only update the rule when using a constructor for the first time, not when using it from the cache ApiCop.UpdateRule <TooManyDependenciesApiCopRule>("TypeFactory.LimitDependencyInjection", x => x.SetNumberOfDependenciesInjected(typeToConstruct, constructor.GetParameters().Count())); return(instanceCreatedWithInjection); } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); } catch (CircularDependencyException) { throw; } catch (Exception ex) { if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } return(null); } }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { #if !DISABLE_TYPEPATH typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } #endif if (_constructorCache.ContainsKey(typeToConstruct)) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, _constructorCache[typeToConstruct]); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(typeToConstruct); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var constructors = (from constructor in typeToConstruct.GetConstructorsEx() orderby constructor.GetParameters().Count() descending select constructor).ToList(); foreach (var constructor in constructors) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif // We found a constructor that works, cache it _constructorCache[typeToConstruct] = constructor; return(instanceCreatedWithInjection); } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return(createdInstanceUsingActivator); } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeTypeIfRequired(typeRequestInfo); return(null); } }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, new object[] { }); if (_constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = _constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, cachedConstructor, false); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); // We found a constructor that works, cache it _constructorCache[constructorCacheKey] = constructor; return(instanceCreatedWithInjection); } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return(createdInstanceUsingActivator); } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeIfRequired(typeRequestInfo); return(null); } }