2010-08-04 6 views
1

Donc, mes scénarios sont un peu drôles mais il y a une raison à cela.Erreur d'analyseur: Impossible de charger le type «x» depuis appdomain depuis le répertoire virtuel dans IIS7

J'ai une application Web parent, appelée Parent, et une deuxième application Web appelée Child. Child est un répertoire virtuel dans IIS7 sous Parent qui est une application dans IIS. Child n'est pas un répertoire enfant du parent dans le système de fichiers, uniquement dans IIS en tant que répertoire virtuel. Lors du chargement de l'application (Application_Start dans global.asax) dans l'application web parente, je lui dis de charger les dlls web enfants à partir du dossier bin childs en utilisant Assembly.LoadFrom() le chargeant dans le domaine de l'application de Parent. Puis, quand j'essaie de visiter /Child/Default.aspx je reçois une erreur disant:

Parser Erreur

Parser Message d'erreur: Impossible de charger le type 'Child._Default'.

Maintenant, le CHILD.DLL (la dll web contenant du code Childs derrière etc) est dans le domaine de l'application de l'application mère et je peux refléter avec succès et ses membres à partir du code derrière la page Parent Default.aspx. En outre sur l'enfant/Default.aspx si je change le Inherits = "Child._Default" à Inherits = "System.Web.UI.Page" et puis dans <%%> tags sur la page énumérer les DLLs dans le domaine de l'application, je peux voir Child.dll et refléter ses membres et invoquer des fonctions. Une chose qui fonctionne change CodeBehind en CodeFile dans la directive page. Ensuite, la page analyse correctement. Toutefois, cela ne fonctionne que lorsque les sites Web sont sous forme non compilée et non publiée.

Répondre

2

Qu'est-ce qui se passe, c'est que l'appdomain ne regarde pas dans sa liste d'assemblage quand il essaie de résoudre l'assemblage "Enfant" pour la page dans le projet enfant.

Ce que vous devez faire est d'utiliser le gestionnaire d'événements AssemblyResolve dans AppDomain. Vous pouvez le faire comme ceci:

Tout d'abord, nous créons et classe AssemblyLoader:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Reflection; 
using System.IO; 

namespace Parent 
{ 
    internal class AssemblyLoader 
    { 
     private static List<AssemblyInformation> virtualDirectoryAssemblies = new List<AssemblyInformation>(); 
     private static readonly string virtualDirectoryBinFolderFormatString = "~/{0}/bin/"; 
     private static readonly string[] pathSplitParams = new string[1] { "\\" }; 
     private static readonly string[] assemblyNameSplitParams = new string[1] { "," }; 

     internal static Assembly AssemblyResolve(object sender, ResolveEventArgs e) 
     { 
      var name = e.Name.Split(assemblyNameSplitParams, StringSplitOptions.RemoveEmptyEntries).First(); 
      if (!virtualDirectoryAssemblies.Exists(a => a.Name.Equals(name))) 
       return null; 

      return Assembly.LoadFrom(virtualDirectoryAssemblies.Single(a => a.Name.Equals(name)).Path); 
     } 

     internal static void LoadVirtualDirectories(List<string> virtualDirectories) 
     { 
      foreach (var v in virtualDirectories) 
      { 
       var path = HttpContext.Current.Server.MapPath(string.Format(virtualDirectoryBinFolderFormatString, v)); 
       AppDomain.CurrentDomain.AppendPrivatePath(path); 
       AppDomain.CurrentDomain.SetShadowCopyPath(path); 

       var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).ToList(); 
       foreach (var a in assemblies) 
       { 
        var name = a.Split(pathSplitParams, StringSplitOptions.RemoveEmptyEntries).Last().Replace(".dll", string.Empty); 
        if(!virtualDirectoryAssemblies.Exists(i => i.Name.Equals(name))) 
        { 
         virtualDirectoryAssemblies.Add(new AssemblyInformation 
         { 
          Name = name, 
          Path = a 
         }); 
        } 
       } 
      } 
     } 

     class AssemblyInformation 
     { 
      public string Name { get;set; } 
      public string Path { get; set; } 
     } 
    } 
} 

Dans le fichier web.config pour le projet parent j'ai ajouté ce (si vous avez des répertoires virtuels, l'idée est de une virgule liste deliminated):

<appSettings> 
    <add key="VirtualDirectories" value="Child"/> 
</appSettings> 

Dans le web.config du projet enfant, vous ajoutez cette référence à l'ensemble des enfants ensemble:

<system.web> 
    <compilation> 
     <assemblies> 
      <add assembly="Child, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </assemblies> 
    </compilation> 
</system.web> 

Il peut aussi ressembler à ceci:

<system.web> 
    <compilation> 
     <assemblies> 
      <add assembly="Child"/> 
     </assemblies> 
    </compilation> 
</system.web> 

Maintenant, last but not least, nous avons mis cela dans le Global.asax:

protected void Application_Start(object sender, EventArgs e) 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += AssemblyLoader.AssemblyResolve; 

     var virtualDirectories = 
      ConfigurationManager.AppSettings.Get("VirtualDirectories").Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList(); 

     AssemblyLoader.LoadVirtualDirectories(virtualDirectories); 
    } 

Et nous sommes fait ...: P

+0

donc la résolution d'assemblage par défaut ne va pas lisse, je me demande pourquoi ... –

Questions connexes