Cet article présente principalement en détail les informations pertinentes sur l'utilisation du moteur ASP.NET MVC pour développer des systèmes de plug-ins. Il a une certaine valeur de référence. Les amis intéressés peuvent s'y référer
1 , Préface
Le système de plug-ins dans mon esprit devrait être comme Nop (des plus géniaux comme Orchard, OSGI.NET). Chaque module de plug-in n'est pas simplement un tas de DLL qui implémentent un certain). interface métier. , puis utilisez la technologie de réflexion ou IOC pour l'appeler, mais c'est une petite application mvc complète. Je peux contrôler l'installation et la désactivation des plug-ins en arrière-plan. La structure des répertoires est la suivante :
<.> généré puis placé dans le dossier Plugins du répertoire racine du site Chaque plug-in possède un sous-dossierPlugins/Sms.AliYun. /
Plugins/ Sms.ManDao/
Je suis une personne paresseuse atteinte d'un trouble obsessionnel-compulsif et je ne veux pas copier la DLL générée fichier dans le répertoire bin.2. Problèmes à résoudre
1. Le moteur asp.net ne chargera que la dll dans le dossier "bin" par défaut, et le plug-in. fichier que nous voulons Il est dispersé dans différents sous-répertoires du répertoire Plugins. 2. Comment gérer lorsque le modèle est utilisé dans la vue ? Par défaut, RazorViewEngine utilise BuildManager pour compiler la vue dans un assembly dynamique, puis utilise Activator.CreateInstance pour instancier l'objet nouvellement compilé. Lors de l'utilisation de la DLL du plugin, l'AppDomain actuel ne sait pas comment résoudre une telle vue qui fait référence au modèle car elle. n'existe pas dans "bin" ou GAC. Pire encore, vous ne recevrez aucun message d'erreur vous indiquant pourquoi cela ne fonctionne pas ou quel est le problème. Au lieu de cela, il vous indiquera que le fichier est introuvable dans le répertoire View. 3. Un plug-in est en cours d'exécution sous le site. L'écrasement direct de la DLL du plug-in vous indiquera que la DLL actuelle est en cours d'utilisation et ne peut pas être écrasée. 4. Comment charger le fichier de vue s'il n'est pas placé dans le répertoire View du site.Three.Net 4.0 rend cela possible
Net4.0 a une nouvelle fonctionnalité qui est la possibilité d'exécuter du code avant l'initialisation de l'application (PreApplicationStartMethodAttribute), ce La fonctionnalité permet à l'application d'effectuer un certain travail avant Application_Star. Par exemple, nous pouvons savoir où la DLL de notre système de plug-in mvc est placée avant le démarrage de l'application, et effectuer un traitement de préchargement, etc. Concernant plusieurs nouvelles fonctionnalités du .net, il existe un blog écrit par Waiguo Keren pour les présenter, veuillez cliquer ici. , Concernant PreApplicationStartMethodAttribute, certains blogueurs ont déjà écrit à ce sujet, veuillez cliquer ici. Le module de démarrage d'Abp devrait également être implémenté en utilisant le principe de fonctionnalité de PreApplicationStartMethodAttribute. Je n'ai pas vu si c'était le cas.4. Solution
1. Modifiez le répertoire web.config du site principal afin qu'en plus de charger des fichiers dans le répertoire bin pendant l'exécution, vous puissiez également charger depuis autres répertoires<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="Plugins/temp/" /> </assemblyBinding> </runtime>
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.Compilation; using System.Web.Hosting; [assembly: PreApplicationStartMethod(typeof(Plugins.Core.PreApplicationInit), "Initialize")] namespace Plugins.Core { public class PreApplicationInit { static PreApplicationInit() { PluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins")); ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins/temp")); } /// <summary> /// 插件所在目录信息 /// </summary> private static readonly DirectoryInfo PluginFolder; /// <summary> /// 程序应行时指定的dll目录 /// </summary> private static readonly DirectoryInfo ShadowCopyFolder; public static void Initialize() { Directory.CreateDirectory(ShadowCopyFolder.FullName); //清空插件dll运行目录中的文件 foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories)) { f.Delete(); } foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories).Where(i=>i.Directory.Parent.Name== "plugins")) { File.Copy(plug.FullName, Path.Combine(ShadowCopyFolder.FullName, plug.Name), true); } foreach (var a in ShadowCopyFolder .GetFiles("*.dll", SearchOption.AllDirectories) .Select(x => AssemblyName.GetAssemblyName(x.FullName)) .Select(x => Assembly.Load(x.FullName))) { BuildManager.AddReferencedAssembly(a); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using System.Web.WebPages.Razor; namespace Plugins.Web { public class CustomerViewEngine : RazorViewEngine { /// <summary> /// 定义视图页所在地址。 /// </summary> private string[] _viewLocationFormats = new[] { "~/Views/Parts/{0}.cshtml", "~/Plugins/{pluginFolder}/Views/{1}/{0}.cshtml", "~/Plugins/{pluginFolder}/Views/Shared/{0}.cshtml", "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml", }; public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { string ns = controllerContext.Controller.GetType().Namespace; string controller = controllerContext.Controller.GetType().Name.Replace("Controller", ""); //说明是插件中的控制器,View目录需要单独处理 if (ns.ToLower().Contains("plugins")) { var pluginsFolder = ns.ToLower().Replace(".controllers", ""); ViewLocationFormats = ReplacePlaceholder(pluginsFolder); } return base.FindView(controllerContext, viewName, masterName, useCache); } /// <summary> /// 替换pluginFolder占位符 /// </summary> /// <param name="folderName"></param> private string[] ReplacePlaceholder(string folderName) { string[] tempArray = new string[_viewLocationFormats.Length]; if (_viewLocationFormats != null) { for (int i = 0; i < _viewLocationFormats.Length; i++) { tempArray[i] = _viewLocationFormats[i].Replace("{pluginFolder}", folderName); } } return tempArray; } } }
4. La structure des répertoires générée est la suivante :
5. le plug-in fonctionne Normalement, il n'y a pas de problème si le modèle est référencé dans la vue
À ce stade, la partie centrale d'un système de plug-in est terminée. peut continuer à s'étendre et à ajouter la découverte et l'installation de plug-ins, la fonction de désinstallation, ce sont un jeu d'enfant par rapport aux fonctions de base. Je publierai prochainement un article sur le système de plug-in basé sur le framework Abp. Si vous êtes intéressé, préparez un petit banc et achetez des graines de melon et des cacahuètes :)
.Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!