GetEntryAssembly pour les applications Web

Assembly.GetEntryAssembly () ne fonctionne pas pour les applications Web.

Mais … j’ai vraiment besoin de quelque chose comme ça. Je travaille avec du code profondément nested utilisé dans les applications Web et non Web.

Ma solution actuelle consiste à parcourir le StackTrace pour trouver le premier assemblage appelé.

///  /// Version of 'GetEntryAssembly' that works with web applications ///  /// The entry assembly, or the first called assembly in a web application public static Assembly GetEntyAssembly() { // get the entry assembly var result = Assembly.GetEntryAssembly(); // if none (ex: web application) if (result == null) { // current method MethodBase methodCurrent = null; // number of frames to skip int framestoSkip = 1; // loop until we cannot got further in the stacktrace do { // get the stack frame, skipping the given number of frames StackFrame stackFrame = new StackFrame(framestoSkip); // get the method methodCurrent = stackFrame.GetMethod(); // if found if ((methodCurrent != null) // and if that method is not excluded from the stack trace && (methodCurrent.GetAtsortingbute(false) == null)) { // get its type var typeCurrent = methodCurrent.DeclaringType; // if valid if (typeCurrent != typeof (RuntimeMethodHandle)) { // get its assembly var assembly = typeCurrent.Assembly; // if valid if (!assembly.GlobalAssemblyCache && !assembly.IsDynamic && (assembly.GetAtsortingbute() == null)) { // then we found a valid assembly, get it as a candidate result = assembly; } } } // increase number of frames to skip framestoSkip++; } // while we have a working method while (methodCurrent != null); } return result; } 

Pour que l’assemblage soit ce que nous voulons, nous avons 3 conditions:

  • l’assemblée n’est pas dans le GAC
  • l’assemblage n’est pas dynamic
  • l’assembly n’est pas généré (pour éviter les fichiers asp.net temporaires

Le dernier problème que je rencontre est lorsque la page de base est définie dans un assembly distinct. (J’utilise ASP.Net MVC, mais ce sera la même chose avec ASP.Net). Dans ce cas particulier, c’est cet assemblage séparé qui est retourné, pas celui qui contient la page.

Ce que je cherche maintenant c’est:

1) Mes conditions de validation d’assemblage sont-elles suffisantes? (J’ai peut-être oublié des cas)

2) Existe-t-il un moyen, à partir d’un assemblage généré par le code dans le dossier temporaire ASP.Net, d’obtenir des informations sur le projet contenant cette page / vue? (Je ne pense pas, mais qui sait …)

Cela semble être un moyen simple et fiable d’obtenir la “saisie” ou l’assemblage principal d’une application Web.

Si vous placez des contrôleurs dans un projet distinct, vous pouvez constater que la classe de base d’ApplicationInstance n’est pas dans le même assemblage que votre projet MVC contenant les vues – mais cette configuration semble assez rare (je l’ai mentionnée parce que j’ai essayé la configuration à un moment donné, et il y a quelques temps quelques blogs ont soutenu l’idée).

  static private Assembly GetWebEntryAssembly() { if (System.Web.HttpContext.Current == null || System.Web.HttpContext.Current.ApplicationInstance == null) { return null; } var type = System.Web.HttpContext.Current.ApplicationInstance.GetType(); while (type != null && type.Namespace == "ASP") { type = type.BaseType; } return type == null ? null : type.Assembly; } 

Dans mon cas, je devais obtenir le “assembly assembly” pour une application Web avant que System.Web.HttpContext.Current.ApplicationInstance soit initialisé. De plus, mon code devait fonctionner pour une variété de types d’applications (services de fenêtres, applications de bureau, etc.) et je n’aime pas polluer mon code commun avec des problèmes Web.

J’ai créé un atsortingbut d’assemblage personnalisé, qui peut être déclaré dans le fichier AssembyInfo.cs d’un assembly que vous souhaitez désigner comme assembly de point d’entrée. Ensuite, il vous suffit d’appeler la méthode GetEntryAssembly statique de l’atsortingbut pour obtenir l’assembly d’entrée. Si Assembly.GetEntryAssembly renvoie non-null, cela est utilisé, sinon il recherche dans les assemblys chargés pour celui avec l’atsortingbut personnalisé. Le résultat est mis en cache dans un Lazy .

 using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace EntryAssemblyAtsortingbuteDemo { ///  /// For certain types of apps, such as web apps,  /// returns null. With the , we can designate /// an assembly as the entry assembly by creating an instance of this atsortingbute, /// typically in the AssemblyInfo.cs file. ///  /// [assembly: EntryAssembly] ///  ///  [AtsortingbuteUsage(AtsortingbuteTargets.Assembly)] public sealed class EntryAssemblyAtsortingbute : Atsortingbute { ///  /// Lazily find the entry assembly. ///  private static readonly Lazy EntryAssemblyLazy = new Lazy(GetEntryAssemblyLazily); ///  /// Gets the entry assembly. ///  /// The entry assembly. public static Assembly GetEntryAssembly() { return EntryAssemblyLazy.Value; } ///  /// Invoked lazily to find the entry assembly. We want to cache this value as it may /// be expensive to find. ///  /// The entry assembly. private static Assembly GetEntryAssemblyLazily() { return Assembly.GetEntryAssembly() ?? FindEntryAssemblyInCurrentAppDomain(); } ///  /// Finds the entry assembly in the current app domain. ///  /// The entry assembly. private static Assembly FindEntryAssemblyInCurrentAppDomain() { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var entryAssemblies = new List(); foreach (var assembly in assemblies) { // Note the usage of LINQ SingleOrDefault. The EntryAssemblyAtsortingbute's AtsortingnuteUsage // only allows it to occur once per assembly; declaring it more than once results in // a comstackr error. var atsortingbute = assembly.GetCustomAtsortingbutes().OfType().SingleOrDefault(); if (atsortingbute != null) { entryAssemblies.Add(assembly); } } // Note that we use LINQ Single to ensure we found one and only one assembly with the // EntryAssemblyAtsortingbute. The EntryAssemblyAtsortingbute should only be put on one assembly // per application. return entryAssemblies.Single(); } } } 

Pour répondre à ma propre question (certaines personnes ici sont très sensibles au taux accepté) => je n’ai pas trouvé de meilleur moyen que le code indiqué dans la question.

Cela signifie que la solution n’est pas parfaite mais que cela fonctionne aussi longtemps que votre page de base est définie dans l’assemblage frontal.

L’algorithme proposé dans la question a bien fonctionné pour moi, alors que la méthode utilisant System.Web.HttpContext.Current.ApplicationInstance n’a pas fonctionné. Je pense que mon problème est que l’ancienne application ASP.Net pour laquelle j’ai besoin d’une solution ne dispose pas d’un gestionnaire global.asax.

Cette solution plus courte a également fonctionné pour moi et je pense que cela fonctionnera généralement à condition que le gestionnaire de page soit défini dans l’assemblage frontal:

  private static Assembly GetMyEntryAssembly() { if ((System.Web.HttpContext.Current == null) || (System.Web.HttpContext.Current.Handler == null)) return Assembly.GetEntryAssembly(); // Not a web application return System.Web.HttpContext.Current.Handler.GetType().BaseType.Assembly; } 

Mon application est une application de formulaires Web ASP.Net 4.x. Pour ce type d’application, HttpContext.Current.Handler est le module de code contenant le point d’entrée du gestionnaire de requêtes en cours. Handler.GetType (). Assembly est un assembly ASP.Net temporaire, mais Handler.GetType (). BaseType.Assembly est le véritable “assembly de saisie” de mon application. Je suis curieux de savoir si le même fonctionne pour divers autres types d’applications ASP.Net.

La seule façon dont j’ai pu obtenir que cela fonctionne de manière cohérente pour les applications Web (au moins dans .NET 4.5.1) était de faire le Assembly.GetExecutingAssembly () dans le projet d’application Web lui-même.

Si vous essayez de créer un projet d’utilitaires avec des méthodes statiques et d’y effectuer l’appel, vous obtiendrez plutôt les informations d’assemblage de cet assembly – à la fois pour GetExecutingAssembly () et GetCallingAssembly ().

GetExecutingAssembly () est une méthode statique qui renvoie une instance du type Assembly. La méthode n’existe pas sur une instance de la classe Assembly elle-même.

J’ai donc créé une classe qui accepte le type d’assemblage dans le constructeur et créé une instance de cette classe en transmettant les résultats de Assembly.GetExecutingAssembly ().

  public class WebAssemblyInfo { Assembly assy; public WebAssemblyInfo(Assembly assy) { this.assy = assy; } public ssortingng Description { get { return GetWebAssemblyAtsortingbute(a => a.Description); } } // I'm using someone else's idea below, but I can't remember who it was private ssortingng GetWebAssemblyAtsortingbute(Func value) where T : Atsortingbute { T atsortingbute = null; atsortingbute = (T)Atsortingbute.GetCustomAtsortingbute(this.assy, typeof(T)); if (atsortingbute != null) return value.Invoke(atsortingbute); else return ssortingng.Empty; } } } 

Et pour l’utiliser

 ssortingng Description = new WebAssemblyInfo(Assembly.GetExecutingAssembly()).Description;