I need to 'scan' the active AppDomain for all loaded assemblies at run time and get a list of unique namespaces available in those assemblies, does .NET support that?
The code must execute during the run time, so that the code is dynamic.
I just started coding in C# , so I'm a bit unsure about where to get started, so any help will be appreciated.
Start from an AppDomain (AppDomain.CurrentDomain perhaps) and call GetAssemblies. On each assembly iterate over the types it defines, keeping track of which namespace each one is in.
As an example of how easy it is to do this with LINQ consider this:
var namespaces = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Select(t => t.Namespace)
.Distinct()
// optionally .OrderBy(ns => ns) here to get sorted results
.ToList();
As a matter of fact I wrote some code that lets you do that a couple of days ago.
Use this class:
public class NSScanner
{
public static List<Type> GetLoadedTypes(AppDomain appDomain)
{
return _getLoadedTypes(appDomain);
}
public static List<Type> GetPublicLoadedTypes(AppDomain appDomain)
{
return _getLoadedTypes(appDomain, true);
}
public static List<string> GetUniqueNamespaces(IEnumerable<Type> types)
{
var uniqueNamespaces = new ConcurrentBag<string>();
Parallel.ForEach(types, type =>
{
if (!uniqueNamespaces.Contains(type.Namespace) && !string.IsNullOrEmpty(type.Namespace))
uniqueNamespaces.Add(type.Namespace);
});
var sortedList = uniqueNamespaces.OrderBy(o => o).ToList();
return sortedList;
}
private static List<Type> _getLoadedTypes(AppDomain appDomain, bool onlyPublicTypes = false)
{
var loadedAssemblies = appDomain.GetAssemblies();
var loadedTypes = new List<Type>();
Parallel.ForEach(loadedAssemblies, asm =>
{
Type[] asmTypes;
if (onlyPublicTypes)
asmTypes = asm.GetExportedTypes();
else
asmTypes = asm.GetTypes();
loadedTypes.AddRange(asmTypes);
});
return loadedTypes;
}
}
Usage:
var publicLoadedTypes = NSScanner.GetPublicLoadedTypes(AppDomain.CurrentDomain);
var namespaces = NSScanner.GetUniqueNamespaces(publicLoadedTypes);
Enjoy!
Related
I'm looking at trying to load our projects from project online into a .NET application, while i can load the projects one thing i'm having trouble with is loading all the columns i would like. I know i can specify the columns i want to load using include but i wanted to be able to use a list of columns that could be generated dynamically.
It's part of an ETL program that I would like to allow the users to configure the list of columns being brought over into the cache database. Below is what I have so far
static void Main(string[] args)
{
ProjectContext pc = getProjCtxt();
pc.Load(pc.Projects);
pc.ExecuteQuery();
ColumnNames fldList = new ColumnNames();
var enumerator = pc.Projects.GetEnumerator();
while (enumerator.MoveNext()) {
var p2 = enumerator.Current;
pc.Load(p2);
pc.ExecuteQuery();
Console.WriteLine(p2.FinishDate);
}
foreach (PublishedProject p in pc.Projects)
{
var pubProj = p.IncludeCustomFields;
pc.Load(pubProj);
pc.ExecuteQuery();
//Dictionary<string, object> projDict = pubProj.FieldValues;
var type = p.GetType();
foreach(ColumnNames.colInfo ci in fldList.impFields)
{
if (type.GetProperty(ci.FieldName) != null)
{
Console.WriteLine(p.FinishDate);
Console.WriteLine(type.GetProperty(ci.FieldName).GetValue(p, null));
}
}
}
}
I get an error on the FinishDate because it hasn't been initialized well how to i initialize all the properties of a task/project so i can work with them if the program doesn't know ahead of time what columns it is looking for.
Is there a way to build up a string and pass it to the project online to tell it what properties to initialize.?
So i found an answer buried eventually.
https://sharepoint.stackexchange.com/questions/89634/syntax-for-including-fields-dynamically-in-csom-query
Managed to also simplify the vode and clean it up. as well as make sure that i'm only including the non Custom Fields in the explicit properties list since the IncludeCustomFields option brings all the custom fields down with it.
static void Main(string[] args)
{
ProjectContext pc = getProjCtxt();
ColumnNames fldList = new ColumnNames();
var q = from ColumnNames.colInfo fld in fldList.impFields
where fld.CustomField == false
select fld;
Console.WriteLine(q.Count());
foreach(ColumnNames.colInfo dynField in q){
pc.Load(pc.Projects, p => p.Include(pj => pj[dynField.FieldName]));
}
pc.Load(pc.Projects, p => p.Include(pj => pj.IncludeCustomFields));
pc.ExecuteQuery();
}
I am trying to use Mono Cecil to manipulate a DLL. What I want to do is to set the base type of some classes to System.MarshalByRefObject from mscorlib.dll. I am using the following code.
var assembly = AssemblyDefinition.ReadAssembly(inputtarget);
var types = assembly.MainModule.Types;
var myTypesToChange = types.Where(...).Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(#"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
myType.BaseType = baseType;
}
assembly.Write(outputtarget);
In the output the base type is not set!
When I am setting the BaseType to a TypeReference selected from the existing assembly, it is setting the base type correctly.
I believe that what I do is very similar to the way it is done as suggested in this reply to a comment about the Code Project article "Reweaving IL code with Mono.Cecil":
"Yes, you can rewrite the base type of any class:"
var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
var mainModule = assembly.MainModule;
var companyType = mainModule.Types.First(t => t.Name == "Company");
var ownerType = mainModule.Types.First(t => t.Name == "Owner");
ownerType.BaseType = companyType;
assembly.Write(AssemblyPath);
This should be easy! What I am doing wrong?
The problem is that assembly metadata is not taken into account. Each assembly has metadata which contains information related to assembly references and type usages.
What you have to do is to import the MarshalByRefObject type in mainModule:
var assembly = assemblyDef.AssemblyDefinition;
var types = assembly.MainModule.Types;
var myTypesToChange = types.Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(#"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
myType.BaseType = mainModule.Import(baseType);
}
Besides the metadata is extended, CIL code of the constructors have to be changed to invoke a constructor of the new base class instead of the original.
Finally, a suggestion. I think TypeReference for MarshalByRefObject can be extracted in a more elegant manner:
var baseType = mainModule.Import(typeof (MarshalByRefObject));
for (...)
{
myType.BaseType = baseType;
}
I'm trying to get the Class and Methods from a assembly, it works when the assembly is the same where the class is, but when it does not work when the assembly is in other project. I already add the reference from the project I want to obtain the Class and Methods but the var theList returns null. I want get the class and methods from one proyect to another , the 2 proyects are in the same solution. I need some help
class Program
{
static void Main(string[] args)
{
var theList = Assembly.GetExecutingAssembly().GetTypes().ToList().Where(t => t.Namespace == "____mvc4.Models").ToList();
Console.WriteLine("--List of Classes with his respective namescpace : ");
foreach (var item in theList)
{
Console.WriteLine(item);
}
Console.WriteLine("------List of classes: ");
foreach (var item in theList)
{
Console.WriteLine("*****************" + item.Name + "*****************");
MemberInfo[] memberInfo = item.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance);
for (int i = 0; i < memberInfo.Length; i++)
{
if (!(memberInfo[i].Name.Contains("get_") || memberInfo[i].Name.Contains("set_")))
{
Console.WriteLine("{0}", memberInfo[i].Name);
}
}
}
Console.ReadLine();
}
the asembly where are the classes that I want obtain does not appear in AppDomain.CurrentDomain.GetAssemblies().ToList();
Here...
var theList = Assembly.GetExecutingAssembly().GetTypes()...etc
you are referring to the current ("executing") assembly. If you want to get types from another assembly, you need to get a reference to that assembly. A simple way to do so is to reference some type from that referenced assembly:
var otherAssembly = typeof(SomeTypeDefinedInAReferencedAssembly).Assembly;
var theList = otherAssembly.GetTypes()...etc
If you want to do it dynamically, then you need to get all the assemblies in the current domain or iterate the /bin/ directory. The domain will get you all kinds of assemblies, including your standard ones, like System. /bin/ will restrict you to just your custom stuff.
Here's a utility method I use. You pass in the evaluation -- i.e. the filter -- and it spits back a list of Types.
public static List<Type> GetClassesWhere(Func<Type, bool> evaluator)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
var types = new List<Type>();
foreach(var assembly in assemblies)
{
try
{
types.AddRange(assembly.GetTypes().Where(evaluator).ToList());
}
catch
{
}
}
return types;
}
I try/catch each assembly individually because I found that sometimes I get some weird permission denied errors, especially in shared environments such as Azure and AppHarbor. It was always on assemblies I didn't care about anyway, so that's why I take no action on catch. For my custom assemblies, it always works for me.
In your example, you'd use it thusly (assuming you put it in a static class called Utilities)
var types = Utilities.GetClassesWhere(t => t.Namespace == "____mvc4.Models");
If you're trying to do this generically as possible, without knowing or caring which assemblies contain this namespaces, you need to check the loaded modules:
var theList = new List<Type>();
BuildManager.GetReferencedAssemblies();
var modules = Assembly.GetExecutingAssembly().GetLoadedModules();
theList.AddRange(modules.SelectMany(x => x.Assembly.GetTypes().Where(t => t.Namespace == "____mvc4.Models")));
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(am => am.GetTypes())
.Select(a => a.Namespace == "Name of your namespace")
.Distinct();
What I'm looking for is probably not going to be possible without resorting to reflection. If that's the case, I'd still want to know the best way to pull it off.
Essentially, this is what I want my code to look like:
var instance = new MyClass();
instance.Add<int, string>(x => x.ToString());
instance.Add<string, Warehouse>(x => Warehouse.LookupByName(x));
instance.Add<Warehouse, IList<Supplier>>(x => x.Suppliers());
instance.Chain(3); // should call each lambda expression in turn
My question is, how can I store these delegates, each with a different signature, in a list in MyClass? And how can I call them later on when I want to, using the return value from each one as the input parameter to the next one?
The inside of MyClass may very well be a mess of List's and all that. But I'm not even sure where to start on this.
(Originally, I wanted to call new MyClass<int, string, Warehouse, IList<Supplier>>(). However, since there's no "type parameter array", I gave up on that approach.)
Well, you could store them all as Delegate - but the tricky thing is invoking them later.
If you're able to validate that the next delegate at any time is of the right type, e.g. by holding a Type reference for "the current output" you could always store a List<Func<object, object>> and make your Add method something like:
public void Add<TIn, TOut>(Func<TIn, TOut> func)
{
// TODO: Consider using IsAssignableFrom etc
if (currentOutputType != typeof(TIn))
{
throw new InvalidOperationException(...);
}
list.Add(o => (object) func((TIn) o));
currentOutputType = typeof(TOut);
}
Then to invoke them all:
object current = ...; // Wherever
foreach (var func in list)
{
current = func(current);
}
The Linq Select statement essentially does this...
var temp = instance.Select(x => x.ToString())
.Select(x => WareHouse.LookupByName(x))
.Select(x=> x.Suppliers());
List<List<Suppliers>> = temp.ToList(); //Evaluate statements
You can also store each intermediate Select call as an Enumerable to have the stated method you use in the OP.
class Program
{
static void Main(string[] args)
{
var instance = new MyClass();
instance.Add<int, string>(i => i.ToString());
instance.Add<string, int>(str => str.Length);
instance.Add<int, int>(i => i*i);
Console.WriteLine(instance.Chain(349));
Console.ReadLine();
}
}
public class MyClass
{
private IList<Delegate> _Delegates = new List<Delegate>();
public void Add<InputType, OutputType>(Func<InputType, OutputType> action)
{
_Delegates.Add(action);
}
public object Chain<InputType>(InputType startingArgument)
{
object currentInputArgument = startingArgument;
for (var i = 0; i < _Delegates.Count(); ++i)
{
var action = _Delegates[i];
currentInputArgument = action.DynamicInvoke(currentInputArgument);
}
return currentInputArgument;
}
}
If you want compile time type checking, what you are doing sounds suspiciously like plain old generic delegates. Assuming that there is some value to storing the individual functions that were Added (other than the Int to String conversion) and composing them later, you can do something like this:
var lookupWarehouseByNumber = new Func<int, Warehouse>(i => Warehouse.LookupByName(i.ToString()));
var getWarehouseSuppliers = new Func<Warehouse, IEnumerable<Supplier>>(w => w.Suppliers);
var getWarehouseSuppliersByNumber = new Func<int, IEnumerable<Supplier>>(i => getWarehouseSuppliers(lookupWarehouseByNumber(i)));
Question based on MSDN example.
Let's say we have some C# classes with HelpAttribute in standalone desktop application. Is it possible to enumerate all classes with such attribute? Does it make sense to recognize classes this way? Custom attribute would be used to list possible menu options, selecting item will bring to screen instance of such class. Number of classes/items will grow slowly, but this way we can avoid enumerating them all elsewhere, I think.
Yes, absolutely. Using Reflection:
static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly) {
foreach(Type type in assembly.GetTypes()) {
if (type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0) {
yield return type;
}
}
}
Well, you would have to enumerate through all the classes in all the assemblies that are loaded into the current app domain. To do that, you would call the GetAssemblies method on the AppDomain instance for the current app domain.
From there, you would call GetExportedTypes (if you only want public types) or GetTypes on each Assembly to get the types that are contained in the assembly.
Then, you would call the GetCustomAttributes extension method on each Type instance, passing the type of the attribute you wish to find.
You can use LINQ to simplify this for you:
var typesWithMyAttribute =
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
The above query will get you each type with your attribute applied to it, along with the instance of the attribute(s) assigned to it.
Note that if you have a large number of assemblies loaded into your application domain, that operation could be expensive. You can use Parallel LINQ to reduce the time of the operation (at the cost of CPU cycles), like so:
var typesWithMyAttribute =
// Note the AsParallel here, this will parallelize everything after.
from a in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
from t in a.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
Filtering it on a specific Assembly is simple:
Assembly assembly = ...;
var typesWithMyAttribute =
from t in assembly.GetTypes()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
And if the assembly has a large number of types in it, then you can use Parallel LINQ again:
Assembly assembly = ...;
var typesWithMyAttribute =
// Partition on the type list initially.
from t in assembly.GetTypes().AsParallel()
let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
where attributes != null && attributes.Length > 0
select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };
Other answers reference GetCustomAttributes. Adding this one as an example of using IsDefined
Assembly assembly = ...
var typesWithHelpAttribute =
from type in assembly.GetTypes()
where type.IsDefined(typeof(HelpAttribute), false)
select type;
As already stated, reflection is the way to go. If you are going to call this frequently, I highly suggest caching the results, as reflection, especially enumerating through every class, can be quite slow.
This is a snippet of my code that runs through all the types in all loaded assemblies:
// this is making the assumption that all assemblies we need are already loaded.
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
var attribs = type.GetCustomAttributes(typeof(MyCustomAttribute), false);
if (attribs != null && attribs.Length > 0)
{
// add to a cache.
}
}
}
This is a performance enhancement on top of the accepted solution. Iterating though all classes can be slow because there are so many. Sometimes you can filter out an entire assembly without looking at any of its types.
For example if you are looking for an attribute that you declared yourself, you don't expect any of the system DLLs to contain any types with that attribute. The Assembly.GlobalAssemblyCache property is a quick way to check for system DLLs. When I tried this on a real program I found I could skip 30,101 types and I only have to check 1,983 types.
Another way to filter is to use Assembly.ReferencedAssemblies. Presumably if you want classes with a specific attribute, and that attribute is defined in a specific assembly, then you only care about that assembly and other assemblies that reference it. In my tests this helped slightly more than checking the GlobalAssemblyCache property.
I combined both of these and got it even faster. The code below includes both filters.
string definedIn = typeof(XmlDecoderAttribute).Assembly.GetName().Name;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
// Note that we have to call GetName().Name. Just GetName() will not work. The following
// if statement never ran when I tried to compare the results of GetName().
if ((!assembly.GlobalAssemblyCache) && ((assembly.GetName().Name == definedIn) || assembly.GetReferencedAssemblies().Any(a => a.Name == definedIn)))
foreach (Type type in assembly.GetTypes())
if (type.GetCustomAttributes(typeof(XmlDecoderAttribute), true).Length > 0)
In case of the Portable .NET limitations, the following code should work:
public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies,
Type attributeType )
{
var typesAttributed =
from assembly in assemblies
from type in assembly.DefinedTypes
where type.IsDefined(attributeType, false)
select type;
return typesAttributed;
}
or for a large number of assemblies using loop-state based yield return:
public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies,
Type attributeType )
{
foreach (var assembly in assemblies)
{
foreach (var typeInfo in assembly.DefinedTypes)
{
if (typeInfo.IsDefined(attributeType, false))
{
yield return typeInfo;
}
}
}
}
This is another version of the code provided by Trade-Ideas philip,
I've condensed the code to linq, plugged it into a nice static function which you can just drop in the project.
Original:
https://stackoverflow.com/a/41411243/4122889
I've also added AsParallel() - on my machine with enough cores etc, and with a 'normally' sized project (which is completely subjective), this was the fastest/
Without AsParallel() this took 1,5 seconds for about 200 results, and with it, it took about a couple milliseconds - therefore this seems the fastest to me.
Note that this skips the assemblies in the GAC.
private static IEnumerable<IEnumerable<T>> GetAllAttributesInAppDomain<T>()
{
var definedIn = typeof(T).Assembly.GetName().Name;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var res = assemblies.AsParallel()
.Where(assembly => (!assembly.GlobalAssemblyCache) && ((assembly.GetName().Name == definedIn) ||
assembly.GetReferencedAssemblies()
.Any(a => a.Name == definedIn))
)
.SelectMany(c => c.GetTypes())
.Select(type => type.GetCustomAttributes(typeof(T), true)
.Cast<T>()
)
.Where(c => c.Any());
return res;
}
Usage:
var allAttributesInAppDomain = GetAllAttributesInAppDomain<ExportViewAttribute>();
Note if you have only 1 attribute per class, so not multiple, its easier to flatten the result from IEnumerable<IEnumerable<T>> to IEnumerable<T> like so:
var allAttributesInAppDomainFlattened = allAttributesInAppDomain.SelectMany(c => c);
Remember, this uses IEnumerable so call ToList() to actually run the function.
We can improve on Andrew's answer and convert the whole thing into one LINQ query.
public static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
{
return assembly.GetTypes().Where(type => type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0);
}