This repository borrows heavily from Onbox framework to create dependency inject with Revit Plugins. Instead of using custom container created by Onbox Team this is using Unity Container.
I've removed some libraries and utilities (like their mvc like packages). Packed all of it into a single dll for simplicity.
The package can be downloaded from Nuget
Make sure that the application class that would normally inherit from IExternalApplication inherits from Revit App
[ContainerProvider("{{GUID}}")] // This attribute is crucial
public class App : RevitApp
{
public override void OnCreateRibbon(IRibbonManager ribbonManager)
{
// Here you can create Ribbon tabs, panels and buttons
}
public override Result OnStartup(IUnityContainer container, UIControlledApplication application)
{
// Add Container registrations here
return Result.Succeeded;
}
public override Result OnShutdown(IUnityContainer container, UIControlledApplication application)
{
// The container will be disposed automatically
return Result.Succeeded;
}
}
Make sure that the command class that would normally inherit from IExternalCommand inherits RevitAppCommand<App> where "App" refers to the application class
[Transaction(TransactionMode.Manual)] // Important to every command
public class SampleCommand : RevitAppCommand<App>
{
public override Result Execute(IUnityContainer container, ExternalCommandData commandData,
ref string message, ElementSet elements)
{
// Your logic here
}
}
Registration follows standard Unity procedures below just the basics from their documentation.
var instance = new Service();
container.RegisterInstance(instance);
// Named Registration
container.RegisterInstance("UniqueName", instance);
// Mapped to type
container.RegisterInstance<IService>(instance);
container.RegisterInstance<IService>("UniqueName", instance);
or
container.RegisterInstance(typeof(IService), instance)
container.RegisterInstance(typeof(IService), "UniqueName", instance)
// Per container (Default)
container.RegisterInstance("UniqueName", instance, InstanceLifetime.PerContainer);
container.RegisterInstance<IService>("UniqueName", instance, InstanceLifetime.PerContainer);
// Singleton
container.RegisterInstance("UniqueName", instance, InstanceLifetime.Singleton);
container.RegisterInstance<IService>("UniqueName", instance, InstanceLifetime.Singleton);
// External (Unity will not control the instance lifetime)
container.RegisterInstance<IService>("Some Name", instance, InstanceLifetime.External);
container.RegisterFactory<IService>(f => new Service());
// Standard
container.RegisterType<IService, Service>();
// Named
container.RegisterType<IService, MailService>("Email");
// Lifetime
container.RegisterType<IService, MailService>("Email", TypeLifetime.Singleton);
You can either register required services directly in the OnStartup method
Or create extension methods
public static class SamplePipeline
{
public static IUnityContainer RegisterSampleServices(this IUnityContainer container)
{
container.RegisterType<IService, Service>();
return container;
}
}
public class App : RevitApp
{
[...]
public override Result OnStartup(IUnityContainer container, UIControlledApplication application)
{
// Direct
container.RegisterType<IService, Service>();
// Extension
container.RegisterSampleServices();
...
return Result.Succeeded;
}
[...]
}
For more detailed explanation refer to Unity Documentation
Generally speaking you can get instance of a class/service by
var instance = Container.Resolve<Service>();
Unity framework should automatically resolve services required by a constructor of a class
static
constructors are not supportedprivate
andprotected
constructors are not accessible- Constructors with
ref
andout
parameters are not supported
Constructors are selected as below:
- If present, use registered Injection Constructor
- If present, annotated with an attribute
- Automatically select constructor
- Get all accessible constructors
- Process constructors in ascending order from most complex to the default
- Filter out restricted constructors
- Loop through parameters and check if
- Is primitive
- Is registered with the container
- Has default value
- Is resolvable type
- Is registered with container
- Is primitive
- Select the first constructor the container can create
Sample
// Default
public class Service
{
private readonly IDependency _dependency;
public Service(IDependency dependency)
{
_dependency = dependency;
}
}
// Constructor Annotation
public class Service
{
private readonly IDependency _dependency;
[InjectionConstructor]
public Service(IDependency dependency)
{
_dependency = dependency;
}
public Service()
{
}
}
// Or Registering a specific constructor
Container.RegisterType<Service>(Invoke.Constructor());
For convenience I've created a project templates