V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
unregister
V2EX  ›  程序员

C# .NET framework 4 程序集加载调试 bug

  •  
  •   unregister · 46 天前 · 1365 次点击
    这是一个创建于 46 天前的主题,其中的信息可能已经有所发展或是发生改变。
    static class Program
    {
    [STAThread]
    static void Main(){
    try{
    AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += new ResolveEventHandler(AssembliesHandler);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm())
    }catch(Exception ex){

    }
    }
    static Assembly AssembliesHandler(object source,ResolveEventArgs e){
    // 应用程序集会加载一些 resouce.dll ,例如
    //Microsoft.ApplicationBlocks.ExceptionManagement.resource.dll,Employee.resource.dll
    string assemblyName = new AssemblyName(e.Name).Name +".dll";
    // 但是指定路径下的路径只有 不带 resources 的 dll
    // Microsoft.ApplicationBlocks.ExceptionManagement.dll,Employee.dll
    string librariesPath = @"C:\Users\ddl\"
    return Assembly.LoadForm(assenblyName+librariesPath)
    }
    }
    就感觉挺奇怪的这些 resource.dll 是哪里来的,问了 GPT 说是 和什么多语言文化有关系,在 main 方法里面 Thread.currentInfo(en-us) 也没什么用
    后面在 AssembliesHandler 里面判断如果包含 resources 的话就 return null 跳过,
    if(assemblyName.contains(resources.dll) return null;
    但是这个会直接触发异常,导致程序一直在重试加载 Microsoft.ApplicationBlocks.ExceptionManagement.resource.dll,Employee.resource.dll 。就是 return null 会触发异常,应该换一个什么比较好?
    麻烦大神们帮忙看一下
    visual studio 2019 professional
    14 条回复    2024-09-21 10:00:03 +08:00
    unregister
        1
    unregister  
    OP
       46 天前
    klo424
        2
    klo424  
       46 天前
    很明显是资源文件,也是你程序运行的依赖项,你把依赖项去掉当然会报异常,就像你生产环境不安装.NET Framework 运行程序会报错是一个道理。所以,不可能去掉的。
    unregister
        3
    unregister  
    OP
       46 天前
    @klo424 AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += new ResolveEventHandler(AssembliesHandler); 这里是新加的,还有这个 AssembliesHandler 函数。 所以资源文件也是要放在那个指定目录下面的吗?但是目前好像没有这两个 dll
    ming159
        4
    ming159  
       46 天前
    1. try{...} catch(Exception ex){
    // 这里 把 ex.Message, ex.StackTrace 打印出来,或者断点,看一下详细信息
    }

    2. 我猜,大概率是这一行报错了(路径对应的文件没有造成的): Assembly.LoadForm(assenblyName+librariesPath)
    unregister
        5
    unregister  
    OP
       46 天前
    @ming159 对,这里是没有,所以我有判断,如果带有 resources.dll 的话就 return null ,不会进入到这一步,但是 return null 之后会一直函数会重试加载 resource.dll ,AssembliesHandler(object source,ResolveEventArgs e) 就是这个 source 一直是 resources.dll 而不是不带 resources.dll 比如 Microsoft.ApplicationBlocks.ExceptionManagement.dll,Employee.dll 这些正常的,就是会一直重试,我在试一下。
    unregister
        6
    unregister  
    OP
       46 天前
    如何有这些 resources.dll 或者忽略它们?
    unregister
        7
    unregister  
    OP
       46 天前
    chatgpt 的回答
    在你的代码中,AssembliesHandler 方法被用作 AssemblyResolve 事件的处理程序,这个事件在应用程序无法找到某个程序集时触发。这个处理程序的 source 参数是事件的触发源,而 ResolveEventArgs e 提供了有关未能加载的程序集的信息。

    为什么会请求 resources.dll 文件?
    本地化支持:如果你的应用程序或它所依赖的库使用了资源文件(如 .resx 文件)来支持多语言或区域性设置,.NET 运行时会尝试加载适当的资源程序集(<assemblyname>.resources.dll )以匹配当前的文化设置。

    默认行为:当应用程序运行时,.NET 会根据当前的文化设置自动查找和加载资源程序集。这是为了确保应用程序能够使用正确的语言和区域性资源。

    依赖关系:如果你的应用程序依赖的某些库使用了资源文件,那么这些库在加载时也可能触发对 resources.dll 文件的请求。

    如何处理这些请求?
    如果你不需要这些资源程序集,或者希望手动控制它们的加载,可以在 AssembliesHandler 中添加逻辑来忽略这些请求。你可以通过检查 ResolveEventArgs 的 Name 属性来确定请求的是否是资源程序集。例如:

    static Assembly AssembliesHandler(object source, ResolveEventArgs e)
    {
    // 检查请求的程序集是否为资源程序集
    if (e.Name.EndsWith(".resources"))
    {
    // 如果是资源程序集,可以选择返回 null 以忽略加载
    return null;
    }

    // 提取程序集名称
    string assemblyName = new AssemblyName(e.Name).Name + ".dll";
    string librariesPath = @"C:\Users\ddl\";

    // 构建完整路径并加载程序集
    string assemblyPath = System.IO.Path.Combine(librariesPath, assemblyName);
    if (System.IO.File.Exists(assemblyPath))
    {
    return Assembly.LoadFrom(assemblyPath);
    }

    // 如果找不到程序集,则返回 null
    return null;
    }
    在这个示例中,如果请求的是资源程序集(名称以 .resources 结尾),则直接返回 null ,表示不加载该程序集。这样可以避免不必要的资源程序集加载请求
    unregister
        8
    unregister  
    OP
       46 天前
    看了我还是不太懂,不知道它说的是不是对的。:)
    klo424
        9
    klo424  
       46 天前   ❤️ 1
    查了一下,第一个 dll 应该是 Enterprise Library 里面的文件,nuget 搜索 enterpriselibrary 能找到。
    https://learn.microsoft.com/en-us/previous-versions/msp-n-p/dn169621(v=pandp.10)
    ming159
        10
    ming159  
       46 天前
    "这个事件在应用程序无法找到某个程序集时触发。" https://learn.microsoft.com/zh-cn/dotnet/standard/assembly/resolve-loads

    你其他地方依赖了一个 dll,但是这个 dll 并没有.所以就调用到 AssembliesHandler 了. 这个逻辑关系理清了吧.
    ming159
        11
    ming159  
       46 天前
    所以,根源在于你依赖的 dll 是什么? 如果不用就删掉依赖项. 如果需要用这个 dll.就去找 然后引入项目依赖里
    kxg3030
        12
    kxg3030  
       46 天前
    应该就是楼上说的依赖的 dll
    unregister
        13
    unregister  
    OP
       45 天前
    @ming159
    @klo424
    @raviscioniemeche
    破案了,因为这个项目原来是.net 2.0 的,然后升级到了 .net framework 4.0 ,然后网上说 4.0 会去加载 带有 resouce 的 assemblies
    "Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. In earlier versions, the event was not raised for resource assemblies. If the operating system is localized, the handler might be called multiple times: once for each culture in the fallback chain."
    https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.assemblyresolve?view=net-8.0
    kxg3030
        14
    kxg3030  
       45 天前
    @unregister 学习了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5565 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 06:44 · PVG 14:44 · LAX 22:44 · JFK 01:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.