Decorating .NET assemblies - c#

This may be a long shot, but the flexibility of .NET never ceases to amaze me, so here goes.
I'm developing an MVC application that needs to search through a set of assemblies for class types that are derived from a common base class.
i.e. I have several assemblies that have activity types that are all derived from ActivityBase. These assemblies will be placed in a specific directory. They're kinda like plugins. Since they will need to be loaded dynamically at runtime, they will also need to be accompanied by some dependencies (unless I can figure out a convenient way to separate them, feel free to chime in on this as well.)
I have code that will iterate through all of the .DLL files in this directory, load the assembly, and iterate through all of the types in the assembly to find ones that are derived from ActivityBase.
This works fine. However, I would like to avoid loading and searching through the assemblies that do not have activities, because some of the dependencies have thousands of types and it becomes a performance problem.
So I guess my question is, other than a file naming convention, is there any way to "decorate" or mark an assembly with some type of data that would indicate that it is an activity assembly, that can be easily automated at build time and easily read at runtime?
Any other suggestions for handling this problem are also welcome.

You can implement your own assembly attribute:
[AttributeUsage(AttributeTargets.Assembly)]
public class ActivityAssemblyAttribute : Attribute
{
}
Then decorate necessary assembly with this attribute:
[assembly: ActivityAssemblyAttribute()]
And, when needed, just check whether the assembly under question is decorated with this attribute:
ActivityAssemblyAttribute attribute = null;
object[] attributes = assembly.GetCustomAttributes(typeof(ActivityAssemblyAttribute), false);
if (attributes.Length > 0)
{
attribute = attributes[0] as ActivityAssemblyAttribute;
}

Related

How to examine .NET assembly without using reflection

Let's say, we have class Base, and Derived, defined in Base.dll and Derived.dll respectively. Derived is derived from Base (may not be a direct sub-class though)
The problem at hand is, if we have Derived.dll at hand but Base.dll is missing, how to programmatically examine all the types in Derived? e.g. to know what types are available, their accessibility, inheritance relationship, etc
Based on my understanding, reflection (things in System.Reflection namespace) is not an option here because GetTypes() will try to load Base.dll which is not available, thus throw ReflectionTypeLoadException.
In particularly, is this something that can be easily achieved using Roslyn, or some good library?
You're looking for System.Reflection.Metadata, which exposes assembly metadata directly, without loading assemblies via reflection.
For investigate .NET assembly (types, methods etc.) you need to get that from the metadata. Roslyn its not what you are looking for.
Although it's not exactly true, because Roslyn has two types of information about your code, one is nodes and token and the other is symbols. The first don't know about relation info but the second know.
Anyway, you can do it in more than one way. I'll write two of them.
Use Mono.Cecil to open your assembly, get the main module and investigate whatever you want.
var allTypesDefinitaion = ModuleDefinition.ReadModule(assemblyPath).Types;
Use tools like CFF Explorer to investigate the relevant metadata tables. (TypeDef\Ref)

How to find a type that is not loaded yet in AppDomain?

I'm developing modular application using WPF and Prism.
All my UserControls have separate assemblies and implement IUserControl interface.
I would like to list all Types which implement IUserControl interface form a loaded module library in this way;
//ModuleA.cs
var interfaceType = typeof(IUserControl);
var userControlTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass);
But I cannot see all UserControl types implementing IUserControl in userControlTypes list.
When I use the all classes that implements IUserControl in Bootstrapper.cs like in the following;
var userControlTypes = new List<Type>()
{
{typeof(HastaKayitControl)},
{typeof(ViziteUserControl)},
{typeof(DenemeUserControl)},
...
};
I can get all desired UserControls from the list just I wrote above(userControlTypes).
What is the reason behind this?
FYI:
All assemblies target the same .NET framework version.
My Prism version is 6.1.0
I will use userControlTypes to show all UserControl types inside the application to the end-user.
IUserControl interface contains nothing.
This behavior is by design. The .net CLR will not load in an assembly unless it is called/entered which forces it to be loaded. Imagine the startup cost of running an app if every .dll file in the directory were loaded into memory when the application started as opposed to when a type was referenced at run time for the first time, some apps with large libraries would have load times of minutes (maybe even more?). Also it would not be realistic because some types are resolved to libraries outside of the execution folder like assemblies that resolve to the GAC.
In your first example AppDomain.CurrentDomain.GetAssemblies will only return the loaded assemblies, not all the assemblies, in that application domain. To see this you could add a {typeof(ViziteUserControl)} (taken from your next code part) and place it right above it, this will force the type (and containing assembly) to be loaded by the CLR and now it (types containing assembly) too will be returned by AppDomain.CurrentDomain.GetAssemblies.
In your next code fragment your code is explicitly entering these assemblies and adding the types. I do not think this requires any explaining.
So if you want AppDomain.CurrentDomain.GetAssemblies to load all your types across your application you need to force the assembly to load into memory if it has not already done so. Depending on your structure you could do this a couple of ways.
Iterate through the .dll files on disk (using a reference location like Assembly.GetExecutingAssembly.Location) and call Assembly.LoadFrom. Use wild cards to ensure you are only loading your assemblies and not every .dll library you are encountering.
Reference interested types in a configuration file and load them from there. You can use Type t = Type.GetType(yourConfigType); when creating your list of types from your configuration string list.
Reference interested assemblies in a configuration file and load in the DLL in the same manner as option 1.
Just hard code the list as you did in your last example.
If you choose option 1 or 3 you will have to check to make sure you have not already loaded the assembly in memory before you call Assembly.LoadFrom. You can do this by again checking what is already loaded with AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query).
Also Note that once you load an assembly into your application domain you cannot unload it for the life of that application domain. If you do not want this but you still want to dynamically find all your types you will have to create a 2nd application domain to find all the types and return them as an array/list of fully qualified type name as a string. You can then unload this created application domain. Also, as correctly noted by #Peter below in the comments, use ReflectionOnlyLoadFrom if you go with this approach. This incurs much less overhead.
AppDomain.GetAssemblies() tells you the loaded assemblies, not the referenced ones. I can't speak to the Prism aspect of your question, and I agree with the comments that there is probably a better way to design this. But…
If you really want to enumerate all of the types that might get loaded in your AppDomain, you can approximate this by enumerating the types in the existing assemblies (i.e. as you've done here, with AppDomain.CurrentDomain.GetAssemblies(), but then for each assembly, call GetReferencedAssemblies()), which returns an array of AssemblyName values that you can use to load additional assemblies. For each of those, you can in turn inspect all of their types (to find the implementors of IUserControl) and to call GetReferencedAssemblies() to continue the recursive search.
Note that this still will not necessarily return all implementors of the IUserControl interface that your process might load. Assemblies can be loaded by means other than being referenced in your AppDomain's assemblies, such as by code searching a directory for candidates, or even the user explicitly naming an assembly to load. This is why using mechanisms directly supported by whatever API you're using is a much better approach, to make sure that you find exactly those assemblies that that API would find.

Assembly.GetCustomAttributes still considered best approach?

I want to point to a directory of DLL's and read the attributes of the classes in it. Most classes have a custom attribute with various properties that I want to read.
I have some old code which uses Assembly.GetCustomAttributes
Is this still considered the best approach?
Assembly.GetCustomAttributes gets you attributes for the assembly - which is assemblie's metadata. This are usually place in the AssemblyInfo.cs while they can be placed anywhere.
It should not be confused with class custom attributes - or property/method/field/etc.
If you mean you want to filter out assemblies to look out for by having a custom attribute which identifies such assemblies of interest, then it is a valid approach. However, bear in mind, to read such attributes, assembly first needs to be loaded onto memory.
Reflection is the only way to read custom attributes. Some pseudo custom attributes are reflected on properties of the System.Type class. Assemblies loaded 'normally' cannot be unloaded from an appdomain, so ideally you want to load the assemblies into a reflection only context (there are methods System.Reflection.Assembly.ReflectionOnlyLoad and ReflectionOnlyLoadFrom) so that they may be unloaded when you have your desired information.

Enforcing type visibility between namespaces in C#

I have the idea that it might be useful to enforce type visibility between namespaces rather than assemblies (internal) in C#.
It would seem that such a concept would assist developers working with a codebase, ensuring the correct types are used in places where another internal type supplying similar functionality is available, but would result in "architectural" disadvantages (unwanted dependencies etc).
Do others think this would be useful and is it currently possible? If not why not?
Also, would the concept of preclusions - the ability to specify negative constraints on references between namespaces and / or assemblies be a useful addition to C#?
A type is strongly bound to the assembly in which it is defined. A namespace is not, it can appear in multiple assemblies. System.Configuration for example.
Let's assume for a moment that the metadata format for an assembly would be changed (-1 billion points) to store attributes for a namespace. Those attributes would still have to be stored in an assembly because that's the storage unit for metadata. Now you have to deal with the possibility that the CLR loads another assembly and finds the same namespace but with conflicting attributes. How could it possibly resolve that?
More seriously, how would you prevent external code from simply using the same namespace and attributes to suddenly get access to implementation details that were meant to be private. This completely destroys the value of having the internal keyword.
You could make them public, tag them with a custom attribute, and then add a FxCop rule to check for accesses from the outside of the namespace.
This doesn't securely enforce the restriction and fails when the member is accessed with reflection, but if it's only about policy/codingstyle this should be enough.
I think there is also an existing attribute to hide members from Intellisense which you might use in conjunction with your custom attribute.

Assembly Attributes with Dynamically Loaded Assembly

I'm using a 3rd party library which requires a static method to be invoked before it is used - it sets the serial key to validate the license for the software. I'm needing to use this library in multiple projects and I want to shield those projects from needing to worry about this license. Ideally, I'd like to create a shared assembly which will handle the licensing and reference it by the projects which use the library - and isolate those projects from even knowing that any licensing is taking place.
One way to start thinking about accomplishing this is to perhaps use an assembly attribute. So, I make one which has a contructor to set the license:
[AttributeUsage(AttributeTargets.Assembly)]
public class LibraryLicenseAttribute : Attribute
{
public LibraryLicenseAttribute()
{
Lib.SetLicense("valid key");
}
}
and place it in a wrapper project:
LibraryWrapperProject
Properties
AssemblyInfo.cs
References
Lib.dll
LibraryLicenseAttribute.cs
And have it invoked by including it in AssemblyInfo.cs:
[LibraryLicense]
Now, I can reference this project in another project which uses the library:
LibraryUserProject
References
LibraryWrapperProject
LibraryUser.cs
... but when I go to use the library ...
class LibraryUser
{
public LibraryUser()
{
Lib.Use();
}
}
It reports that the license hasn't been set. I've found that I can include the attribute in the calling project's AssemblyInfo.cs and the attribute will get invoked. This is better than redistributing the licensing to all the downstream projects, but they still need that extra cruft to make it work.
Furthermore - some of the projects are dynamically loaded elseware. For instance:
Assembly.Load("LibraryUserProject.dll");
How can I invoke the licensing assembly attribute when dynamically loading the assembly it is contained in? Is there another .NET framework feature that might make this easier?
Without much analysing your solution to the problem, i suggest you to check out the AppDomain.CurrentDomain.AssemblyLoad and AppDomain.AssemblyResolve events for running your code when the assembly resolved or loadded.
Another and more elegant solution may be using a static type initializers (static constructor) or Module Initializers. Static type intitializers are called the first time the type is referenced and easy to implement. However, Module Initializers in C# is not a trivial task but you can achive your goal by implementing.

Categories

Resources