Maison >développement back-end >Tutoriel C#.Net >Exemple détaillé de développement d'un système de plug-in utilisant le moteur MVC dans ASP.NET

Exemple détaillé de développement d'un système de plug-in utilisant le moteur MVC dans ASP.NET

黄舟
黄舟original
2017-05-21 11:23:532205parcourir

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 se référer à

1. Introduction

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 seulement un tas de dll qui implémente une certaine interface métier, puis appelée en utilisant la technologie de réflexion ou IOC, mais une petite application mvc complète, je peut contrôler l'installation et la désactivation du plug-in en arrière-plan. La structure des répertoires est la suivante :

est. généré et placé dans le répertoire racine du site. Dans le dossier Plugins, chaque plug-in possède un sous-dossier

Plugins/Sms.AliYun/

. Plugins/Sms.ManDao/

Je suis une personne paresseuse atteinte de trouble obsessionnel-compulsif et je ne veux pas copier le fichier dll généré 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. Que faire lorsque Modèle est utilisé dans Vue ? Par défaut, RazorViewEngine utilise BuildManager pour compiler la vue dans un assemblage dynamique, puis utilise Activator.CreateInstance pour instancier le objet nouvellement compilé, tandis que lors de l'utilisation de la dll du plugin, l'Ap actuel pDomain ne sait pas comment analyser cette vue qui référence un modèle car elle n'existe pas dans "bin" ou dans le 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 des fichiers. depuis autre Chargement du répertoire

 <runtime>
 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <probing privatePath="Plugins/temp/" />
 </assemblyBinding>
 </runtime>

2. Développer une classe de gestion de plug-ins simple La fonction de cette classe est de copier les dll de chaque sous-répertoire de plugins dans le dossier spécifié dans. étape 1 avant Application_Start Afin de rendre la démo la plus simple possible, les dll en double ne sont pas détectées (par exemple, l'assembly ef est référencé dans le plug-in, et le site principal le référence également. La dll de ef existe déjà. dans le répertoire bin du site, il n'est donc pas nécessaire d'ajouter à nouveau le plug-in (copiez la dll dans le répertoire d'assemblage dynamique défini ci-dessus)

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);
   }

  }
 }
}

3. Comment laisser le moteur View. trouver notre point de vue ? La réponse est de réécrire RazorViewEngine. J'ai adopté l'approche de la convention sur la configuration (en supposant que notre projet de plug-in espace de noms est Plugins.Apps.Sms, puis l'espace de noms par défaut contrôleur pour les plugins. .Apps.Sms.Controllers, le dossier après la génération du plug-in doit être /Plugins/Plugins.Apps.Sms/). En analysant le contrôleur actuel, vous pouvez connaître l'emplacement du répertoire View du plug-in actuel.

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;
  }
 }
}

Puis spécifiez le moteur Razor comme notre

réécrit dans le Global.asax du site principal

4. Commencez à créer un répertoire de plug-ins, qui n'est pas très différent du projet MVC que nous construisons habituellement. Il nécessite juste quelques paramètres lors de la publication.

. Le chemin de génération doit être écrit conformément à l'accord de l'article 3, sinon le fichier de vue ne sera pas trouvé

.web.config et The Le fichier .cshtml doit être copié dans le répertoire de build (clic droit sur le fichier)

3. Configurez la build dans le projet référencé Attribut , s'il existe déjà sous le programme principal, définissez "Copier dans le répertoire de sortie" sur Aucun, sinon une erreur se produira lors de la copie dans le répertoire bin dynamique. Vous pouvez modifier la classe à l'étape 2. et ajouter une comparaison de fichiers. Les fonctions qui ne se trouvent pas dans le répertoire bin sont copiées dans le répertoire bin dynamique.

4. La structure des répertoires générée est la suivante :

5. le plug-in Le contrôleur fonctionne normalement, et il n'y a aucun problème si le Modèle est référencé dans la vue

À ce stade, la partie centrale d'un système de plug-ins est terminé et vous pouvez continuer à développer et ajouter des fonctions de découverte, d'installation et de désinstallation de plug-ins. Ce sont toutes un jeu d'enfant par rapport aux fonctions de base. Je publierai à l'avenir 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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn