Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

NopEngine.cs

using System.Reflection;
using AutoMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Nop.Core.Infrastructure.Mapper;

namespace Nop.Core.Infrastructure;

/// 
/// Represents Nop engine
/// 
public partial class NopEngine : IEngine
{
    #region Utilities

    /// 
    /// Get IServiceProvider
    /// 
    /// IServiceProvider
    protected virtual IServiceProvider GetServiceProvider(IServiceScope scope = null)
    {
        if (scope == null)
        {
            var accessor = ServiceProvider?.GetService();
            var context = accessor?.HttpContext;
            return context?.RequestServices ?? ServiceProvider;
        }
        return scope.ServiceProvider;
    }

    /// 
    /// Run startup tasks
    /// 
    protected virtual void RunStartupTasks()
    {
        //find startup tasks provided by other assemblies
        var typeFinder = Singleton.Instance;
        var startupTasks = typeFinder.FindClassesOfType();

        //create and sort instances of startup tasks
        //we startup this interface even for not installed plugins. 
        //otherwise, DbContext initializers won't run and a plugin installation won't work
        var instances = startupTasks
            .Select(startupTask => (IStartupTask)Activator.CreateInstance(startupTask))
            .Where(startupTask => startupTask != null)
            .OrderBy(startupTask => startupTask.Order);

        //execute tasks
        foreach (var task in instances)
            task.Execute();
    }

    /// 
    /// Register and configure AutoMapper
    /// 
    protected virtual void AddAutoMapper()
    {
        //find mapper configurations provided by other assemblies
        var typeFinder = Singleton.Instance;
        var mapperConfigurations = typeFinder.FindClassesOfType();

        //create and sort instances of mapper configurations
        var instances = mapperConfigurations
            .Select(mapperConfiguration => (IOrderedMapperProfile)Activator.CreateInstance(mapperConfiguration))
            .Where(mapperConfiguration => mapperConfiguration != null)
            .OrderBy(mapperConfiguration => mapperConfiguration.Order);

        //create AutoMapper configuration
        var config = new MapperConfiguration(cfg =>
        {
            foreach (var instance in instances) 
                cfg.AddProfile(instance.GetType());
        });

        //register
        AutoMapperConfiguration.Init(config);
    }

    protected virtual Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var assemblyFullName = args.Name;

        //check for assembly already loaded
        var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyFullName);
        if (assembly != null)
            return assembly;

        //get assembly from TypeFinder
        var typeFinder = Singleton.Instance;

        return typeFinder?.GetAssemblyByName(assemblyFullName);
    }

    #endregion

    #region Methods

    /// 
    /// Add and configure services
    /// 
    /// Collection of service descriptors
    /// Configuration of the application
    public virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        //register engine
        services.AddSingleton(this);

        //find startup configurations provided by other assemblies
        var typeFinder = Singleton.Instance;
        var startupConfigurations = typeFinder.FindClassesOfType();

        //create and sort instances of startup configurations
        var instances = startupConfigurations
            .Select(startup => (INopStartup)Activator.CreateInstance(startup))
            .Where(startup => startup != null)
            .OrderBy(startup => startup.Order);

        //configure services
        foreach (var instance in instances)
            instance.ConfigureServices(services, configuration);

        services.AddSingleton(services);

        //register mapper configurations
        AddAutoMapper();

        //run startup tasks
        RunStartupTasks();

        //resolve assemblies here. otherwise, plugins can throw an exception when rendering views
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }

    /// 
    /// Configure HTTP request pipeline
    /// 
    /// Builder for configuring an application's request pipeline
    public virtual void ConfigureRequestPipeline(IApplicationBuilder application)
    {
        ServiceProvider = application.ApplicationServices;

        //find startup configurations provided by other assemblies
        var typeFinder = Singleton.Instance;
        var startupConfigurations = typeFinder.FindClassesOfType();

        //create and sort instances of startup configurations
        var instances = startupConfigurations
            .Select(startup => (INopStartup)Activator.CreateInstance(startup))
            .Where(startup => startup != null)
            .OrderBy(startup => startup.Order);

        //configure request pipeline
        foreach (var instance in instances)
            instance.Configure(application);
    }

    /// 
    /// Resolve dependency
    /// 
    /// Scope
    /// Type of resolved service
    /// Resolved service
    public virtual T Resolve(IServiceScope scope = null) where T : class
    {
        return (T)Resolve(typeof(T), scope);
    }

    /// 
    /// Resolve dependency
    /// 
    /// Type of resolved service
    /// Scope
    /// Resolved service
    public virtual object Resolve(Type type, IServiceScope scope = null)
    {
        return GetServiceProvider(scope)?.GetService(type);
    }

    /// 
    /// Resolve dependencies
    /// 
    /// Type of resolved services
    /// Collection of resolved services
    public virtual IEnumerable ResolveAll()
    {
        return (IEnumerable)GetServiceProvider().GetServices(typeof(T));
    }

    /// 
    /// Resolve unregistered service
    /// 
    /// Type of service
    /// Resolved service
    public virtual object ResolveUnregistered(Type type)
    {
        Exception innerException = null;
        foreach (var constructor in type.GetConstructors())
            try
            {
                //try to resolve constructor parameters
                var parameters = constructor.GetParameters().Select(parameter =>
                {
                    var service = Resolve(parameter.ParameterType) ?? throw new NopException("Unknown dependency");
                    return service;
                });

                //all is ok, so create instance
                return Activator.CreateInstance(type, parameters.ToArray());
            }
            catch (Exception ex)
            {
                innerException = ex;
            }

        throw new NopException("No constructor was found that had all the dependencies satisfied.", innerException);
    }

    #endregion

    #region Properties

    /// 
    /// Service provider
    /// 
    public virtual IServiceProvider ServiceProvider { get; protected set; }

    #endregion
}