view Implab.ServiceHost/Unity/ContainerBuilder.cs @ 281:e0916ddc9950 v3 tip

code cleanup and refactoring
author cin
date Fri, 01 Jun 2018 21:35:24 +0300
parents f07be402ab02
children
line wrap: on
line source

using System;
using System.IO;
using System.Reflection;
using Implab.Diagnostics;
using Unity;

namespace Implab.ServiceHost.Unity {
    using static Trace<ContainerBuilder>;

    public class ContainerBuilder {

        readonly TypeResolver m_resolver;

        readonly IUnityContainer m_container;

        readonly ContainerConfigurationSchema m_schema;

        Uri m_location;

        public IUnityContainer Container {
            get {
                return m_container;
            }
        }

        public ContainerBuilder() : this(null, null) {
        }

        public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) {
            m_container = container ?? new UnityContainer();
            m_resolver = new TypeResolver();
            m_schema = schema ?? ContainerConfigurationSchema.Default;
        }

        public Type ResolveType(string typeReference) {
            return string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true);
        }

        public void Visit(ITypeRegistration registration) {
            Safe.ArgumentNotNull(registration, nameof(registration));

            var registrationType = registration.GetRegistrationType(this);
            var implementationType = registration.GetImplementationType(this) ?? registrationType;

            if (registrationType == null)
                throw new Exception($"A type must be specified for the registration {registration.Name}");

            var builder = new TypeRegistrationBuilder(
                m_resolver,
                registrationType,
                implementationType
            );

            builder.Lifetime = registration.GetLifetime(this);

            if (registration.MemberInjections != null) {
                foreach(var member in registration.MemberInjections)
                    member.Visit(builder);
            }

            m_container.RegisterType(
                builder.RegistrationType,
                builder.ImplementationType,
                registration.Name,
                builder.Lifetime,
                builder.Injections
            );
        }

        public void Visit(IInstanceRegistration registration) {
            Safe.ArgumentNotNull(registration, nameof(registration));

            var registrationType = registration.GetRegistrationType(this);

            var builder = new InstanceRegistrationBuilder (
                m_resolver,
                registrationType
            );

            builder.Lifetime = registration.GetLifetime(this);

            if (registration.MemberInjections != null) {
                foreach(var member in registration.MemberInjections)
                    member.Visit(builder.ValueBuilder);
            }

            if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
                throw new Exception($"A type must be specified for the registration {registration.Name}");

            m_container.RegisterInstance(
                builder.RegistrationType ?? builder.ValueBuilder.ValueType,
                registration.Name,
                builder.ValueBuilder.Value,
                builder.Lifetime                
            );
        }

        public void AddNamespace(string ns) {
            m_resolver.AddNamespace(ns);
        }

        public void AddAssembly(string assembly) {

        }

        /// <summary>
        /// Includes the confguration. Creates a new <see cref="ContainerBuilder"/>,
        /// and loads the configuration to it. The created builder will share the
        /// container and will have its own isolated type resolver.
        /// </summary>
        /// <param name="file">A path to configuration relative to the current configuration.</param>
        public void Include(string file) {
            var includeContext = new ContainerBuilder(m_container, m_schema);

            if (m_location != null) {
                var uri =  new Uri(m_location, file);
                includeContext.LoadConfig(uri);
            } else {
                includeContext.LoadConfig(file);
            }
        }

        /// <summary>
        /// Loads a configuration from the specified local file.
        /// </summary>
        /// <param name="file">The path to the configuration file.</param>
        public void LoadConfig(string file) {
            Safe.ArgumentNotEmpty(file, nameof(file));

            LoadConfig(new Uri(Path.GetFullPath(file)));
        }

        public void LoadConfig(Uri location) {
            Safe.ArgumentNotNull(location, nameof(location));

            m_location = location;

            var config = m_schema.LoadConfig(location.ToString());
            config.Visit(this);
        }

    }
}