예제 #1
0
    private static void AddRelatedParts(IServiceCollection services, string framework)
    {
        var _assemblyMap =
            new Dictionary <UIFramework, string>()
        {
            [UIFramework.Bootstrap5] = "Microsoft.AspNetCore.Identity.UI.Views.V5",
            [UIFramework.Bootstrap4] = "Microsoft.AspNetCore.Identity.UI.Views.V4",
        };

        var mvcBuilder = services
                         .AddMvc()
                         .ConfigureApplicationPartManager(partManager =>
        {
            var thisAssembly      = typeof(IdentityBuilderUIExtensions).Assembly;
            var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(thisAssembly, throwOnError: true);
            var relatedParts      = relatedAssemblies.ToDictionary(
                ra => ra,
                CompiledRazorAssemblyApplicationPartFactory.GetDefaultApplicationParts);

            var selectedFrameworkAssembly = _assemblyMap[framework == "V4" ? UIFramework.Bootstrap4 : UIFramework.Bootstrap5];

            foreach (var kvp in relatedParts)
            {
                var assemblyName = kvp.Key.GetName().Name;
                if (!IsAssemblyForFramework(selectedFrameworkAssembly, assemblyName))
                {
                    RemoveParts(partManager, kvp.Value);
                }
                else
                {
                    AddParts(partManager, kvp.Value);
                }
            }
            bool IsAssemblyForFramework(string frameworkAssembly, string assemblyName) =>
            string.Equals(assemblyName, frameworkAssembly, StringComparison.OrdinalIgnoreCase);
            void RemoveParts(
                ApplicationPartManager manager,
                IEnumerable <ApplicationPart> partsToRemove)
            {
                for (var i = 0; i < manager.ApplicationParts.Count; i++)
                {
                    var part = manager.ApplicationParts[i];
                    if (partsToRemove.Any(p => string.Equals(
                                              p.Name,
                                              part.Name,
                                              StringComparison.OrdinalIgnoreCase)))
                    {
                        manager.ApplicationParts.Remove(part);
                    }
                }
            }
            void AddParts(
                ApplicationPartManager manager,
                IEnumerable <ApplicationPart> partsToAdd)
            {
                foreach (var part in partsToAdd)
                {
                    if (!manager.ApplicationParts.Any(p => p.GetType() == part.GetType() &&
                                                      string.Equals(p.Name, part.Name, StringComparison.OrdinalIgnoreCase)))
                    {
                        manager.ApplicationParts.Add(part);
                    }
                }
            }
        });
    }
        private static void AddRelatedParts(IdentityBuilder builder)
        {
            var mvcBuilder = builder.Services
                             .AddMvc()
                             .ConfigureApplicationPartManager(partManager =>
            {
                // We try to resolve the UI framework that was used by looking at the entry assembly.
                // When an app runs, the entry assembly will point to the built app. In some rare cases
                // (functional testing) the app assembly will be different, and we'll try to locate it through
                // the same mechanism that MVC uses today.
                // Finally, if for some reason we aren't able to find the assembly, we'll use our default value
                // (Bootstrap4)
                if (!TryResolveUIFramework(Assembly.GetEntryAssembly(), out var framework) &&
                    !TryResolveUIFramework(GetApplicationAssembly(builder), out framework))
                {
                    framework = default;
                }

                var thisAssembly      = typeof(IdentityBuilderUIExtensions).Assembly;
                var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(thisAssembly, throwOnError: true);
                var relatedParts      = relatedAssemblies.ToDictionary(
                    ra => ra,
                    CompiledRazorAssemblyApplicationPartFactory.GetDefaultApplicationParts);

                var selectedFrameworkAssembly = _assemblyMap[framework];

                foreach (var kvp in relatedParts)
                {
                    var assemblyName = kvp.Key.GetName().Name;
                    if (!IsAssemblyForFramework(selectedFrameworkAssembly, assemblyName))
                    {
                        RemoveParts(partManager, kvp.Value);
                    }
                    else
                    {
                        AddParts(partManager, kvp.Value);
                    }
                }

                bool IsAssemblyForFramework(string frameworkAssembly, string assemblyName) =>
                string.Equals(assemblyName, frameworkAssembly, StringComparison.OrdinalIgnoreCase);

                void RemoveParts(
                    ApplicationPartManager manager,
                    IEnumerable <ApplicationPart> partsToRemove)
                {
                    for (var i = 0; i < manager.ApplicationParts.Count; i++)
                    {
                        var part = manager.ApplicationParts[i];
                        if (partsToRemove.Any(p => string.Equals(
                                                  p.Name,
                                                  part.Name,
                                                  StringComparison.OrdinalIgnoreCase)))
                        {
                            manager.ApplicationParts.Remove(part);
                        }
                    }
                }

                void AddParts(
                    ApplicationPartManager manager,
                    IEnumerable <ApplicationPart> partsToAdd)
                {
                    foreach (var part in partsToAdd)
                    {
                        if (!manager.ApplicationParts.Any(p => p.GetType() == part.GetType() &&
                                                          string.Equals(p.Name, part.Name, StringComparison.OrdinalIgnoreCase)))
                        {
                            manager.ApplicationParts.Add(part);
                        }
                    }
                }
            });
        }
예제 #3
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure <CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded    = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            var rootDir = new DirectoryInfo(_hostingEnvironment.ContentRootPath);
            var dir     = new DirectoryInfo(Path.Combine(rootDir.ToString(), "Modules"));

            List <string> assmemblyNameList = new List <string>();

            foreach (var file in dir.GetFileSystemInfos("*.dll", SearchOption.AllDirectories))
            {
                Assembly assembly;
                try
                {
                    assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName);
                }
                catch (FileLoadException)
                {
                    // Get loaded assembly. This assembly might be loaded
                    assembly = Assembly.Load(new AssemblyName(Path.GetFileNameWithoutExtension(file.Name)));

                    if (assembly == null)
                    {
                        throw;
                    }
                }

                assmemblyNameList.Add(assembly.GetName().Name);
            }

            services.Configure <RazorViewEngineOptions>(
                options => { options.ViewLocationExpanders.Add(new ThemeableViewLocationExpander()); });

            var mvcBuilder = services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);


            foreach (var item in assmemblyNameList)
            {
                mvcBuilder.AddRazorOptions(o =>
                {
                    o.AdditionalCompilationReferences.Add(MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName(item)).Location));
                });

                var pluginAssembly = Assembly.Load(new AssemblyName(item));
                var partFactory    = ApplicationPartFactory.GetApplicationPartFactory(pluginAssembly);

                foreach (var part in partFactory.GetApplicationParts(pluginAssembly))
                {
                    mvcBuilder.PartManager.ApplicationParts.Add(part);
                }

                var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(pluginAssembly, throwOnError: true);
                foreach (var assembly in relatedAssemblies)
                {
                    partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
                    foreach (var part in partFactory.GetApplicationParts(assembly))
                    {
                        mvcBuilder.PartManager.ApplicationParts.Add(part);
                    }
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Initialize
        /// </summary>
        /// <param name="applicationPartManager">Application part manager</param>
        /// <param name="config">Config</param>
        public static void Initialize(ApplicationPartManager applicationPartManager, IHostingEnvironment hostingEnvironment, FrameworkPluginOptions options)
        {
            if (applicationPartManager == null)
            {
                throw new ArgumentNullException(nameof(applicationPartManager));
            }

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

            using (new DisposableWriteLock(Locker))
            {
                // TODO: Add verbose exception handling / raising here since this is happening on app startup and could
                // prevent app from starting altogether
                var pluginFolder = new DirectoryInfo(CommonHelper.MapPath(PluginsPath));
                shadowCopyFolder        = new DirectoryInfo(CommonHelper.MapPath(ShadowCopyPath));
                reserveShadowCopyFolder = new DirectoryInfo(Path.Combine(CommonHelper.MapPath(ShadowCopyPath), $"{RESERVE_SHADOW_COPY_FOLDER_NAME}{DateTime.Now.ToFileTimeUtc()}"));

                var referencedPlugins   = new List <PluginDescriptor>();
                var incompatiblePlugins = new List <string>();

                try
                {
                    var installedPluginSystemNames = GetInstalledPluginNames(CommonHelper.MapPath(InstalledPluginsFilePath));

                    Debug.WriteLine("Creating shadow copy folder and querying for DLLs");
                    //ensure folders are created
                    Directory.CreateDirectory(pluginFolder.FullName);
                    Directory.CreateDirectory(shadowCopyFolder.FullName);

                    //get list of all files in bin
                    var binFiles = shadowCopyFolder.GetFiles("*", SearchOption.AllDirectories);
                    if (options.ClearPluginShadowDirectoryOnStartup)
                    {
                        //clear out shadow copied plugins
                        foreach (var f in binFiles)
                        {
                            if (f.Name.Equals("placeholder.txt", StringComparison.InvariantCultureIgnoreCase))
                            {
                                continue;
                            }

                            Debug.WriteLine("Deleting " + f.Name);
                            try
                            {
                                //ignore index.htm
                                var fileName = Path.GetFileName(f.FullName);
                                if (fileName.Equals("index.htm", StringComparison.InvariantCultureIgnoreCase))
                                {
                                    continue;
                                }

                                File.Delete(f.FullName);
                            }
                            catch (Exception exc)
                            {
                                Debug.WriteLine("Error deleting file " + f.Name + ". Exception: " + exc);
                            }
                        }

                        //delete all reserve folders
                        foreach (var directory in shadowCopyFolder.GetDirectories(RESERVE_SHADOW_COPY_FOLDER_NAME_PATTERN, SearchOption.TopDirectoryOnly))
                        {
                            try
                            {
                                CommonHelper.DeleteDirectory(directory.FullName);
                            }
                            catch
                            {
                                //do nothing
                            }
                        }
                    }

                    //load description files
                    foreach (var dfd in GetDescriptionFilesAndDescriptors(pluginFolder))
                    {
                        var descriptionFile  = dfd.Key;
                        var pluginDescriptor = dfd.Value;

                        //ensure that version of plugin is valid
                        if (!pluginDescriptor.SupportedVersions.Contains(CurrentVersion, StringComparer.InvariantCultureIgnoreCase))
                        {
                            incompatiblePlugins.Add(pluginDescriptor.SystemName);
                            continue;
                        }

                        //some validation
                        if (string.IsNullOrWhiteSpace(pluginDescriptor.SystemName))
                        {
                            throw new Exception($"A plugin '{descriptionFile.FullName}' has no system name. Try assigning the plugin a unique name and recompiling.");
                        }

                        if (referencedPlugins.Contains(pluginDescriptor))
                        {
                            throw new Exception($"A plugin with '{pluginDescriptor.SystemName}' system name is already defined");
                        }

                        //set 'Installed' property
                        pluginDescriptor.Installed = installedPluginSystemNames
                                                     .FirstOrDefault(x => x.Equals(pluginDescriptor.SystemName, StringComparison.InvariantCultureIgnoreCase)) != null;

                        try
                        {
                            if (descriptionFile.Directory == null)
                            {
                                throw new Exception($"Directory cannot be resolved for '{descriptionFile.Name}' description file");
                            }

                            //get list of all DLLs in plugins (not in bin!)
                            var pluginFiles = descriptionFile.Directory.GetFiles("*.dll", SearchOption.AllDirectories)
                                              //just make sure we're not registering shadow copied plugins
                                              .Where(x => !binFiles.Select(q => q.FullName).Contains(x.FullName))
                                              .Where(x => IsPackagePluginFolder(x.Directory))
                                              .ToList();

                            //other plugin description info
                            var mainPluginFile = pluginFiles
                                                 .FirstOrDefault(x => x.Name.Equals(pluginDescriptor.AssemblyFileName, StringComparison.InvariantCultureIgnoreCase));

                            //plugin have wrong directory
                            if (mainPluginFile == null)
                            {
                                incompatiblePlugins.Add(pluginDescriptor.SystemName);
                                continue;
                            }

                            pluginDescriptor.OriginalAssemblyFile = mainPluginFile;

                            //shadow copy main plugin file
                            var pluginAssembly = PerformFileDeploy(mainPluginFile, options);
                            pluginDescriptor.ReferencedAssembly = pluginAssembly;

                            var partFactory = ApplicationPartFactory.GetApplicationPartFactory(pluginAssembly);

                            foreach (var part in partFactory.GetApplicationParts(pluginAssembly))
                            {
                                applicationPartManager.ApplicationParts.Add(part);
                            }

                            var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(pluginAssembly, throwOnError: true);
                            foreach (var assembly in relatedAssemblies)
                            {
                                partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
                                foreach (var part in partFactory.GetApplicationParts(assembly))
                                {
                                    applicationPartManager.ApplicationParts.Add(part);
                                }
                            }

                            ////load all other referenced assemblies now
                            //foreach (var plugin in pluginFiles
                            //    .Where(x => !x.Name.Equals(mainPluginFile.Name, StringComparison.InvariantCultureIgnoreCase))
                            //    .Where(x => !IsAlreadyLoaded(x)))
                            //    PerformFileDeploy(plugin, options);

                            //init plugin type (only one plugin per assembly is allowed)
                            foreach (var t in pluginAssembly.GetTypes())
                            {
                                if (typeof(IPlugin).IsAssignableFrom(t))
                                {
                                    if (!t.IsInterface)
                                    {
                                        if (t.IsClass && !t.IsAbstract)
                                        {
                                            pluginDescriptor.PluginType = t;
                                            break;
                                        }
                                    }
                                }
                            }

                            referencedPlugins.Add(pluginDescriptor);
                        }
                        catch (ReflectionTypeLoadException ex)
                        {
                            //add a plugin name. this way we can easily identify a problematic plugin
                            var msg = $"Plugin '{pluginDescriptor.FriendlyName}'. ";
                            foreach (var e in ex.LoaderExceptions)
                            {
                                msg += e.Message + Environment.NewLine;
                            }

                            var fail = new Exception(msg, ex);
                            throw fail;
                        }
                        catch (Exception ex)
                        {
                            //add a plugin name. this way we can easily identify a problematic plugin
                            var msg = $"Plugin '{pluginDescriptor.FriendlyName}'. {ex.Message}";

                            var fail = new Exception(msg, ex);
                            throw fail;
                        }
                    }
                }
                catch (Exception ex)
                {
                    var msg = string.Empty;
                    for (var e = ex; e != null; e = e.InnerException)
                    {
                        msg += e.Message + Environment.NewLine;
                    }

                    var fail = new Exception(msg, ex);
                    throw fail;
                }

                ReferencedPlugins   = referencedPlugins;
                IncompatiblePlugins = incompatiblePlugins;
            }
        }