Skip to content

Instantly share code, notes, and snippets.

@abombss
Last active August 22, 2016 15:21
Show Gist options
  • Save abombss/5206329 to your computer and use it in GitHub Desktop.
Save abombss/5206329 to your computer and use it in GitHub Desktop.
Collect all assembly attributes using a reflection only load of an assembly
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
namespace MsBuild.AssemblyFu
{
internal interface IAssemblyAttributeGetter
{
IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetAssemblyAttributes(string assemblyFile);
}
public class ReflectionOnlyAssemblyAttributeGetter : MarshalByRefObject, IAssemblyAttributeGetter
{
public IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetAssemblyAttributes(string assemblyFile)
{
var output = new List<IDictionary<string, string>>();
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;
try
{
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFile);
var assemblyAttributes = CustomAttributeData.GetCustomAttributes(assembly);
output.Add(new Dictionary<string, string>()
{
{"AttribFullName", typeof(AssemblyVersionAttribute).FullName},
{"AttribName", typeof(AssemblyVersionAttribute).Name},
{"AttribNamespace", typeof(AssemblyVersionAttribute).Namespace},
{"AttribTargetAssembly", assemblyFile},
{"Version", assembly.GetName().Version.ToString()},
{"MajorVersion", assembly.GetName().Version.Major.ToString()},
{"MinorVersion", assembly.GetName().Version.Minor.ToString()},
{"BuildVersion", assembly.GetName().Version.Build.ToString()},
{"RevisionVersion", assembly.GetName().Version.Revision.ToString()},
});
foreach (var assemblyAttribute in assemblyAttributes)
{
var attributeResult = new Dictionary<string, string>()
{
{"AttribTargetAssembly", assemblyFile},
};
attributeResult["AttribFullName"] = assemblyAttribute.Constructor.DeclaringType.FullName;
attributeResult["AttribName"] = assemblyAttribute.Constructor.DeclaringType.Name;
attributeResult["AttribNamespace"] = assemblyAttribute.Constructor.DeclaringType.Namespace;
output.Add(attributeResult);
var constructorParamNames = assemblyAttribute.Constructor.GetParameters();
for (int i = 0; i < assemblyAttribute.ConstructorArguments.Count; i++)
{
attributeResult[constructorParamNames[i].Name] = Convert.ToString(assemblyAttribute.ConstructorArguments[i].Value);
}
if (assemblyAttribute.NamedArguments != null)
{
foreach (var namedArg in assemblyAttribute.NamedArguments)
{
attributeResult[namedArg.MemberInfo.Name] = Convert.ToString(namedArg.TypedValue.Value);
}
}
}
}
finally
{
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve;
}
return output;
}
static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
return Assembly.ReflectionOnlyLoad(args.Name);
}
catch (FileNotFoundException fileNotFoundException)
{
try
{
var path = Path.GetDirectoryName(args.RequestingAssembly.Location);
path = Path.Combine(path, args.Name);
return Assembly.ReflectionOnlyLoadFrom(path);
}
catch (Exception) { }
}
catch (Exception) { }
return null;
}
}
internal class AssemblyAttributeGetter : MarshalByRefObject, IAssemblyAttributeGetter
{
public IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetAssemblyAttributes(string assemblyFile)
{
var output = new List<IDictionary<string, string>>();
var assembly = Assembly.LoadFrom(assemblyFile);
var attribs = assembly.GetCustomAttributes(true);
foreach (var attrib in attribs)
{
var dict = new Dictionary<string, string>();
dict["AttribName"] = attrib.GetType().Name;
dict["AttribFullName"] = attrib.GetType().FullName;
dict["AttribNamespace"] = attrib.GetType().Namespace;
foreach (var prop in attrib.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.CanRead))
{
dict[prop.Name] = Convert.ToString(prop.GetValue(attrib, null));
}
output.Add(dict);
}
return output;
}
}
internal class InProcessAssemblyAttributeGetter : MarshalByRefObject, IAssemblyAttributeGetter
{
readonly IAssemblyAttributeGetter _inner;
public InProcessAssemblyAttributeGetter(IAssemblyAttributeGetter inner)
{
_inner = inner;
}
public IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetAssemblyAttributes(string assemblyFile)
{
var result = _inner.GetAssemblyAttributes(assemblyFile);
return result;
}
}
internal class IsolatedAssemblyAttributeGetter : MarshalByRefObject, IAssemblyAttributeGetter
{
static readonly string _assemblyName = Assembly.GetExecutingAssembly().FullName;
static readonly string _codeBase = Assembly.GetExecutingAssembly().CodeBase;
readonly IAssemblyAttributeGetter _inner;
public IsolatedAssemblyAttributeGetter(IAssemblyAttributeGetter inner)
{
_inner = inner;
}
public IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetAssemblyAttributes(string assemblyFile)
{
//AppDomain.CurrentDomain.AssemblyResolve += NewDomainOnAssemblyResolve;
var newDomain = AppDomain.CreateDomain("GetAssemblyAttributes", new Evidence(AppDomain.CurrentDomain.Evidence), new AppDomainSetup()
{
ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
ApplicationName = AppDomain.CurrentDomain.FriendlyName,
// PrivateBinPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
AppDomainInitializerArguments = new[] { _codeBase },
AppDomainInitializer = args =>
{
//Assembly.LoadFile(args[0]);
},
});
//newDomain.AssemblyResolve += NewDomainOnAssemblyResolve;
try
{
var proxiedInner = (IAssemblyAttributeGetter)newDomain.CreateInstanceAndUnwrap(_inner.GetType().Assembly.FullName, _inner.GetType().FullName);
return proxiedInner.GetAssemblyAttributes(assemblyFile);
}
finally
{
//AppDomain.CurrentDomain.AssemblyResolve -= NewDomainOnAssemblyResolve;
//newDomain.AssemblyResolve -= NewDomainOnAssemblyResolve;
AppDomain.Unload(newDomain);
}
}
static Assembly NewDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment