Exemple #1
0
        private void _resolveWithMappingProvider(ResolveLoad resolve_load, ref MappingLoad mapping_load, out object concrete_instance)
        {
            //Begin with null output.
            concrete_instance = null;

            //Mapping level defines until which stage or level , the mapping should be applied. If mapping provider is null or mapping level is none, don't proceed.
            if (mapping_load.provider == null || mapping_load.level == MappingLevel.None)
            {
                return;
            }

            if (mapping_load.level == MappingLevel.Current)
            {
                mapping_load.level = MappingLevel.None;
            }

            if (resolve_load.contract_type == null)
            {
                throw new ArgumentNullException(nameof(resolve_load.contract_type));
            }

            var _dip_values = mapping_load.provider.Resolve(resolve_load.contract_type, resolve_load.contract_name, resolve_load.contract_parent);

            //if external mapping resolves to a value, ensure that this injection is for suitable target or it should be for all
            if (_dip_values.concrete_instance != null && (mapping_load.injection == _dip_values.injection || mapping_load.injection == InjectionTarget.All))
            {
                concrete_instance = _dip_values.concrete_instance;
            }
        }
Exemple #2
0
        private void _resolveAsRegistered(ResolveLoad resolve_load, MappingLoad mapping_load, out object concrete_instance)
        {
            concrete_instance = null;
            Type current_contract_type = resolve_load.contract_type;

            if (current_contract_type == null)
            {
                throw new ArgumentNullException(nameof(current_contract_type));
            }

            //Try to resolve multiple params if needed.
            _resolveArrayTypes(resolve_load, mapping_load, out concrete_instance);

            if (concrete_instance != null)
            {
                return;
            }
            var _registered = _getMapping(resolve_load.priority_key, current_contract_type);

            //Try to resolve with mapping provider before anything.
            _resolveWithMappingProvider(resolve_load, ref mapping_load, out concrete_instance);

            if (concrete_instance != null)
            {
                return;
            }

            //If it is registered, then resolve it else re send request as transient.
            if (_registered.exists)
            {
                //If already exists, then fetch the concrete type. Also, if a concrete type is registered, we can be confident that it has already passed the concrete type validation.
                resolve_load.concrete_type = _registered.load.concrete_type ?? resolve_load.concrete_type ?? current_contract_type;

                switch (_registered.load.mode)
                {
                case RegisterMode.Singleton:
                    concrete_instance = _registered.load.concrete_instance;
                    break;

                case RegisterMode.Transient:
                    concrete_instance = _createInstance(resolve_load, mapping_load);
                    break;
                }
            }
            else // It is not registered. So, we reassign as transient resolution.
            {
                resolve_load.mode = ResolveMode.Transient;
                if (resolve_load.transient_level == TransientCreationLevel.None)
                {
                    resolve_load.transient_level = TransientCreationLevel.Current;
                }

                //todo: Should we reset the mapping level as well??
                concrete_instance = _mainResolve(resolve_load, mapping_load);
            }
        }
Exemple #3
0
        private void _resolveAsTransient(ResolveLoad resolve_load, MappingLoad mapping_load, out object concrete_instance)
        {
            concrete_instance = null;
            //Try to resolve multiple params if needed.
            _resolveArrayTypes(resolve_load, mapping_load, out concrete_instance);
            if (concrete_instance != null)
            {
                return;
            }

            var _registered = _getMapping(resolve_load.priority_key, resolve_load.contract_type);

            //By default, create instance for the contract type.
            if (resolve_load.concrete_type == null)
            {
                resolve_load.concrete_type = resolve_load.contract_type;
            }
            //If a mapping already exists, then create instance for the concrete type in mapping.
            if (_registered.exists)
            {
                resolve_load.concrete_type = _registered.load.concrete_type;
            }

            //Try to resolve with mapping provider before anything.
            _resolveWithMappingProvider(resolve_load, ref mapping_load, out concrete_instance);

            if (concrete_instance != null)
            {
                return;
            }

            //Validate concrete type.
            if (resolve_load.concrete_type == typeof(string) || resolve_load.concrete_type.IsValueType)
            {
                throw new ArgumentException($@"Value type dependency error. The {resolve_load.contract_parent ?? resolve_load.contract_type} with contract name {resolve_load.contract_name ?? "#NotFound#"} contains a value dependency {resolve_load.concrete_type}. Try adding a mapping provider for injecting value types.");
            }

            //If transient is not none, try to create new instance. If none, then go with as registered.
            if (resolve_load.transient_level != TransientCreationLevel.None)
            {
                concrete_instance = _createInstance(resolve_load, mapping_load);
            }
            else
            {
                resolve_load.mode = ResolveMode.AsRegistered;
                concrete_instance = _mainResolve(resolve_load, mapping_load);
            }
        }
Exemple #4
0
        private object _mainResolve(ResolveLoad resolve_load, MappingLoad mapping_load)
        {
            object concrete_instance = null;

            switch (resolve_load.mode)
            {
            case ResolveMode.AsRegistered:     //This can be transient or singleton.
                _resolveAsRegistered(resolve_load, mapping_load, out concrete_instance);
                break;

            case ResolveMode.Transient:     //This creates new instance.
                _resolveAsTransient(resolve_load, mapping_load, out concrete_instance);
                break;
            }

            return(concrete_instance);
        }
Exemple #5
0
        private object _createInstance(ResolveLoad resolve_load, MappingLoad mapping_load)
        {
            //If transient creation is current level only, then further dependencies should not generate new instance.
            if (resolve_load.transient_level == TransientCreationLevel.Current)
            {
                resolve_load.transient_level = TransientCreationLevel.None;
            }

            object concrete_instance = null;

            _validateConcreteType(resolve_load.concrete_type);
            ConstructorInfo constructor = _getConstructor(resolve_load.concrete_type);

            _resolveConstructorParameters(ref constructor, resolve_load, mapping_load, ref concrete_instance);
            _resolveProperties(resolve_load, mapping_load, ref concrete_instance);
            return(concrete_instance);
        }
Exemple #6
0
        private void _resolveArrayTypes(ResolveLoad resolve_load, MappingLoad mapping_load, out object concrete_instance)
        {
            concrete_instance = null;
            Type array_contract_type = null;

            //If contracttype is of list or enumerable or array or collection, then return all the registered values for the generictypedefinition
            if (resolve_load.contract_type.IsList())
            {
                //We need to check the generic type.
                array_contract_type = resolve_load.contract_type.GetGenericArguments()[0];
            }
            else if (resolve_load.contract_type.IsArray)
            {
                array_contract_type = resolve_load.contract_type.GetElementType();
            }

            if (array_contract_type == null)
            {
                return;                              //Then this value is null and unable to resolve.
            }
            List <RegisterLoad> _registrations = new List <RegisterLoad>();

            _registrations = _getAllMappings(array_contract_type) ?? new List <RegisterLoad>();
            List <object> _instances_list = new List <object>();

            if (_registrations.Count > 0)
            {
                foreach (var _registration in _registrations)
                {
                    try
                    {
                        ResolveLoad _new_resolve_load = _registration.convert(resolve_load.contract_name, resolve_load.contract_parent, resolve_load.mode);
                        _new_resolve_load.transient_level = resolve_load.transient_level;
                        var _current_instance = _mainResolve(_new_resolve_load, mapping_load);
                        _instances_list.Add(_current_instance);
                    }
                    catch (Exception)
                    {
                        // Don't throw, continue
                        continue; //Implement a logger to capture the details and return back to the user.
                    }
                }
                concrete_instance = _instances_list.changeType(resolve_load.contract_type);  //Convert to the contract type.
            }
        }
Exemple #7
0
        private void _resolveProperties(ResolveLoad resolve_load, MappingLoad mapping_load, ref object concrete_instance)
        {
            //If creation is current with properties, then constructor and props should generate new instance. Rest should be resolved.
            if (resolve_load.transient_level == TransientCreationLevel.CurrentWithDependencies)
            {
                resolve_load.transient_level = TransientCreationLevel.Current;
            }
            if (mapping_load?.level == MappingLevel.CurrentWithDependencies)
            {
                mapping_load.level = MappingLevel.Current;
            }

            //Resolve only properties that are of type Haley inject and also ignore if it has haleyignore
            var _props = resolve_load.concrete_type.GetProperties().Where(
                p => Attribute.IsDefined(p, typeof(HaleyInjectAttribute)));

            if (_props.Count() > 0)
            {
                foreach (PropertyInfo pinfo in _props)
                {
                    try
                    {
                        //New resolve and mapping load.
                        ResolveLoad _new_res_load = new ResolveLoad(resolve_load.mode, resolve_load.priority_key, pinfo.Name, pinfo.PropertyType, resolve_load.concrete_type, null, resolve_load.transient_level);

                        MappingLoad _new_map_load = new MappingLoad(mapping_load.provider, mapping_load.level, InjectionTarget.Property);

                        var resolved_value = _mainResolve(_new_res_load, _new_map_load);
                        if (resolved_value != null)
                        {
                            pinfo.SetValue(concrete_instance, resolved_value);
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
        }
Exemple #8
0
        private bool _register(RegisterLoad register_load, MappingLoad mapping_load)
        {
            //Validate if the contract type is alredy registered. If so, against correct concrete type.
            bool _exists = _validateExistence(register_load);

            //If it already exists and we should not over write, then do not proceed.
            if (_exists && (!overwrite_if_registered))
            {
                return(false);
            }

            //Validate if the concrete type can be registered
            _validateConcreteType(register_load.concrete_type);

            //Generate instance only if the provided value is null and also singleton. Only if it is singleton, we create an instance and store. Else we store only the concrete type and save instance as it is (even if is null).
            if (register_load.concrete_instance == null && register_load.mode == RegisterMode.Singleton)
            {
                ResolveLoad resolve_load = register_load.convert(null, null, ResolveMode.AsRegistered);
                register_load.concrete_instance = _createInstance(resolve_load, mapping_load); //Create instance resolving all dependencies
            }

            //Get the key to register.
            var _key = new KeyBase(register_load.contract_type, register_load.priority_key);

            //We have already validate if overwrite is required or not. If we reach this point, then overwrite is required.
            if (_exists)
            {
                //Update the existing value
                RegisterLoad _existing_value;
                _mappings.TryGetValue(_key, out _existing_value);
                _mappings.TryUpdate(_key, register_load, _existing_value); //Remember to assign the instance
            }
            else
            {
                _mappings.TryAdd(_key, register_load);
            }
            return(true);
        }
Exemple #9
0
        private void _resolveConstructorParameters(ref ConstructorInfo constructor, ResolveLoad resolve_load, MappingLoad mapping_load, ref object concrete_instance)
        {
            //If creation is current with properties, then constructor and props should generate new instance. Rest should be resolved.
            if (resolve_load.transient_level == TransientCreationLevel.CurrentWithDependencies)
            {
                resolve_load.transient_level = TransientCreationLevel.Current;
            }

            //TODO: CHECK IF BELOW REASSIGNMENT IS REQUIRED.
            if (mapping_load?.level == MappingLevel.CurrentWithDependencies)
            {
                mapping_load.level = MappingLevel.Current;
            }

            //Resolve the param arugments for the constructor.
            ParameterInfo[] constructor_params = constructor.GetParameters();

            //If parameter less construction, return a new creation.
            if (constructor_params.Length == 0)
            {
                concrete_instance = Activator.CreateInstance(resolve_load.concrete_type);
            }
            else
            {
                List <object> parameters = new List <object>(constructor_params.Length);
                foreach (ParameterInfo pinfo in constructor_params)
                {
                    //New resolve and mapping load.
                    ResolveLoad _new_res_load = new ResolveLoad(resolve_load.mode, resolve_load.priority_key, pinfo.Name, pinfo.ParameterType, resolve_load.concrete_type, null, resolve_load.transient_level);

                    MappingLoad _new_map_load = new MappingLoad(mapping_load.provider, mapping_load.level, InjectionTarget.Constructor);

                    parameters.Add(_mainResolve(_new_res_load, _new_map_load));
                }
                concrete_instance = constructor.Invoke(parameters.ToArray());
            }
        }