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

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

  •  
  •   unregister · 6 小时 24 分钟前 · 608 次点击
    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
    12 条回复    2024-09-20 11:04:00 +08:00
    unregister
        1
    unregister  
    OP
       6 小时 19 分钟前
    klo424
        2
    klo424  
       6 小时 11 分钟前
    很明显是资源文件,也是你程序运行的依赖项,你把依赖项去掉当然会报异常,就像你生产环境不安装.NET Framework 运行程序会报错是一个道理。所以,不可能去掉的。
    unregister
        3
    unregister  
    OP
       6 小时 7 分钟前
    @klo424 AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += new ResolveEventHandler(AssembliesHandler); 这里是新加的,还有这个 AssembliesHandler 函数。 所以资源文件也是要放在那个指定目录下面的吗?但是目前好像没有这两个 dll
    ming159
        4
    ming159  
       6 小时 7 分钟前
    1. try{...} catch(Exception ex){
    // 这里 把 ex.Message, ex.StackTrace 打印出来,或者断点,看一下详细信息
    }

    2. 我猜,大概率是这一行报错了(路径对应的文件没有造成的): Assembly.LoadForm(assenblyName+librariesPath)
    unregister
        5
    unregister  
    OP
       6 小时 0 分钟前
    @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
       5 小时 55 分钟前
    如何有这些 resources.dll 或者忽略它们?
    unregister
        7
    unregister  
    OP
       5 小时 49 分钟前
    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
       5 小时 46 分钟前
    看了我还是不太懂,不知道它说的是不是对的。:)
    klo424
        9
    klo424  
       5 小时 45 分钟前
    查了一下,第一个 dll 应该是 Enterprise Library 里面的文件,nuget 搜索 enterpriselibrary 能找到。
    https://learn.microsoft.com/en-us/previous-versions/msp-n-p/dn169621(v=pandp.10)
    ming159
        10
    ming159  
       5 小时 44 分钟前
    "这个事件在应用程序无法找到某个程序集时触发。" https://learn.microsoft.com/zh-cn/dotnet/standard/assembly/resolve-loads

    你其他地方依赖了一个 dll,但是这个 dll 并没有.所以就调用到 AssembliesHandler 了. 这个逻辑关系理清了吧.
    ming159
        11
    ming159  
       5 小时 43 分钟前
    所以,根源在于你依赖的 dll 是什么? 如果不用就删掉依赖项. 如果需要用这个 dll.就去找 然后引入项目依赖里
    raviscioniemeche
        12
    raviscioniemeche  
       3 小时 35 分钟前
    应该就是楼上说的依赖的 dll
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5136 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 06:39 · PVG 14:39 · LAX 23:39 · JFK 02:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.