从另一个文件夹解析程序集引用

时间:2011-03-10 13:42:23

标签: c# .net clr assembly-resolution

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

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

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

如果我在该文件夹中复制我的小可执行文件并运行它,它可以很好地工作,但如果我把我的.exe放在一个更合适的文件夹中,就像我想要的那样:

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

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

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

我不想在我的app文件夹中复制所有供应商程序集,我不能只在那里放置我引用的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;
    }
}

2 个答案:

答案 0 :(得分:12)

您应首先找到安装这些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);
};

答案 1 :(得分:0)

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

  <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>