AppDomain DoCallBack FileNotFound 异常
AppDomain DoCallBack FileNotFound exception
我将一个函数加载到新创建的 AppDomain 并且一切正常,但是如果我关闭程序然后重命名它并再次启动它,那么我将遇到 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");
}
}
}
抱歉,这是设计使然...
作为解决方法,您可以将该方法移动到外部 dll,这样您就可以重命名 .exe。
如果您希望您的申请只有一个文件,您可以使用 ILmerge
我猜 exe
s 有一些关于它们的硬编码名称。事实上,如果您检查 typeof(Program).AssemblyName
它是原始名称,这就是我希望我们得到错误的原因。
但是,您始终可以手动将 dll 加载到 AppDomain 中,然后在其中放置一些 class 来拦截对 "orginal" 名称的请求并将其替换为正确的程序集。
此代码执行此操作:
/// <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.
///
///
/// </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);
我将一个函数加载到新创建的 AppDomain 并且一切正常,但是如果我关闭程序然后重命名它并再次启动它,那么我将遇到 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");
}
}
}
抱歉,这是设计使然...
作为解决方法,您可以将该方法移动到外部 dll,这样您就可以重命名 .exe。
如果您希望您的申请只有一个文件,您可以使用 ILmerge
我猜 exe
s 有一些关于它们的硬编码名称。事实上,如果您检查 typeof(Program).AssemblyName
它是原始名称,这就是我希望我们得到错误的原因。
但是,您始终可以手动将 dll 加载到 AppDomain 中,然后在其中放置一些 class 来拦截对 "orginal" 名称的请求并将其替换为正确的程序集。
此代码执行此操作:
/// <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.
///
///
/// </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);