我正在使用一个自定义框架,该框架使用反射对从数据库获取的完全限定类型名称执行GetTypeByName(string fullName)
,以创建所述类型的实例并将其添加到页面中,从而生成在一个标准的模块化的东西。
GetTypeByName
是我的一个实用函数,它只是遍历Thread.GetDomain().GetAssemblies()
,然后执行assembly.GetType(fullName)
来查找相关类型。显然,这个结果会被缓存以供将来参考和使用。
但是,我遇到了一些问题,如果web.config得到更新(并且在某些更可怕的实例中,如果应用程序池被回收)那么它将失去对某些程序集的所有知识,导致无法呈现模块类型的实例。调试显示缺少的程序集在当前线程程序集列表中确实不存在。
为了解决这个问题,我添加了第二个检查,它有点脏,但通过/ bin /目录的DLL进行递归并检查程序集列表中是否存在每个检查。如果没有,则使用Assembly.Load加载它并通过'Solving the Assembly Load Context Problem'修复上下文问题。
这样可行,只是看起来(并且我知道这不可能)一些项目仍然可以访问缺少的程序集,例如我的实际Web项目而不是框架本身 - 然后它会抱怨已经添加了重复的引用!
有没有人听说过这样的事情,或者有任何想法为什么程序集在配置更改时根本不存在?没有一个解决方案,最优雅的解决方法是让bin中的所有程序集重新加载?它需要全部在一个“点击”,以便网站访问者除了一个小延迟之外没有看到任何差异,因此app_offline.htm文件是不可能的。以编程方式重命名bin中的DLL然后将其命名回来确实有效,但需要“修改”IIS用户帐户的权限,这是疯了。
感谢社区可以收集的任何指示!
答案 0 :(得分:2)
你很明显知道,there are many situations where the current appdomain is unloaded and reloaded。每次重新加载后,将卸载所有程序集,整个应用程序将“从头开始”运行。
默认情况下,按需加载程序集。通常情况是JIT偶然遇到一些引用。因此,appdomain重新加载将清除appdomain中的程序集,并且只有在JIT加载它们时才会再次出现。
作为解决方案,我希望使用静态Type.GetType()
方法并提供程序集限定名称(例如包含程序集名称的类型名称)。这与框架在加载配置文件中指定的类型时使用的相同,它将确保按需搜索和加载所需的程序集,而不使用任何技巧。请参阅上述方法的备注部分(名称上方的方法名称是链接)。
这将需要更新数据库以保存程序集限定名称,而不是“仅”完全限定类型名称。但是,它还确保当两个程序集提供具有相同名称的不同类型时不会遇到名称冲突,所以无论如何我认为这是一个好主意。
答案 1 :(得分:2)
通常,您应该避免依赖于当前在appdomain中加载的程序集,因为这是动态发生的。相反,只需调用System.Web.Compilation.BuildManager.GetType()而不是Type.GetType()或Assembly.GetType()。这应该为您做正确的事情,而不受appdomain周期的影响。
答案 2 :(得分:1)
我以前从未听说过这个问题。
我不确定这是否可行,因为我在研究ODAC依赖项的变通方法时最近才读到它,但指定程序集的探测路径可能会解决您的问题。
请参阅:http://msdn.microsoft.com/en-us/library/823z9h8w(VS.80).aspx
样品:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
答案 3 :(得分:1)
我有一个类似的问题,当我更新2-5个文件,ether web.config,ether其他文件,而asp.net需要重新创建正在运行的文件,然后有时候没有找到存在的某些类/函数DLL文件,我的系统无法正常工作 - 抛出像你这样的错误。
我的解决方案是将app_offline.htm放在root上,进行更新,然后重命名/删除app_offline.htm,我的系统工作正常。
我确信这与缓存的编译文件有关,但我没有得到满足的搜索结果。
[什么是让bin中的所有程序集重新加载的最优雅的解决方法]
现在最优雅的解决方法是调用 HttpRuntime.UnloadAppDomain 并实际让您的应用程序停止并重新启动。
http://msdn.microsoft.com/en-us/library/system.web.httpruntime.unloadappdomain(VS.80).aspx
我不知道这是否能解决您的问题,您需要进行测试。
可能在Global.asax上制作类似的东西
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError().GetBaseException();
...if ex is your error, and you get more than 2 ...
{
HttpRuntime.UnloadAppDomain();
}
}
答案 4 :(得分:0)
我会尝试创建一些基本类,从哪个程序集开始,这对你来说很有意思而没有反映Application Start以确保它被加载。 例如。
var temp = new BaseModuleBuilder();
这看起来并不聪明,但它非常简洁,asp.net应该为你做一切。如果您的列表过于动态,则可能类似于
var temp = Activator.CreateInstance(Type.GetType("BaseModuleBuilder, Modules.dll"));
确保在使用dynacmically加载的类时始终指定DLL。