Web.config 更改后程序集不可用

发布于 2024-08-27 18:36:58 字数 1000 浏览 7 评论 0原文

我正在使用一个自定义框架,该框架使用反射对从数据库获取的完全限定类型名称执行 GetTypeByName(string fullName) ,以创建所述类型的实例并将其添加到页面,产生标准的模块化的东西。

GetTypeByName 是我的一个实用函数,它只需迭代 Thread.GetDomain().GetAssemblies(),然后执行 assemble.GetType(fullName) > 查找相关类型。显然,这个结果会被缓存以供将来参考和提高速度。

但是,我遇到了一些问题,如果 web.config 得到更新(并且在一些更可怕的情况下,如果应用程序池被回收),那么它将丢失某些程序集的所有知识,导致无法渲染该程序集的实例模块类型。调试显示丢失的程序集实际上并不存在于当前线程程序集列表中。

为了解决这个问题,我添加了第二个检查,该检查有点脏,但会通过 /bin/ 目录的 DLL 进行递归,并检查每个DLL 是否存在于程序集列表中。如果没有,它会使用 Assembly.Load 加载它并通过 “解决程序集加载上下文问题”

这可行,只是看起来(而且我知道这不应该是可能的)某些项目仍然可以访问丢失的程序集,例如我的实际 Web 项目而不是框架本身 - 然后它抱怨重复的引用已添加!

有没有人听说过这样的事情,或者知道为什么程序集会在配置更改时简单地消失?如果没有解决方案,那么让垃圾箱中的所有程序集重新加载的最优雅的解决方法是什么?它需要全部集中在一次“点击”中,以便网站访问者除了一点点延迟之外看不到任何差异,因此 app_offline.htm 文件是不可能的。以编程方式重命名 bin 中的 DLL,然后将其重新命名确实可行,但需要 IIS 用户帐户的“修改”权限,这很疯狂。

感谢社区可以收集的任何指示!

I'm using a custom framework that uses reflection to do a GetTypeByName(string fullName) on the fully-qualified type name that it gets from the database, to create an instance of said type and add it to the page, resulting in a standard modular kind of thing.

GetTypeByName is a utility function of mine that simply iterates through Thread.GetDomain().GetAssemblies(), then performs an assembly.GetType(fullName) to find the relevant type. Obviously this result gets cached for future reference and speed.

However, I'm experiencing some issues whereby if the web.config gets updated (and, in some scarier instances if the application pool gets recycled) then it will lose all knowledge of certain assemblies, resulting in the inability to render an instance of the module type. Debugging shows that the missing assembly literally does not exist in the current thread assemblies list.

To get around this I added a second check which is a bit dirty but recurses through the /bin/ directory's DLLs and checks that each one exists in the assemblies list. If it doesn't, it loads it using Assembly.Load and fixing the context issue thanks to 'Solving the Assembly Load Context Problem'.

This would work, only it seems that (and I'm aware this shouldn't be possible) some projects still have access to the missing assembly, for example my actual web project rather than the framework itself - and it then complains that duplicate references have been added!

Has anyone ever heard of anything like this, or have any ideas why an assembly would simply drop out of existence on a config change? Short of a solution, what is the most elegant workaround to get all the assemblies in the bin to reload? It needs to be all in one "hit" so that the site visitors don't see any difference other than a small delay, so an app_offline.htm file is out of the question. Programatically renaming a DLL in the bin and then naming it back does work, but requires "modify" permissions for the IIS user account, which is insane.

Thanks for any pointers the community can gather!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

随心而道 2024-09-03 18:36:58

通常,您应该避免依赖应用程序域中当前加载的程序集,因为这种情况是动态发生的。相反,只需调用 System.Web.Compilation.BuildManager.GetType() 而不是 Type.GetType() 或 Assembly.GetType()。这应该只是为您做正确的事情,并且不受应用程序域周期的影响。

Generally, you should avoid relying on what assemblies are currently loaded in an appdomain, as that happens dynamically. Instead, simply call System.Web.Compilation.BuildManager.GetType() instead of Type.GetType() or Assembly.GetType(). This should just do the right thing for you, and not be affected by appdomain cycles.

骄傲 2024-09-03 18:36:58

您显然知道,有很多情况会导致当前appdomain被卸载并重新加载。每次重新加载后,所有程序集都会被卸载,整个应用程序“从头开始”运行。

默认情况下,程序集按需加载。通常,当 JIT 偶然发现某些引用时就会出现这种情况。因此,应用程序域重新加载将清除应用程序域中的程序集,并且它们只会在稍后 JIT 加载它们时再次出现。

作为解决方案,我倾向于使用静态 Type.GetType() 方法并提供程序集限定名称(例如包含程序集名称的类型名称)。这与框架在加载配置文件中指定的类型时使用的内容相同,它将确保按需搜索和加载所需的程序集,而不使用任何技巧。参见上面方法的备注部分(名称上面的方法名称是链接)。

这将需要更新数据库以保存程序集限定名称,而不是“仅”完全限定类型名称。但是,它还可以确保当两个程序集提供具有相同名称的不同类型时不会遇到名称冲突,因此我认为无论如何这是一个好主意。

As you obviously know, there are many situations where the current appdomain is unloaded and reloaded. After each reload, all assemblies are unloaded and the whole application starts running "from scratch".

Assemblies are by default loaded on demand. Usually that is the case when the JIT stumbles across some reference. In consequence, a appdomain reload will clear out the assemblies in the appdomain and they will only appear again later on when the JIT loads them.

As solution I'd rever to using the static Type.GetType() method and supply an assembly qualified name (e.g. a type name with the assembly name included). That's the same thing the framework uses when loading types specified in the config file, and it will make sure that the required assembly is searched and loaded on demand without using any tricks. See the remarks section of the method above (the method name above name is a link).

This will require updates to your database to hold assembly qualified names instead of "only" fully qualified type names. However, it also makes sure that you don't run into name collisions when two assemblies provide different type with the same name, so this is a good idea anyways I think.

静若繁花 2024-09-03 18:36:58

我以前从未听说过这个问题。

我不确定这是否有效,因为我最近在研究 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>

I've never heard of this problem before.

I'm not sure if this will work, as I only recently read about it while researching workarounds to ODAC dependencies, but specifying the probing path for assemblies may fix your issue.

see: http://msdn.microsoft.com/en-us/library/823z9h8w(VS.80).aspx

sample:

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="bin;bin2\subbin;bin3"/>
      </assemblyBinding>
   </runtime>
</configuration>
绳情 2024-09-03 18:36:58

我有一个类似的问题,当我更新2-5个文件,ether web.config,ether其他文件,并且asp.net需要重新创建运行文件时,有时找不到dll文件上存在的一些类/函数,我的系统无法正常工作 - 抛出像你一样的错误。

我的解决方案是将 app_offline.htm 放在根目录上,进行更新,然后重命名/删除 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();
   }
}

I have a similar problem, when I update 2-5 files, ether web.config, ether other files, and asp.net needs to recreate the running files, then some times did not find some classes/function that exist on dll files, and my system is not working - throw errors like yours.

My solution to that is that I place the app_offline.htm on the root, make my updates, then rename/remove the app_offline.htm and my system works fine.

I am sure that have something to do with the cached compiled files, but I did not have deaply search whats exactly cause that.

[what is the most elegant workaround to get all the assemblies in the bin to reload]

Now what is the most elegant workaround on this is to call the HttpRuntime.UnloadAppDomain and actually make your application to stop and starts again.

http://msdn.microsoft.com/en-us/library/system.web.httpruntime.unloadappdomain(VS.80).aspx

I do not know if this solve your issue, you need to make tests.

probably on Global.asax make something like that

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();
   }
}
微暖i 2024-09-03 18:36:58

我会尝试从程序集中创建一些基本类,这对您来说很有趣,而无需反思应用程序启动以确保它已加载。
例如,

var temp = new BaseModuleBuilder();

这看起来并不聪明,但它非常简单,asp.net 应该为你做一切。如果您的列表过于动态,则可能类似于“

var temp = Activator.CreateInstance(Type.GetType("BaseModuleBuilder, Modules.dll"));

在使用动态加载的类时确保始终指定 DLL”。

I would try to create some basic class from which assembly, which is interesting for you without reflection on Application Start to make sure it is loaded.
E.g.

var temp = new BaseModuleBuilder();

This do not look smart, but it is very straitforward and asp.net should do everything for you. In case when your list is too dynamic, it could be something like

var temp = Activator.CreateInstance(Type.GetType("BaseModuleBuilder, Modules.dll"));

Make sure to always specify DLL when working with dynacmically loaded classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文