2016-06-07 1 views
3

Je charge une fonction nouvelle créée AppDomain et tout le travail va bien, mais si je ferme le programme, puis le renommer et le lancer à nouveau, que je ne ferai exception FileNotFound. Je ne comprends pas, comment cela peut-il être?AppDomain DoCallBack FileNotFound exception

Erreur (appDomainProject nom du programme original)

System.IO.FileNotFoundException: Could not load file or assembly "appDomainProject, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null" or one of its dependencies. Can not find the file specified. 

Source

using System; 
using System.IO; 
using System.Windows.Forms; 

namespace appDomainProject 
{ 
    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 

      try 
      { 
       AppDomain authDomain = AppDomain.CreateDomain(DateTime.Now.ToString()); 
       authDomain.DoCallBack(load_Auth); 
      } 
      catch (Exception ex) 
      { 
       File.WriteAllText("e.txt", ex.ToString());; 
       MessageBox.Show(ex.ToString()); 
      } 
     } 

     private static void load_Auth() 
     { 
      MessageBox.Show("AUTH"); 
     } 
    } 
} 
+0

: « fermer le programme et renommez-le ", vous voulez dire que vous renommez le fichier exe, aucune reconstruction impliquée, rien enregistré dans GAC ou NGen etc.? – dlatikay

+0

Oui, il suffit de renommer sans reconstruire – SLI

+0

peut reproduire. Echoue dans la ligne source 21, 'DoCallBack'. Fait intéressant, un Q qui ressemble à un double de celui-ci, a été supprimée de SO: http://stackoverflow.com/questions/30512932/execute-code-in-appdomain-in-renamed-executables – dlatikay

Répondre

2

Je devine que exe s ont une sorte de noms hardcoded à leur sujet. En fait, si vous cochez typeof(Program).AssemblyName, c'est le nom d'origine, c'est pourquoi je pense que nous aurons l'erreur.

Cependant, vous pouvez toujours charger manuellement la DLL dans l'AppDomain et y avoir une classe qui intercepte la requête pour le nom "orginal" et le remplace par l'assembly correct.

Ce code fait que:

/// <summary> 
/// It seems that if you rename an exe and then try to load said 
/// assembly into a separate app-domain, .NET looks for the original 
/// name. This class loads the current assembly into the app 
/// domain manually and then detects request for the original name 
/// and redirects it to the correct assembly. 
/// 
/// http://stackoverflow.com/questions/37685180 
/// </summary> 
public class RenamedExeFixer : MarshalByRefObject 
{ 
    /// <summary> Load the assembly that this type is in into the app-domain. </summary> 
    public static void LoadOriginatingAssemblyIntoDomain(AppDomain appDomain) 
    { 
    var pathToSelf = new Uri(typeof(RenamedExeFixer).Assembly.CodeBase).LocalPath; 
    appDomain.Load(File.ReadAllBytes(pathToSelf)); 

    // create an instance of the class inside of the domain 
    // so that it can hook into the AssemblyResolve event 
    appDomain.CreateInstanceFrom(pathToSelf, typeof(RenamedExeFixer).FullName); 
    } 

    private readonly string _myAssemblyName; 

    public RenamedExeFixer() 
    { 
    // cached for efficiency (probably not needed) 
    _myAssemblyName = typeof(RenamedExeFixer).Assembly.FullName; 

    AppDomain.CurrentDomain.AssemblyResolve += HandleAssemblyResolve; 
    } 

    private Assembly HandleAssemblyResolve(object sender, ResolveEventArgs args) 
    { 
    if (args.Name == _myAssemblyName) 
    { 
     return typeof(RenamedExeFixer).Assembly; 
    } 

    return null; 
    } 
} 

Et tout ce que vous devez faire est d'appeler la méthode d'aide après avoir créé votre application domaine: juste pour être sûr

AppDomain authDomain = AppDomain.CreateDomain(DateTime.Now.ToString()); 
RenamedExeFixer.LoadOriginatingAssemblyIntoDomain(authDomain); 
authDomain.DoCallBack(load_Auth); 
0

Désolé, c'est par la conception ...

comme solution de contournement, vous pouvez déplacer le méthode à une DLL externe, de sorte que vous pouvez renommer le fichier .exe.

Si vous voulez que votre demande soit un seul fichier que vous pouvez utiliser ILmerge

+0

Existe-t-il une source pour "by design"? – FriendlyGuy

+0

@MackieChan aucune documentation, mais si vous regardez le code. Net et si vous pensez à quoi est Docallback pour.Il faut stocker le nom de l'exe pour faire l'application croisée appel – giammin

+0

Eh bien, je pense que ce qui se passe est qu'il stocke le nom de l'assembly, qui est le nom d'origine exe (probablement à cause de la façon dont les .NET exes sont stockés). Ainsi, quand il va charger l'ensemble, il ne peut pas le résoudre correctement. Je ne sais pas si je dirais que c'est par conception, mais plutôt que c'est un effet secondaire de la façon dont .NET fonctionne (si ma théorie est correcte). – FriendlyGuy