참조 된 모든 어셈블리를 앱 도메인에 강제로로드하는 방법이 있습니까?
내 프로젝트는 다음과 같이 설정됩니다.
- 프로젝트 "정의"
- 프로젝트 구현"
- 프로젝트 "소비자"
"Consumer"프로젝트는 "Definition"과 "Implementation"을 모두 참조하지만 "Implementation"의 어떤 유형도 정적으로 참조하지 않습니다.
애플리케이션이 시작되면 프로젝트 "Consumer"는 "구현"에서 유형을 찾아야하는 "정의"에서 정적 메소드를 호출합니다.
경로 나 이름을 모르고, 가급적이면 본격적인 IOC 프레임 워크를 사용하지 않고도 참조 된 어셈블리를 앱 도메인에 강제로로드 할 수있는 방법이 있습니까?
이것은 트릭을 수행하는 것처럼 보였습니다.
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
var loadedPaths = loadedAssemblies.Select(a => a.Location).ToArray();
var referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
var toLoad = referencedPaths.Where(r => !loadedPaths.Contains(r, StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(path => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
Jon이 언급했듯이 이상적인 솔루션은로드 된 각 어셈블리의 종속성으로 재귀해야하지만 특정 시나리오에서는 걱정할 필요가 없습니다.
업데이트 : .NET 4에 포함 된 Managed Extensibility Framework (System.ComponentModel)는 이와 같은 작업을 수행하는 데 훨씬 더 나은 기능을 제공합니다.
를 사용 Assembly.GetReferencedAssemblies
하여를 얻은 AssemblyName[]
다음 Assembly.Load(AssemblyName)
각각 을 호출 할 수 있습니다. 물론 재귀해야하지만 이미로드 한 어셈블리를 추적하는 것이 좋습니다. :)
재귀 예제를 공유하고 싶었습니다. 다음과 같이 시작 루틴에서 LoadReferencedAssembly 메서드를 호출합니다.
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
this.LoadReferencedAssembly(assembly);
}
다음은 재귀 적 방법입니다.
private void LoadReferencedAssembly(Assembly assembly)
{
foreach (AssemblyName name in assembly.GetReferencedAssemblies())
{
if (!AppDomain.CurrentDomain.GetAssemblies().Any(a => a.FullName == name.FullName))
{
this.LoadReferencedAssembly(Assembly.Load(name));
}
}
}
Fody.Costura 또는 기타 어셈블리 병합 솔루션을 사용하는 경우 허용 된 답변이 작동하지 않습니다.
다음은 현재로드 된 어셈블리의 참조 된 어셈블리를로드합니다. 재귀는 당신에게 맡겨져 있습니다.
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
loadedAssemblies
.SelectMany(x => x.GetReferencedAssemblies())
.Distinct()
.Where(y => loadedAssemblies.Any((a) => a.FullName == y.FullName) == false)
.ToList()
.ForEach(x => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(x)));
오늘 특정 경로에서 어셈블리 + 종속성을로드해야했기 때문에이 클래스를 작성했습니다.
public static class AssemblyLoader
{
private static readonly ConcurrentDictionary<string, bool> AssemblyDirectories = new ConcurrentDictionary<string, bool>();
static AssemblyLoader()
{
AssemblyDirectories[GetExecutingAssemblyDirectory()] = true;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
}
public static Assembly LoadWithDependencies(string assemblyPath)
{
AssemblyDirectories[Path.GetDirectoryName(assemblyPath)] = true;
return Assembly.LoadFile(assemblyPath);
}
private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
{
string dependentAssemblyName = args.Name.Split(',')[0] + ".dll";
List<string> directoriesToScan = AssemblyDirectories.Keys.ToList();
foreach (string directoryToScan in directoriesToScan)
{
string dependentAssemblyPath = Path.Combine(directoryToScan, dependentAssemblyName);
if (File.Exists(dependentAssemblyPath))
return LoadWithDependencies(dependentAssemblyPath);
}
return null;
}
private static string GetExecutingAssemblyDirectory()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
또 다른 버전 ( Daniel Schaffer 답변 기반 )은 모든 어셈블리를로드 할 필요가 없지만 미리 정의 된 수의 어셈블리를로드 할 수있는 경우입니다.
var assembliesToLoad = { "MY_SLN.PROJECT_1", "MY_SLN.PROJECT_2" };
// First trying to get all in above list, however this might not
// load all of them, because CLR will exclude the ones
// which are not used in the code
List<Assembly> dataAssembliesNames =
AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly => AssembliesToLoad.Any(a => assembly.GetName().Name == a))
.ToList();
var loadedPaths = dataAssembliesNames.Select(a => a.Location).ToArray();
var compareConfig = StringComparison.InvariantCultureIgnoreCase;
var referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
.Where(f =>
{
// filtering the ones which are in above list
var lastIndexOf = f.LastIndexOf("\\", compareConfig);
var dllIndex = f.LastIndexOf(".dll", compareConfig);
if (-1 == lastIndexOf || -1 == dllIndex)
{
return false;
}
return AssembliesToLoad.Any(aName => aName ==
f.Substring(lastIndexOf + 1, dllIndex - lastIndexOf - 1));
});
var toLoad = referencedPaths.Where(r => !loadedPaths.Contains(r, StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(path => dataAssembliesNames.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
if (dataAssembliesNames.Count() != AssembliesToLoad.Length)
{
throw new Exception("Not all assemblies were loaded into the project!");
}
'Development Tip' 카테고리의 다른 글
Android Studio 3.4로 업그레이드 한 후 resources_ap 관련 오류 (0) | 2020.10.31 |
---|---|
Rails has_many : Join Model의 추가 속성으로 찾기 (0) | 2020.10.31 |
MVVM을 사용하는 이유는 무엇입니까? (0) | 2020.10.31 |
"로그 앤 스로우"가 안티 패턴으로 간주되는 이유는 무엇입니까? (0) | 2020.10.31 |
단일 Scrapy 프로젝트에서 서로 다른 스파이더에 대해 서로 다른 파이프 라인을 사용하려면 어떻게해야합니까? (0) | 2020.10.31 |