2016-06-07 85 views
3

我加載一個函數到新創建的AppDomain並且所有的工作都很好,但是如果我關閉程序然後重新命名並重新啓動它,那麼我會有FileNotFound異常。我只是不明白,那怎麼可能?AppDomain DoCallBack FileNotFound異常

錯誤(appDomainProject原來的程序名)

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. 

來源

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

只是可以肯定的:「關閉程序並重新命名「,你的意思是你正在重命名exe文件,不涉及重建,沒有在GAC或NGen等中註冊? – dlatikay

+0

yeap,只需重新命名而不需重建 – SLI

+0

即可重現。源代碼行21,DoCallBack失敗。有趣的是,看起來像這樣的一個重複的Q,被刪除從SO:http://stackoverflow.com/questions/30512932/execute-code-in-appdomain-in-renamed-executables – dlatikay

回答

2

我猜exe我們有一些類型的關於他們的硬編碼的名字。事實上,如果你檢查typeof(Program).AssemblyName這是原來的名字,這就是我期望我們得到錯誤的原因。

但是,您始終可以手動將DLL加載到AppDomain中,然後在那裏有一些類,用於攔截「原始」名稱的請求並將其替換爲正確的程序集。

此代碼是:

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

然後所有你需要做的是調用輔助方法創建的應用程序域後:

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

對不起,這是由設計...

作爲一種解決方法,你可以移動方法添加到外部DLL,因此您可以重命名.exe。

如果你希望你的應用程序只有一個文件,你可以使用ILmerge

+0

有沒有「設計」的來源? – FriendlyGuy

+0

@MackieChan沒有文檔,但如果你看看.net代碼,並且你想到什麼是Docallback。它需要存儲的exe的名稱做跨應用程序調用 – giammin

+0

嗯,我認爲發生的事情是它存儲程序集名稱,這是最初的exe名稱(可能是因爲.NET exes的存儲方式)。因此,當它加載組件時,它不能正確解決它。我不知道我是否會說這是通過設計,而是說它是.NET退出方式的一個副作用(如果我的理論是正確的)。 – FriendlyGuy

相關問題