Explication détaillée du développement du moteur MVC et du système de plug-in dans ASP.NET

巴扎黑
Libérer: 2017-08-14 13:25:00
original
1213 Les gens l'ont consulté

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-dossier

Plugins/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>
Copier après la connexion
2. Développer une classe simple de gestion de plug-ins La fonction de cette classe est de copier les dll de chaque sous-répertoire de plugins vers ceux spécifiés. à l'étape 1 avant le dossier Application_Start., afin de rendre la démo aussi simple que 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, et il y a déjà une dll ef dans le répertoire bin du site, donc ce n'est pas nécessaire. Copiez ensuite la dll dans le plug-in 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);
   }

  }
 }
}
Copier après la connexion
3. Comment laisser le moteur View trouver notre vue ? La réponse est de réécrire RazorViewEngine. J'ai adopté l'approche de la convention sur la configuration (en supposant que l'espace de noms de notre projet de plug-in est Plugins.Apps.Sms, alors l'espace de noms du contrôleur par défaut est Plugins.Apps.Sms.Controllers. Après le plug-in. est généré Le dossier 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;
  }
 }
}
Copier après la connexion
puis dans Dans le Global.asax du site principal, le moteur Razor est désigné comme notre réécrit

4. Commencez à créer un plug-in , qui n'est pas trop similaire au projet MVC que nous construisons habituellement. La grande différence est que vous devez effectuer certains réglages 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 construction (clic droit sur le fichier)

3. Définissez les propriétés de construction dans le projet de référence, le principal Si le programme existe déjà, 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 y ajouter une fonction de comparaison de fichiers. n'y a rien de tel dans le répertoire bin, puis copiez-le dans le répertoire bin dynamique.

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal