私が開発に役立つシステムの要件の1つに、ファイルをインポートする機能があり、さまざまな種類のファイル(csv、xmlなど)を処理するための一連のアダプタがあります。私たちは遭遇すると予想します。開発の初期段階では、リファレンスとコマンドを使用してデータアダプタをハードコーディングしていました。明らかにこれが生きるときには、新しいアダプタを作成してdllをフォルダに入れ、コードを再コンパイルせずにプロシージャを実行できる状況が必要です。多くのdllをコードにロードするとクラッシュする
これを実装するには、this questionのコードを修正しました。この方法は、我々は成功し、データアダプタをロードし、私が期待するようにそれらを使用することができます。この
private IEnumerable<IUniversalDataAdapter> DataAdapters
{
get
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IUniversalDataAdapter))))
{
if (type.IsAbstract) continue; // can't create abstract classes
if (!dataAdapters.Any(y => y.GetType().Equals(type)))
{
IUniversalDataAdapter adapter = (IUniversalDataAdapter)Activator.CreateInstance(type);
dataAdapters.Add(adapter);
}
}
}
return dataAdapters;
}
}
を持って実行したときに
string dllLocation = @"C:MyLocation\dllLocation";
DirectoryInfo dir = new DirectoryInfo(dllLocation);
var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories); // This will need to be changed when we go live
foreach (var file in tempfiles)
{
Assembly tempAssembly = null;
//Before loading the assembly, check all current loaded assemblies in case already loaded
//has already been loaded as a reference to another assembly
//Loading the assembly twice can cause major issues
foreach (Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
//Check the assembly is not dynamically generated as we are not interested in these
if (loadedAssembly.ManifestModule.GetType().Namespace != "System.Reflection.Emit")
{
//Get the loaded assembly filename
string loadedFilename = loadedAssembly.CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/') + 1);
//If the filenames match, set the assembly to the one that is already loaded
if (loadedFilename.ToUpper() == file.Name.ToUpper())
{
tempAssembly = loadedAssembly;
break;
}
}
}
//If the assembly is not aleady loaded, load it manually
if (tempAssembly == null)
{
tempAssembly = Assembly.LoadFrom(file.FullName);
}
Assembly a = tempAssembly;
その後、次のように問題のコードは、コンストラクタに位置しています。私は
var tempfiles = dir.GetFiles("*.dll", SearchOption.AllDirectories);
ルーチンクラッシュにそれを変更すると、コードの第2ビットは、この時に実行される前に、私たちはライン
var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories);
を持っているコードの最初のビットに質問に対する今
、ルーチン
private IEnumerable<IDataValidator> DataValidators
{
get
{
if (validators.Count == 0)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IDataValidator))))
{
if (!type.IsAbstract)
{
var validator = (IDataValidator)Activator.CreateInstance(type, context);
validators.Add(validator);
}
}
}
}
return validators;
}
}
編集:例外を追加しました
System.Reflection.ReflectionTypeLoadException was unhandled
HResult=-2146232830
Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Source=mscorlib
StackTrace:
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.RuntimeModule.GetTypes()
at System.Reflection.Assembly.GetTypes()
at TTi.Data.Pipeline.Server.Common.DataPipeline.get_DataValidators() in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 124
at TTi.Data.Pipeline.Server.Common.DataPipeline.CheckConfiguration(DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 528
at TTi.Data.Pipeline.Server.Common.DataPipeline.ProcessDataSource(IDataSource dataSource, DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 213
at TTi.Data.Test.Program.ImportTest(String testFolders) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 362
at TTi.Data.Test.Program.Main(String[] args) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 48
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
EndEdit:
DataValidators
は間違いDataAdapters
ルーチンの前に実行されます。 DataValidatorsは、メインコードベースに含まれる単なるコードの一部であり、インポートされたデータが期待される形式であることを確認するためにチェックします。この時点で、必要なものが存在することを確認できるように、ロードするだけです。
ロードされたアセンブリを見ると、両方のバージョンのコードでは必要に応じてアダプタが読み込まれますが、2番目のバージョンは最初のバージョンよりも先に読み込まれます。
だから、tempfiles
の2番目のバージョンは、コードのまったく無関係な部分のように見えるのはなぜですか?十分なデータアダプタを追加すると、コードがクラッシュする可能性がありますか?
例外とスタックトレースとは何ですか? – rene
いくつかの質問:.dllで終わるすべてのファイルは本当に.net dllですか?管理されていないDLLを読み込もうとすると、クラッシュします。あなたのdllによって同じ場所に参照されるdllはありますか?またはシステムがそれらを見つける可能性がある場所(つまり、binフォルダまたは%windir%\ system32など)に移動しますか?あなたは64ビットのプロセスとして実行していますが、読み込みしようとしているアセンブリのいずれかが32ビットのアンマネージdllを参照していますか(これもクラッシュします)? – mortb
@mortbはい、彼らが私たちのコードやNugetパッケージのすべてのビットであることがわかります。このプログラムは、32ビットまたは64ビットについては特定されておらず、.Net 4.6を実行しています。私は特にソリューションフォルダを探しています。 – Andrew