簡體   English   中英

C#,獲取Activator.CreateInstance(assemblyType)對象引用的DLL

[英]C#, Get DLLs referenced by Activator.CreateInstance(assemblyType) object

我有一個位於C:\\ MyApp的控制台應用程序。

我有幾個應用程序未引用的庫。 我使用Activator.CreateInstance()來使用它們。 它們位於C:\\ MyLibrary \\ Job001,C:\\ MyLibrary \\ Job002等 這些庫中的每一個都有多個依賴項,並且可以是主應用程序中已經存在的依賴項的不同版本。

當我嘗試運行此命令時,我看到此錯誤: Could not load file or assembly 'Persistence.Database, Version=1.7.2.67, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. Could not load file or assembly 'Persistence.Database, Version=1.7.2.67, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. 這是大多數作業的常見依賴項之一。 我檢查了目錄,它確實存在於庫中。

如何激活庫中,並將它用作為參考在它自己的目錄中發現了什么?

我正在使用以下(擴展)代碼來激活庫:

public static IJob ConcreteJob(this JobInfoPayload src)
{
    if (src.AssemblyFile.IsNullOrEmpty())
        throw new Exception("AssemblyFile cannot be empty or null!");
    if (src.AssemblyName.IsNullOrEmpty())
        throw new Exception("AssemblyName cannot be empty or null!");

    try
    {
        var assembly = Assembly.LoadFile(src.AssemblyFile);
        var assemblyType = assembly.GetType(src.AssemblyName);
        var job = Activator.CreateInstance(assemblyType) as IJob;
        return job;
    }
    catch (Exception ex)
    {
        Serilog.Log.Logger.Fatal(ex, "JOB was not able to be created!!");
        throw; // bubble this up to the top...
    }
}

我正在查看system.appdomain.assemblyresolve,但在圖書館項目中如何使用它毫無意義。

有什么想法嗎?


其他信息(2016年11月29日)

服務器應用程序參考:

  • 圖書館基礎設施
  • QueueApp.Core
  • 吊火
  • 歐文

作業庫參考:

  • 圖書館基礎設施
  • 庫持久性
  • Library.SQL.Database01
  • Library.SQL.Database02
  • QueueApp.Job.Core
  • 實體框架

我們有遵循相同的模式, 可以使用不同版本的作業庫引用的建成幾項工作 這是由於隨着時間的推移緩慢的蠕變。 如果去年編寫的工作仍在工作,為什么我們要花時間開放該解決方案,更新所有參考文獻,重新編譯,然后花一個月的時間進行質量檢查和驗收,而我們只能將其擱置一旁?

我遇到的挑戰是,JOB無法找到引用的文件,期望它們位於Server App目錄中。 相反,它們位於該Job的目錄中。 使用Fuslogvw.exe只是確認它不在DLL的目錄中查找,而是在宿主應用程序的目錄中查找。

**我現在無論使用Assembly.LoadFrom()還是Assembly.LoadFile()都得到相同的行為。

FUSLOGVW日志結果

*** Assembly Binder Log Entry  (11/29/2016 @ 10:20:21 AM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  D:\Dev\QueueApp\Source\QueueApp\bin\Debug\QueueApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Job.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = file:///D:/Dev/QueueApp/Source/QueueApp/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = QueueApp.exe
Calling assembly : Job.AgileExport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: D:\Dev\QueueApp\Source\QueueApp\bin\Debug\QueueApp.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///D:/Dev/QueueApp/Source/QueueApp/bin/Debug/Job.Core.DLL.
LOG: Attempting download of new URL file:///D:/Dev/QueueApp/Source/QueueApp/bin/Debug/Job.Core/Job.Core.DLL.
LOG: Attempting download of new URL file:///D:/Dev/QueueApp/Source/QueueApp/bin/Debug/Job.Core.EXE.
LOG: Attempting download of new URL file:///D:/Dev/QueueApp/Source/QueueApp/bin/Debug/Job.Core/Job.Core.EXE.
LOG: All probing URLs attempted and failed.

APP正在尋找以下位置的所有文件:
D:\\ Dev \\ QueueApp \\ Source \\ QueueApp \\ bin \\ Debug
該工作存在於:
D:\\ Dev \\ QueueApp \\ Source \\ Job.AgileExport \\ bin \\ Debug

我認為有兩種解決方案可用。

一種解決方案是創建一個新的AppDomain來承載動態加載的程序集。 創建新的AppDomain時,可以選擇提供AppDomain的設置對象,然后在該對象中提供AppDomain用來解析程序集的路徑。 您無法更改現有 AppDomain中的路徑,因為它已經存在。

另一個解決方案是處理您當前的AppDomain的AssemblyResolve事件,如果正常的程序集解析失敗,則會引發此事件。 然后,您可以采取自定義步驟來幫助解決裝配。

.NET中有一個功能/錯誤,當將.NET托管在各種容器(例如IE,COM +等)中並且BinaryFormatter用於反序列化應該可用的類型時,需要處理此事件。找到了。

我在這里有一個掛鈎和解決AssemblyResolve事件的示例: https : //github.com/MarimerLLC/csla/blob/V1-5-x/cslacs10/NetRun/Launcher.cs

在您的情況下,您可能可以更改我的ResolveEventHandler方法,以在最初加載動態程序集的文件夾中查找“丟失”的程序集。

使用Assembly.LoadFrom ,不可能在同一AppDomain中加載同一程序集的多個版本。

因此,如果Job001需要LibraryA, 1.0.0.0 (並且不能在運行時使用較新版本),而Job002需要LibraryA, 2.0.0.0 ,則必須將Job001Job002分別加載到其自己的AppDomain中。

請注意,動態加載程序集的順序非常重要:

  • 加載Job001 ,它將自動加載找到的LibraryA, 1.0.0.0 ,然后再加載Job002 ,則它將無法加載LibraryA, 2.0.0.0LibraryA, 1.0.0.0將保留在域中。

  • 同樣,當您加載Job002 ,它將自動加載LibraryA, 2.0.0.0如果找到),如果之后加載Job001 ,它將無法加載LibraryA, 1.0.0.0LibraryA, 2.0.0.0將保留在其中。域。

最好的選擇是使用Assembly.LoadFile + AppDomain.AssemblyResolve自己加載依賴項(然后您可以在同一AppDomain中擁有同一程序集的多個版本),或者為每個JobXXX程序集創建一個單獨的AppDomain,然后讓依賴項將自動加載。

到目前為止,這是我想出的。 這些類在主服務器應用程序中,而在任何JOB中都找不到。 我們有幾種不同類型的作業,即席即是其中的一種。 通過將代碼放在基類中,所有的JOB處理程序現在都可以繼承它。

public class JobAdHocHandler : BaseHandler, IJobHandler
{
    public MinimumResultModel Handle(MinimumCommandModel message)
    {
        var result = new MinimumResultModel {Id = "-1", PayloadAsString = message.FullPayloadString};

        try
        {
            var info = message.MinimumPayload.JobInfo;

            SetupInstance(info); // <<-- SOLUTION (in BaseHandler)
            var job = JobHandler.GetJob(info); // <<-- SOLUTION (in BaseHandler)

            result.Id = BackgroundJob.Enqueue(() => job.Execute(null, message.FullPayloadString, JobCancellationToken.Null));
        }
        catch (Exception ex)
        {
            Log.Logger.Fatal(ex, ex.Message);
            result.Exception = ex;
        }

        AppDomain.Unload(JobAppDomain);
        return result;
    }
    public bool AppliesTo(JobType jobType) => jobType == JobType.AdHoc;
}

public class BaseHandler : MarshalByRefObject
{
    protected internal AppDomain JobAppDomain;
    protected internal BaseHandler JobHandler;

    protected internal void SetupInstance(JobInfoPayload info)
    {
        var ads = new AppDomainSetup
        {
            ApplicationBase = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName,
            DisallowBindingRedirects = false,
            DisallowCodeDownload = true,
            PrivateBinPath = info.JobClassName,
            ApplicationName = info.JobName,
        };
        JobAppDomain = AppDomain.CreateDomain(info.JobName, null, ads);
        JobHandler = (BaseHandler)JobAppDomain.CreateInstanceAndUnwrap(typeof(BaseHandler).Assembly.FullName, typeof(BaseHandler).FullName);
    }

    protected internal IJob GetJob(JobInfoPayload info)
    {
        var assembly = Assembly.LoadFrom(info.JobClassName + @"\" + info.JobClassName + ".dll");
        var assemblyType = assembly.GetType(info.AssemblyName);
        var job = Activator.CreateInstance(assemblyType) as IJob;
        if (job == null)
            throw new Exception("Unable to create job: " + info.JobClassName);
        return job;
    }
}

到目前為止似乎工作良好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM