【问题标题】:Resolve assembly references from another folder解析来自另一个文件夹的程序集引用
【发布时间】:2011-07-12 17:41:08
【问题描述】:

我正在开发一个应用程序,它引用和使用来自某个供应商的一些第三方程序集;在开发框中,我在源代码树的引用文件夹中有这 3 个程序集,我可以引用它们并构建应用程序,应用程序构建但不运行,因为没有安装整个服务器应用程序,但这很好。

在我要复制此自定义应用程序并运行我引用的所有程序集的服务器上,文件夹中的内容如下:

D:\ProgramFiles\VendorName\ProductName\Support\API\Bin64

如果我将我的小型可执行文件复制到该文件夹​​中并运行它,它会完美运行,但如果我将我的 .exe 放在我想要的更合适的文件夹中:

D:\ProgramFiles\MyCompanyName\MyProduct\bin\...

它不起作用,因为它无法解析这些程序集。

我知道我可以在 app.config 中使用探测来指定我的 exe 必须在哪些文件夹中查找引用,但我认为程序集不在子文件夹中,而是在完全不同的位置。

我不想复制我的应用程序文件夹中的所有供应商程序集,我不能只放我引用的 3 个,因为它们也在加载其他程序集,除非我拥有所有这些程序集(很多......),它不起作用。

我没有做任何特别的事情,没有创建应用程序域,也没有通过反射加载程序集,只是希望 CLR 在应用程序启动或执行时解析引用。

谢谢。

编辑:这里是最终的工作代码

static System.Reflection.Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    Logger logger = new Logger();

    try
    {
        string RMSAssemblyFolder = ConfigurationManager.AppSettings["RMSAssemblyFolder"];

        Assembly MyAssembly = null;
        string strTempAssmbPath = string.Empty;

        Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly();
        AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

        AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name);

        if (myAssemblyName != null)
        {
            MyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase);
        }
        else
        {
            strTempAssmbPath = Path.Combine(RMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");

            if (!string.IsNullOrEmpty(strTempAssmbPath))
            {
                if (File.Exists(strTempAssmbPath))
                {
                    logger.Information("Assembly to load: {0} - File was found in: {1}", args.Name, strTempAssmbPath);

                    // Loads the assembly from the specified path.                  
                    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
                }
            }
        }

        // Returns the loaded assembly.
        return MyAssembly;
    }
    catch (Exception exc)
    {
        logger.Error(exc);
        return null;
    }
}

【问题讨论】:

标签: c# .net clr assembly-resolution


【解决方案1】:

您应该首先找到安装这些 dll 的文件夹,然后使用 AppDomain.AssemblyResolve 挂钩程序集解析并尝试从该文件夹加载请求的程序集。

它看起来像这样(未经测试,您需要检查 args.Name 包含的确切内容,可能包含版本和强名称以及类型名称):

var otherCompanyDlls = new DirectoryInfo(companyFolder).GetFiles("*.dll");

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var dll = otherCompanyDlls.FirstOrDefault(fi => fi.Name == args.Name);
    if (dll == null)
    {
        return null;
    }

    return Assembly.Load(dll.FullName);
};

【讨论】:

  • 谢谢,我已经在编辑后的问题中使用了你的想法和我的代码,现在可以正常工作了:)
  • 我的解决方案当然可以优化,如果在自定义文件夹中找不到程序集,我不确定此方法是否必须返回 null,如果是这样,CLR 仍会在 GAC 中查找它,因为例如我注意到这个方法也被称为 System.XML.Serializer 之类的程序集......我正在一个控制台应用程序中测试这个,它托管一个 netTcp 绑定的 WCF 服务,现在它可以工作了,我可以从任何运行应用程序文件夹,最后我将创建一个 WindowsService 来托管我的 WCF。再次感谢。))
  • 我发现这种方法对我不起作用。具有完整路径的 Assembly.Load() 失败;它再次调用 AssemblyResolve(因为它无法解析 DLL)。所以我目前正在考虑在 AssemblyResolve 处理程序中使用 Assembly.LoadFrom()。
  • 'var dll = otherCompanyDlls.FirstOrDefault(fi => fi.Name == args.Name)' - 在每次命中或未命中时对列表进行线性扫描。请求大量 oaf 并且现有程序集可能是性能问题。
  • 每次某些程序集无法解析(每个加载上下文每个未知程序集最多一次)时,它是对一小部分(文件夹中的 dll 数量)的线性扫描。这闻起来像是过早的优化(1. 不要这样做。2. 仅供专家使用!:不要这样做)。但无论如何,一个简单的var otherCompanyDllsDict = otherCompanyDlls.ToDictionary(fi =&gt; fi.Name) 然后通过字典访问应该可以解决它。
【解决方案2】:

使用SN.exe:SN -T VendorAssembly.dll,这将返回一个十六进制数字,即公钥令牌,然后,从 app.config 引用程序集。要获取版本,请右键单击您的供应商程序集并将其用作 codeBase 版本值,即您提到的 href=path。

  <configuration>
       <runtime>
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
             <dependentAssembly>
                <assemblyIdentity name="VendorAssembly"  culture="neutral" publicKeyToken="307041694a995978"/>
                <codeBase version="1.1.1.1" href="FILE://D:/ProgramFiles/VendorName/ProductName/Support/API/Bin64/VendorAssembly.dll"/>
             </dependentAssembly>
          </assemblyBinding>
       </runtime>
    </configuration>

【讨论】:

  • 嗨,希望它工作,我仍然得到 FileNotFound 异常...我需要引用的程序集没有强命名我猜,SN -t 没有工作,但我从异常中看到了 PublicKeyToken消息,所以我从那里复制了它的值,仍然无法解决... :(
猜你喜欢
  • 1970-01-01
  • 2011-09-11
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多