2011-03-10 76 views
7

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

在这里我想复制此自定义应用程序并运行,我引用的所有组件都在文件夹类似服务器:

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

,如果我复制我小的可执行文件,文件夹中,然后运行它,它作品完美,但如果我把我的.exe以更适当的文件夹,就像我想:

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

这是行不通的,因为它解决不了这些组件。

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

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

的可能重复的http:/ /stackoverflow.com/questions/1373100/how-to-add-folder-to-assembly-search-path-at-runtime-in-net – nawfal 2013-02-20 11:28:18

回答

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); 
}; 
+0

谢谢,我已经修复你的想法和我的代码在edi中特德的问题,现在工作正常:) – 2011-03-10 16:46:51

+0

当然我的解决方案可以优化,我不知道如果此方法必须返回null,如果没有在自定义文件夹中找到程序集,如果是这样,CLR仍然会在GAC,因为例如我注意到这个方法也被称为像System.XML.Serializer这样的程序集......我正在一个控制台应用程序中测试这个控制台应用程序,它承载了一个netTcp绑定的WCF服务,现在它可以工作,我可以从任何文件夹运行应用程序,最后我将创建一个WindowsService来托管我的WCF。再次感谢。)) – 2011-03-10 16:50:01

+0

哎呀,谢谢。将在几天内尝试。 – Tarion 2013-02-19 21:52:19

0

使用SN.exe:SN-T VendorAssembly.dll,这将返回一个十六进制数字,它是公钥标记,然后从应用程序引用的程序集的.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> 
+0

嗨,希望它的工作,我仍然得到FileNotFound异常...大会我需要引用没有强烈命名我猜,SN -t没有工作,但我从异常消息看到PublicKeyToken,所以我从那里复制了它的值,仍然无法解决... :( – 2011-03-10 14:57:39

相关问题