Whenever types need to be found in assemblies in order to add them to resolvers, the PluginManager should be used. The TypeFinder should never be used directly in any code except for in PluginManager extension methods or in the PluginManager itself.
The Umbraco.Core.PluginManager
class is responsible for finding and caching all plugin types. It is also responsible for instantiating these types. It contains 4 important methods:
IEnumerable<Type> ResolveTypes<T>()
Generic method to find the specified type and cache the result
IEnumerable<Type> ResolveTypesWithAttribute<T, TAttribute>()
Generic method to find the specified type that has an attribute and cache the result
IEnumerable<Type> ResolveAttributedTypes<TAttribute>()
Generic method to find any type that has the specified attribute and cache the result
T CreateInstance<T>(Type type, bool throwException = false)
Used to create an instance of the specified type based on the resolved/cached plugin types
It is definitely possible to use the methods above to find types in your code but this is not recommended practice. It is recommended to create extension methods for the PluginManager named accordingly to find specific types. For example:
The code for this method is as follows:
The code calls the PluginManager's ResolveTypes method but this method is human readable and distinguishable.
A Resolver should be created for any plugin type. Resolvers are the standard way to retrieve/create/register plugin types.
As an example, we'll create a resolver to resolve an application error logger:
All you need to do is inherit from Umbraco.Core.ObjectResolution.SingleObjectResolverBase<TResolver, TResolved>
and then add whatever constructors, properties and methods you would like to expose.
In the example above we have a constructor that accepts a default IErrorLogger
. Normally in Umbraco this resolver will be constructed in a IBootManager
with a default object. The we expose a method to allow developers to change to a custom IErrorLogger
at runtime called SetErrorLogger
. Then we create a property to expose the IErrorLogger
called ErrorLogger.
Example:
Creating a multiple object resolver is similar. As an example we'll create a LanguageConvertersResolver.
The naming convention for multiple objects resolvers are plural: We've named this LanguageConvertersResolver with a pluralized 'Converters' to denote that this resolver returns multiple objects
When creating a multiple object resolver you need to decide what lifetime scope the objects created and returned will have which is defined in the constructor created. The default constructor of the ManyObjectsResolverBase
specifies that the objects created will have an Application based lifetime scope which means the objects will be singletons only one instance of each one will exist for the lifetime of the application. There are 3 lifetime scopes that can be specified:
ObjectLifetimeScope.Application
One instance of each object will be created for the entire lifetime of the application (singleton)
ObjectLifetimeScope.Transient
A new instance of each object will be created each time the 'Values' collection is accessed
ObjectLifetimeScope.HttpRequest
One instance of each object will be created for the lifetime of the current http request
The term 'Plugins' is referring to any types in Umbraco that are found in assemblies that are used to extend and/or enhance the Umbraco application. Plugins can also be added directly registered to their specific 'Resolver' if the plugin type is not public or if the Resolver type doesn't support finding types in assemblies.
What is a Resolver and what kinds of Resolvers are there?
Creating a single object and multiple object Resolver.
Using the PluginManager to lookup types in assemblies to register in Resolvers.