![](/img/trans.png)
[英]Activator.CreateInstance(assemblyType) return null using c#
[英]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日)
服務器應用程序參考:
作業庫參考:
我們有遵循相同的模式, 但可以使用不同版本的作業庫引用的建成幾項工作 。 這是由於隨着時間的推移緩慢的蠕變。 如果去年編寫的工作仍在工作,為什么我們要花時間開放該解決方案,更新所有參考文獻,重新編譯,然后花一個月的時間進行質量檢查和驗收,而我們只能將其擱置一旁?
我遇到的挑戰是,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
,則必須將Job001
和Job002
分別加載到其自己的AppDomain中。
請注意,動態加載程序集的順序非常重要:
加載Job001
,它將自動加載找到的LibraryA, 1.0.0.0
,然后再加載Job002
,則它將無法加載LibraryA, 2.0.0.0
和LibraryA, 1.0.0.0
將保留在域中。
同樣,當您加載Job002
,它將自動加載LibraryA, 2.0.0.0
如果找到),如果之后加載Job001
,它將無法加載LibraryA, 1.0.0.0
而LibraryA, 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.