发布1203
大石头 编写于 2019-12-03 23:10:00
NewLife.Cube
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WebEncoders;
using NewLife.Common;
using NewLife.Cube.Extensions;
using NewLife.Reflection;
using NewLife.Web;

namespace NewLife.Cube
{
    /// <summary>魔方服务</summary>
    public static class CubeService
    {
        #region 配置魔方
        /// <summary>添加魔方</summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddCube(this IServiceCollection services)
        {
            // 修正系统名,确保可运行
            var set = SysConfig.Current;
            if (set.IsNew || set.Name == "NewLife.Cube.Views")
            {
                set.Name = "NewLife.Cube";
                set.Save();
            }

            // 配置Cookie策略
            services.Configure<CookiePolicyOptions>(options =>
            {
                // 此项为true需要用户授权才能记录cookie
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            // 添加Session会话支持
            services.AddSession();

            //// 添加标识用户支持
            //services.AddDefaultIdentity<IdentityUser>();

            //services.AddSingleton<IRazorViewEngine, CompositePrecompiledMvcEngine>();
            //services.AddSingleton<IView, PrecompiledMvcView>();

            var provider = services.BuildServiceProvider();
            //var env = provider.GetService<IHostingEnvironment>();
            var env = provider.GetService(typeof(IWebHostEnvironment)) as IWebHostEnvironment;
            if (env != null) services.AddCubeDefaultUI(env);

            services.AddMvc(opt =>
            {
                // 分页器绑定
                opt.ModelBinderProviders.Insert(0, new PagerModelBinderProvider());

                // 模型绑定
                opt.ModelBinderProviders.Insert(0, new EntityModelBinderProvider());

                // 过滤器
                //opt.Filters.Add<MvcHandleErrorAttribute>();

                //opt.EnableEndpointRouting = false;

            })
            // 添加版本兼容性,显示声明当前应用版本为2.1
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);


            services.AddCustomApplicationParts();

            //services.AddSingleton<IRazorViewEngine, CompositePrecompiledMvcEngine>();
            //services.AddTransient<IConfigureOptions<MvcViewOptions>, RazorViewOPtionsSetup>();

            //// 注册Cookie认证服务
            //services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();

            // 添加魔方模块
            // 添加管理提供者
            services.AddManageProvider();

            //// 添加Http上下文访问器
            //services.AddHttpContextAccessor();

            //services.AddCubeDefaultUI(HostingEnvironment);

            // 添加压缩
            services.AddResponseCompression();

            // 防止汉字被自动编码
            services.Configure<WebEncoderOptions>(options =>
            {
                options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
            });

            return services;
        }

        /// <summary>添加自定义应用部分,即添加外部引用的控制器、视图的Assembly,作为本应用的一部分</summary>
        /// <param name="services"></param>
        public static void AddCustomApplicationParts(this IServiceCollection services)
        {
            var manager = services.LastOrDefault(e => e.ServiceType == typeof(ApplicationPartManager))?.ImplementationInstance as ApplicationPartManager;
            if (manager == null) manager = new ApplicationPartManager();

            var list = FindAllArea();

            foreach (var asm in list)
            {
                var factory = ApplicationPartFactory.GetApplicationPartFactory(asm);
                foreach (var part in factory.GetApplicationParts(asm))
                {
                    if (!manager.ApplicationParts.Contains(part)) manager.ApplicationParts.Add(part);
                }
            }
        }

        /// <summary>遍历所有引用了AreaRegistrationBase的程序集</summary>
        /// <returns></returns>
        static List<Assembly> FindAllArea()
        {
            var list = new List<Assembly>();
            var cs = typeof(ControllerBaseX).GetAllSubclasses(true).ToArray();
            foreach (var item in cs)
            {
                var asm = item.Assembly;
                if (!list.Contains(asm))
                {
                    list.Add(asm);
                }
            }
            cs = typeof(RazorPage).GetAllSubclasses(true).ToArray();
            foreach (var item in cs)
            {
                var asm = item.Assembly;
                if (!list.Contains(asm))
                {
                    list.Add(asm);
                }
            }

            // 为了能够实现模板覆盖,程序集相互引用需要排序,父程序集在前
            list.Sort((x, y) =>
            {
                if (x == y) return 0;
                if (x != null && y == null) return 1;
                if (x == null && y != null) return -1;

                //return x.GetReferencedAssemblies().Any(e => e.FullName == y.FullName) ? 1 : -1;
                // 对程序集引用进行排序时,不能使用全名,当魔方更新而APP没有重新编译时,版本的不同将会导致全名不同,无法准确进行排序
                var yname = y.GetName().Name;
                return x.GetReferencedAssemblies().Any(e => e.Name == yname) ? 1 : -1;
            });

            return list;
        }
        #endregion

        #region 使用魔方
        /// <summary>使用魔方</summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseCube(this IApplicationBuilder app)
        {
            // 配置静态Http上下文访问器
            app.UseStaticHttpContext();

            var set = Setting.Current;

            // 添加自定义中间件(3.0开始采用netcore原生版本错误页面)
            // 注册错误处理模块中间件
            //app.UseErrorModule();

            // 压缩配置
            if (set.EnableCompress) app.UseResponseCompression();

            // 注册请求执行时间中间件
            app.UseDbRunTimeModule();

            if (set.SslMode > SslModes.Disable) app.UseHttpsRedirection();

            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseSession();
            app.UseAuthentication();

            app.UseRouting();
            // 设置默认路由
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    "CubeAreas",
                    "{area=Admin}/{controller=Index}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    "Default",
                    "{controller=Index}/{action=Index}/{id?}"
                    );
                endpoints.MapRazorPages();
            })
            .Build();

            // 使用管理提供者
            app.UseManagerProvider();

            // 自动检查并添加菜单
            AreaBase.RegisterArea<Admin.AdminArea>();

            return app;
        }
        #endregion
    }
}