Reputation: 3181
Assembly A declares a custom assembly attribute which is applied in assembly B.
class MyAssemblyAttribute : Attribute { /* ... */ }
I need to get that attribute data from Assembly B from Assembly A method without keeping assembly B loaded.
Pseudo code in assembly A:
var domain = AppDomain.Create();
MyAssemblyAttribute attr = null;
string path = "B.dll";
domain.DoCallback(() => {
attr = Assembly.Load(path)
.GetCustomAttributes()
.OfType<MyAssemblyAttribute>()
.First();
});
AppDomain.Unload(domain);
File.Delete(path);
File.WriteAllBytes(path, ...);
return expectedAttr.Equals(attr);
How can I do it?
I can recompile both assemblies. I can't use 3rd party things like Mono.Cecil or IKVM.
Upvotes: 0
Views: 485
Reputation: 3181
Finally I made this work:
var domain = AppDomain.CreateDomain(
"CompiledAssemblyCheck",
null,
new AppDomainSetup()
{
LoaderOptimization = LoaderOptimization.MultiDomainHost,
PrivateBinPath = Path.GetDirectoryName(Path.GetFullPath(otherAssembly)),
ShadowCopyFiles = "true"
});
try
{
var data = File.ReadAllBytes(otherAssembly);
string myPath = new Uri(executingAssembly.GetName().CodeBase).LocalPath;
var proxy = (AssemblyAnyLoadProxy)domain.CreateInstanceFromAndUnwrap(myPath, typeof(AssemblyAnyLoadProxy).FullName);
proxy.LoadFrom(myPath);
int outputAssemblyId = proxy.Load(data);
bool same = proxy.CompareAttribute(outputAssemblyId, typeof(MyAssemblyAttribute).FullName, expectedArgs);
}
finally
{
AppDomain.Unload(domain);
}
[Serializable]
class AssemblyAnyLoadProxy : MarshalByRefObject
{
List<Assembly> _assemblies=new List<Assembly>();
public int Load(byte[] raw)
{
Assembly asm = Assembly.ReflectionOnlyLoad(raw);
return Add(asm);
}
public int LoadFrom(string assemblyFile)
{
Assembly asm = Assembly.ReflectionOnlyLoadFrom(assemblyFile);
return Add(asm);
}
int Add(Assembly asm)
{
_assemblies.Add(asm);
return _assemblies.Count - 1;
}
public bool CompareAttribute(int assembly, string fullName, object[] args)
{
var attrs = CustomAttributeData.GetCustomAttributes(_assemblies[assembly]);
CustomAttributeData attr = attrs.FirstOrDefault(x => x.Constructor.DeclaringType.FullName == fullName);
return attr?.ConstructorArguments.Select(x => x.Value).SequenceEqual(args) ?? false;
}
}
Upvotes: 1