2011-03-10 27 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

相關問題