/// <summary> /// Sets the number of dependencies injected for the specified type. /// </summary> /// <param name="type">The type.</param> /// <param name="numberOfDependencies">The number of dependencies.</param> public void SetNumberOfDependenciesInjected(Type type, int numberOfDependencies) { if (type == null) { return; } lock (_lockObject) { var typeName = type.GetSafeFullName(true); AddTag(typeName); bool update = false; if (!_dependenciesPerType.ContainsKey(typeName)) { update = true; } else { if (_dependenciesPerType[typeName] < numberOfDependencies) { update = true; } } if (update) { _dependenciesPerType[typeName] = numberOfDependencies; } } }
/// <summary> /// Creates a command using a naming convention with the specified gesture. /// </summary> /// <param name="commandManager">The command manager.</param> /// <param name="containerType">Type of the container.</param> /// <param name="commandNameFieldName">Name of the command name field.</param> /// <exception cref="ArgumentNullException">The <paramref name="commandManager"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="containerType"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="commandNameFieldName"/> is <c>null</c>.</exception> public static void CreateCommandWithGesture(this ICommandManager commandManager, Type containerType, string commandNameFieldName) { Argument.IsNotNull("commandManager", commandManager); Argument.IsNotNull("containerType", containerType); Argument.IsNotNullOrWhitespace("commandNameFieldName", commandNameFieldName); Log.Debug("Creating command '{0}'", commandNameFieldName); // Note: we must store bindingflags inside variable otherwise invalid IL will be generated var bindingFlags = BindingFlags.Public | BindingFlags.Static; var commandNameField = containerType.GetFieldEx(commandNameFieldName, bindingFlags); if (commandNameField == null) { throw Log.ErrorAndCreateException<InvalidOperationException>("Command '{0}' is not available on container type '{1}'", commandNameFieldName, containerType.GetSafeFullName()); } var commandName = (string)commandNameField.GetValue(null); if (commandManager.IsCommandCreated(commandName)) { Log.Debug("Command '{0}' is already created, skipping...", commandName); return; } InputGesture commandInputGesture = null; var inputGestureField = containerType.GetFieldEx(string.Format("{0}InputGesture", commandNameFieldName), bindingFlags); if (inputGestureField != null) { commandInputGesture = inputGestureField.GetValue(null) as InputGesture; } commandManager.CreateCommand(commandName, commandInputGesture); var commandContainerName = string.Format("{0}CommandContainer", commandName.Replace(".", string.Empty)); var commandContainerType = (from type in TypeCache.GetTypes() where string.Equals(type.Name, commandContainerName, StringComparison.OrdinalIgnoreCase) select type).FirstOrDefault(); if (commandContainerType != null) { Log.Debug("Found command container '{0}', registering it in the ServiceLocator now", commandContainerType.GetSafeFullName()); var serviceLocator = commandManager.GetServiceLocator(); if (!serviceLocator.IsTypeRegistered(commandContainerType)) { var typeFactory = serviceLocator.ResolveType<ITypeFactory>(); var commandContainer = typeFactory.CreateInstance(commandContainerType); if (commandContainer != null) { serviceLocator.RegisterInstance(commandContainer); } else { Log.Warning("Cannot create command container '{0}', skipping registration", commandContainerType.GetSafeFullName()); } } } }
/// <summary> /// Initializes a new instance of the <see cref="MemberValue" /> class. /// </summary> /// <param name="memberGroup">Group of the member.</param> /// <param name="modelType">Type of the model.</param> /// <param name="memberType">Type of the member.</param> /// <param name="name">The name.</param> /// <param name="nameForSerialization">The name for serialization.</param> /// <param name="value">The value.</param> public MemberValue(SerializationMemberGroup memberGroup, Type modelType, Type memberType, string name, string nameForSerialization, object value) { MemberGroup = memberGroup; ModelType = modelType; ModelTypeName = modelType.GetSafeFullName(); MemberType = memberType; MemberTypeName = memberType.GetSafeFullName(); Name = name; NameForSerialization = nameForSerialization; Value = value; }
/// <summary> /// Gets the Data Contract serializer for a specific type. This method caches serializers so the /// performance can be improved when a serializer is used more than once. /// </summary> /// <param name="serializingType">The type that is currently (de)serializing.</param> /// <param name="typeToSerialize">The type to (de)serialize.</param> /// <param name="xmlName">Name of the property as known in XML.</param> /// <param name="rootNamespace">The root namespace.</param> /// <param name="serializingObject">The object to create the serializer for. When the object is not <c>null</c>, the types that are /// a child object of this object are added to the known types of the serializer.</param> /// <param name="additionalKnownTypes">A list of additional types to add to the known types.</param> /// <returns><see cref="DataContractSerializer" /> for the given type.</returns> /// <exception cref="ArgumentNullException">The <paramref name="serializingType" /> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="typeToSerialize" /> is <c>null</c>.</exception> /// <exception cref="ArgumentException">The <paramref name="xmlName" /> is <c>null</c> or whitespace.</exception> public virtual DataContractSerializer GetDataContractSerializer(Type serializingType, Type typeToSerialize, string xmlName, string rootNamespace = null, object serializingObject = null, List<Type> additionalKnownTypes = null) { Argument.IsNotNull("serializingType", serializingType); Argument.IsNotNull("typeToSerialize", typeToSerialize); Argument.IsNotNullOrWhitespace("xmlName", xmlName); string key = string.Format("{0}|{1}", typeToSerialize.GetSafeFullName(), xmlName); return _dataContractSerializersCache.GetFromCacheOrFetch(key, () => { Log.Debug("Getting known types for xml serialization of '{0}'", typeToSerialize.GetSafeFullName()); var serializerTypeInfo = new XmlSerializerTypeInfo(serializingType, typeToSerialize, additionalKnownTypes); if (serializingObject != null) { GetKnownTypesForInstance(serializingObject, serializerTypeInfo); } else { GetKnownTypes(typeToSerialize, serializerTypeInfo); } var knownTypesViaAttributes = GetKnownTypesViaAttributes(serializingType); foreach (var knownTypeViaAttribute in knownTypesViaAttributes) { GetKnownTypes(knownTypeViaAttribute, serializerTypeInfo); } if (additionalKnownTypes != null) { foreach (var additionalKnownType in additionalKnownTypes) { GetKnownTypes(additionalKnownType, serializerTypeInfo); } } var xmlSerializer = new DataContractSerializer(typeToSerialize, xmlName, rootNamespace ?? string.Empty, serializerTypeInfo.KnownTypes); return xmlSerializer; }); }
/// <summary> /// Resolves the specified type with the specified tag. /// </summary> /// <param name="type">The type.</param> /// <param name="tag">The tag.</param> /// <returns>The resolved object or <c>null</c> if the type could not be resolved.</returns> public object Resolve(Type type, object tag = null) { Argument.IsNotNull("type", type); if (!_serviceLocator.IsTypeRegistered(type, tag)) { Log.Debug("Failed to resolve type '{0}', returning null", type.GetSafeFullName()); return null; } return _serviceLocator.ResolveType(type, tag); }
private bool IsSpecificTypeSpecialCollection(Type type) { if (type.IsGenericTypeEx()) { var fullName = type.GetSafeFullName(); if (fullName.StartsWith("System.Collections.ObjectModel.ObservableCollection") || fullName.StartsWith("System.Collections.Generic.")) { // Note: this is not a bug, we need to add type to the collection return true; } } return false; }
/// <summary> /// Determines whether the type should be handled. /// </summary> /// <param name="type">The type.</param> /// <param name="serializerTypeInfo">The serializer type info.</param> /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns> protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo) { if (type == null) { return true; } // Never include generic type definitions, otherwise we will get this: // Error while getting known types for Type 'Catel.Test.Data.PropertyDataManagerFacts+SupportsGenericClasses+GenericClass`1[T]'. The type must not be an open or partial generic class. if (type.IsGenericTypeDefinitionEx()) { return true; } // Note, although resharper says this isn't possible, it might be var fullName = type.GetSafeFullName(); if (string.IsNullOrWhiteSpace(fullName)) { serializerTypeInfo.AddTypeAsHandled(type); return true; } // Ignore non-generic .NET if (!type.IsGenericTypeEx() && fullName.StartsWith("System.")) { // Log.Debug("Non-generic .NET system type, can be ignored"); serializerTypeInfo.AddTypeAsHandled(type); return true; } if (type.IsCOMObjectEx()) { serializerTypeInfo.AddTypeAsHandled(type); return true; } return serializerTypeInfo.ContainsKnownType(type) || serializerTypeInfo.IsTypeAlreadyHandled(type) || serializerTypeInfo.IsCollectionAlreadyHandled(type); }
/// <summary> /// Gets the known types inside the specific type. /// </summary> /// <param name="type">The type.</param> /// <param name="serializerTypeInfo">The serializer type info.</param> /// <param name="resolveAbstractClassesAndInterfaces">if set to <c>true</c> [resolve abstract classes and interfaces].</param> /// <returns>Array of <see cref="Type" /> that are found in the object type.</returns> protected virtual void GetKnownTypes(Type type, XmlSerializerTypeInfo serializerTypeInfo, bool resolveAbstractClassesAndInterfaces = true) { if (ShouldTypeBeIgnored(type, serializerTypeInfo)) { return; } #if ENABLE_DETAILED_LOGGING Log.Debug("Getting known types for '{0}'", type.GetSafeFullName()); #endif GetKnownTypesForItems(type, serializerTypeInfo); // If this is an interface or abstract, we need to retieve all items that might possible implement or derive var isInterface = type.IsInterfaceEx(); var isAbstract = type.IsAbstractEx(); if (isInterface || isAbstract) { if (!serializerTypeInfo.IsTypeAlreadyHandled(type) && resolveAbstractClassesAndInterfaces) { // Interfaces / abstract classes are not a type, and in fact a LOT of types can be added (in fact every object implementing // the interface). For serialization, this is not a problem (we know the exact type), but for deserialization this IS an // issue because we should expect EVERY type that implements the type in the whole AppDomain. // This is huge performance hit, but it's the cost for dynamic easy on-the-fly serialization in WPF and Silverlight. Luckily // we already implemented caching. // Don't check this type again in children checks serializerTypeInfo.AddTypeAsHandled(type); #if ENABLE_DETAILED_LOGGING Log.Debug("Type is an interface / abstract class, checking all types implementing / deriving"); #endif if (isInterface) { var typesImplementingInterface = TypeCache.GetTypesImplementingInterface(type); foreach (var typeImplementingInterface in typesImplementingInterface) { if (typeImplementingInterface != type) { GetKnownTypes(typeImplementingInterface, serializerTypeInfo); } } } if (isAbstract) { var typesDerivingFromClass = TypeCache.GetTypes(type.IsAssignableFromEx); foreach (var typeDerivingFromClass in typesDerivingFromClass) { if (typeDerivingFromClass != type) { GetKnownTypes(typeDerivingFromClass, serializerTypeInfo); } } } #if ENABLE_DETAILED_LOGGING Log.Debug("Finished checking all types implementing / deriving"); #endif } // The interface itself is ignored return; } if (serializerTypeInfo.IsSpecialCollectionType(type) && !type.IsInterfaceEx()) { #if ENABLE_DETAILED_LOGGING Log.Debug("Type is a special collection type, adding it to the array of known types"); #endif AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo); } // Fix generics if (type.GetSafeFullName().StartsWith("System.")) { var genericArguments = type.GetGenericArgumentsEx(); foreach (var genericArgument in genericArguments) { #if ENABLE_DETAILED_LOGGING Log.Debug("Retrieving known types for generic argument '{0}' of '{1}'", genericArgument.GetSafeFullName(), type.GetSafeFullName()); #endif GetKnownTypes(genericArgument, serializerTypeInfo); } return; } if (!AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo)) { serializerTypeInfo.AddTypeAsHandled(type); } AddTypeMembers(type, serializerTypeInfo); // If this isn't the base type, check that as well var baseType = type.GetBaseTypeEx(); if (baseType != null) { #if ENABLE_DETAILED_LOGGING Log.Debug("Checking base type of '{0}' for known types", type.GetSafeFullName()); #endif if (baseType.FullName != null) { GetKnownTypes(baseType, serializerTypeInfo); } else { serializerTypeInfo.AddTypeAsHandled(baseType); } } // Last but not least, check if the type is decorated with KnownTypeAttributes var knowTypesByAttributes = GetKnownTypesViaAttributes(type); if (knowTypesByAttributes.Length > 0) { #if ENABLE_DETAILED_LOGGING Log.Debug("Found {0} additional known types for type '{1}'", knowTypesByAttributes.Length, type.GetSafeFullName()); #endif foreach (var knownTypeByAttribute in knowTypesByAttributes) { var attributeType = knownTypeByAttribute; var attributeTypeFullName = attributeType.GetSafeFullName(); if (attributeTypeFullName != null) { GetKnownTypes(knownTypeByAttribute, serializerTypeInfo); } else { serializerTypeInfo.AddTypeAsHandled(attributeType); } } } }
/// <summary> /// Determines whether the type should be handled. /// </summary> /// <param name="type">The type.</param> /// <param name="serializerTypeInfo">The serializer type info.</param> /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns> protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo) { if (type == null) { return true; } // Note, although resharper says this isn't possible, it might be if (type.FullName == null) { serializerTypeInfo.AddTypeAsHandled(type); return true; } // Ignore non-generic .NET if (!type.IsGenericTypeEx() && type.GetSafeFullName().StartsWith("System.")) { // Log.Debug("Non-generic .NET system type, can be ignored"); serializerTypeInfo.AddTypeAsHandled(type); return true; } return serializerTypeInfo.ContainsKnownType(type) || serializerTypeInfo.IsTypeAlreadyHandled(type); }
/// <summary> /// Gets the known types inside the specific type. /// </summary> /// <param name="type">The type.</param> /// <param name="serializerTypeInfo">The serializer type info.</param> /// <returns>Array of <see cref="Type"/> that are found in the object type.</returns> protected virtual void GetKnownTypes(Type type, XmlSerializerTypeInfo serializerTypeInfo) { if (ShouldTypeBeIgnored(type, serializerTypeInfo)) { return; } Log.Debug("Getting known types for '{0}'", type.GetSafeFullName()); // If this is an interface, HOUSTON, WE HAVE A PROBLEM if (type.IsInterfaceEx()) { if (!serializerTypeInfo.IsTypeAlreadyHandled(type)) { Log.Debug("Type is an interface, checking all types deriving from this interface"); // Don't check this interface again in children checks serializerTypeInfo.AddTypeAsHandled(type); // Interfaces are not a type, and in fact a LOT of types can be added (in fact every object implementing the interface). For // serialization, this is not a problem (we know the exact type), but for deserialization this IS an issue because we should // expect EVERY type that implements the type in the whole AppDomain. // This is huge performance hit, but it's the cost for dynamic easy on-the-fly serialization in WPF and Silverlight. Luckily // we already implemented caching. var typesDerivingFromInterface = TypeCache.GetTypes(t => t.ImplementsInterfaceEx(type)); foreach (var typeDerivingFromInterface in typesDerivingFromInterface) { if (typeDerivingFromInterface != type) { GetKnownTypes(typeDerivingFromInterface, serializerTypeInfo); } } Log.Debug("Finished checking all types deriving from this interface"); } // The interface itself is ignored return; } if (serializerTypeInfo.IsSpecialCollectionType(type) && !type.IsInterfaceEx()) { Log.Debug("Type is a special collection type, adding it to the array of known types"); AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo); } // Fix generics if (type.GetSafeFullName().StartsWith("System.")) { var genericArguments = type.GetGenericArgumentsEx(); foreach (var genericArgument in genericArguments) { Log.Debug("Retrieving known types for generic argument '{0}' of '{1}'", genericArgument.GetSafeFullName(), type.GetSafeFullName()); GetKnownTypes(genericArgument, serializerTypeInfo); } return; } if (!AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo)) { serializerTypeInfo.AddTypeAsHandled(type); } AddTypeMembers(type, serializerTypeInfo); // If this isn't the base type, check that as well var baseType = type.GetBaseTypeEx(); if (baseType != null) { Log.Debug("Checking base type of '{0}' for known types", type.GetSafeFullName()); if (baseType.FullName != null) { GetKnownTypes(baseType, serializerTypeInfo); } else { serializerTypeInfo.AddTypeAsHandled(baseType); } } // Last but not least, check if the type is decorated with KnownTypeAttributes var knowTypesByAttributes = GetKnownTypesViaAttributes(type); if (knowTypesByAttributes.Length > 0) { Log.Debug("Found {0} additional known types for type '{1}'", knowTypesByAttributes.Length, type.GetSafeFullName()); foreach (var knownTypeByAttribute in knowTypesByAttributes) { var attributeType = knownTypeByAttribute; if (attributeType.FullName != null) { GetKnownTypes(knownTypeByAttribute, serializerTypeInfo); } else { serializerTypeInfo.AddTypeAsHandled(attributeType); } } } }
/// <summary> /// Throws the <see cref="TypeNotRegisteredException" /> but will also reset the current type request path. /// </summary> /// <param name="type">The type.</param> /// <param name="message">The message.</param> private void ThrowTypeNotRegisteredException(Type type, string message = null) { _currentTypeRequestPath = null; // or _currentTypeRequestPath.PopType(); throw Log.ErrorAndCreateException(msg => new TypeNotRegisteredException(type, msg), "The type '{0}' is not registered", type.GetSafeFullName()); }
/// <summary> /// Registers the specific implementing type for the service type. /// </summary> /// <param name="serviceType">Type of the service.</param> /// <param name="serviceImplementationType">Type of the implementing.</param> /// <param name="tag">The tag to register the service with. The default value is <c>null</c>.</param> /// <param name="registrationType">The registration type.</param> /// <param name="registerIfAlreadyRegistered">if set to <c>true</c>, an older type registration is overwritten by this new one.</param> /// <param name="originalContainer">The original container where the type was found in.</param> /// <param name="createServiceFunc">The create service function.</param> /// <exception cref="System.InvalidOperationException"></exception> /// <exception cref="ArgumentNullException">The <paramref name="serviceType" /> is <c>null</c>.</exception> private void RegisterType(Type serviceType, Type serviceImplementationType, object tag, RegistrationType registrationType, bool registerIfAlreadyRegistered, object originalContainer, Func<ServiceLocatorRegistration, object> createServiceFunc) { Argument.IsNotNull("serviceType", serviceType); if (serviceImplementationType == null) { // Dynamic late-bound type serviceImplementationType = typeof(LateBoundImplementation); } if (serviceImplementationType.IsInterfaceEx()) { throw Log.ErrorAndCreateException<InvalidOperationException>("Cannot register interface type '{0}' as implementation, make sure to specify an actual class", serviceImplementationType.GetSafeFullName()); } /* TODO: This code have to be here to ensure the right usage of non-generic overloads of register methods. * TODO: If it is finally accepted then remove it from ServiceLocatorAutoRegistrationManager if (serviceImplementationType.IsAbstractEx() || !serviceType.IsAssignableFromEx(serviceImplementationType)) { string message = string.Format("The type '{0}' is abstract or can't be registered as '{1}'", serviceImplementationType, serviceType); Log.Error(message); throw new InvalidOperationException(message); } */ // Outside lock scope for event ServiceLocatorRegistration registeredTypeInfo = null; lock (this) { if (!registerIfAlreadyRegistered && IsTypeRegistered(serviceType, tag)) { //Log.Debug("Type '{0}' already registered, will not overwrite registration", serviceType.FullName); return; } var serviceInfo = new ServiceInfo(serviceType, tag); if (_registeredInstances.ContainsKey(serviceInfo)) { _registeredInstances.Remove(serviceInfo); } Log.Debug("Registering type '{0}' to type '{1}'", serviceType.FullName, serviceImplementationType.FullName); registeredTypeInfo = new ServiceLocatorRegistration(serviceType, serviceImplementationType, tag, registrationType, x => (createServiceFunc != null) ? createServiceFunc(x) : CreateServiceInstance(x)); _registeredTypes[serviceInfo] = registeredTypeInfo; } TypeRegistered.SafeInvoke(this, new TypeRegisteredEventArgs(registeredTypeInfo.DeclaringType, registeredTypeInfo.ImplementingType, tag, registeredTypeInfo.RegistrationType)); Log.Debug("Registered type '{0}' to type '{1}'", serviceType.FullName, serviceImplementationType.FullName); }
/// <summary> /// Determines whether the specified service type is registered. /// </summary> /// <param name="serviceType">The type of the service.</param> /// <param name="tag">The tag to register the service with. The default value is <c>null</c>.</param> /// <returns><c>true</c> if the specified service type is registered; otherwise, <c>false</c>.</returns> /// <remarks>Note that the actual implementation lays in the hands of the IoC technique being used.</remarks> /// <exception cref="ArgumentNullException">The <paramref name="serviceType"/> is <c>null</c>.</exception> public bool IsTypeRegistered(Type serviceType, object tag = null) { Argument.IsNotNull("serviceType", serviceType); var serviceInfo = new ServiceInfo(serviceType, tag); lock (this) { if (_registeredInstances.ContainsKey(serviceInfo)) { return true; } if (_registeredTypes.ContainsKey(serviceInfo)) { return true; } // CTL-161, support generic types if (serviceType.IsGenericTypeEx()) { var genericArguments = serviceType.GetGenericArgumentsEx().ToList(); var hasRealGenericArguments = (from genericArgument in genericArguments where !string.IsNullOrEmpty(genericArgument.FullName) select genericArgument).Any(); if (hasRealGenericArguments) { var genericType = serviceType.GetGenericTypeDefinitionEx(); var isOpenGenericTypeRegistered = IsTypeRegistered(genericType, tag); if (isOpenGenericTypeRegistered) { Log.Debug("An open generic type '{0}' is registered, registering new closed generic type '{1}' based on the open registration", genericType.GetSafeFullName(), serviceType.GetSafeFullName()); var registrationInfo = GetRegistrationInfo(genericType, tag); var finalType = registrationInfo.ImplementingType.MakeGenericType(genericArguments.ToArray()); RegisterType(serviceType, finalType, tag, registrationInfo.RegistrationType); return true; } } } // CTL-271 Support generic lists (array specific type) // TODO: Can register, // Last resort var eventArgs = new MissingTypeEventArgs(serviceType); MissingType.SafeInvoke(this, eventArgs); if (eventArgs.ImplementingInstance != null) { Log.Debug("Late registering type '{0}' to instance of type '{1}' via MissingTypeEventArgs.ImplementingInstance", serviceType.FullName, eventArgs.ImplementingInstance.GetType().FullName); RegisterInstance(serviceType, eventArgs.ImplementingInstance, eventArgs.Tag, this); return true; } if (eventArgs.ImplementingType != null) { Log.Debug("Late registering type '{0}' to type '{1}' via MissingTypeEventArgs.ImplementingType", serviceType.FullName, eventArgs.ImplementingType.FullName); RegisterType(serviceType, eventArgs.ImplementingType, eventArgs.Tag, eventArgs.RegistrationType, true, this, null); return true; } } return false; }
private void RegisterPropertyIfNotYetRegistered(string propertyName, Type propertyType) { var model = (ModelBase)Value; if (model.IsPropertyRegistered(propertyName)) { return; } var modelType = model.GetType(); Log.Debug("Register dynamic property '{0}.{1}' of type '{2}'", modelType.GetSafeFullName(), propertyName, propertyType.GetSafeFullName()); var registerPropertyMethodInfo = GetRegisterSimplePropertyMethodInfo(modelType); registerPropertyMethodInfo.Invoke(model, new object[] { propertyName, propertyType }); }
public ConstructorCacheKey(Type type, object[] parameters) { string key = type.GetSafeFullName(); foreach (var parameter in parameters) { key += "_" + ObjectToStringHelper.ToFullTypeString(parameter); } Key = key; _hashCode = Key.GetHashCode(); }
/// <summary> /// Initializes a new instance of the <see cref="TypeNotRegisteredException" /> class. /// </summary> /// <param name="requestedType">The requested type.</param> /// <param name="message">The message.</param> public TypeNotRegisteredException(Type requestedType, string message) : base(string.Format("The specified type '{0}' is not registered or could not be constructed. Please register type before using it. {1}", requestedType.GetSafeFullName(true), message ?? string.Empty)) { RequestedType = requestedType; }