Preface

Dependency Injection (DI) technology is already quite mature. This article mainly explains the applicable versions in Revit and introduces relevant open-source projects.

Version Issues

Version

Current dependency injection packages cannot support Revit versions below 2020. This is because the dependencies in the package are inconsistent with Revit’s own dependencies. Therefore, if you are developing with Revit + DI, you need to use version 2020 or higher. If there are other ways, please introduce them in the comments for us to discuss together.

Reason

Since I commonly use the 2019 version, I referenced the Microsoft.Extensions.Hosting package for development when using DI. However, it reported errors every time I developed. Initially, I thought my development references conflicted with the internal dependencies of this package, so I made a separate project for referencing, but the error persisted. However, changing the version to Revit 2021 worked normally, so I suspect Revit’s loaded dependencies conflict with this package.

![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_16-03-23.png)

So I searched for information and found very little relevant material. There is also relatively little information on using Revit + DI on the internet. I found one resource here that mentioned this issue, which is consistent with my estimation. Jimmy’s reply below also suggests bridging through a complex method (IPC).

How to force a host application to load a .Net addin’s version of transitive dependencies

Revit + DI

There are many explanations and videos about dependency injection online. Here provide two URLs: one is an open-source project and the other is a principle explanation. You can check them if needed.

Dependency Injection - This article is enough
RevitLookup

RevitLookUp collaborated with another open-source author Nice3point after 2020, changing the framework to DI, so those who need to learn can download this file to study and use it themselves.


Let me talk about my current application direction. Because there is less development for versions above 2020 currently, I might misunderstand, but I will record it for now and gradually expand later.
Assuming each method is X_Command, if the number of our plugin functions exceeds 20, we may integrate a set of our own Tools to facilitate development. Based on this, if we directly test plugin functions, we may face frequent Revit startups, or we have to create a separate project to copy the code over for testing, and then copy it back after completion. The efficiency of this method will be relatively slow.
If we create an interface ourselves, and the main code of all commands inherits this interface, we only need to make a test project and use dependency injection to load this method for testing, which will be much more convenient.

![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_16-03-27.png)

Core_Di_Test serves as the project for all Revit functions, containing only the operation part of the code without involving Application and Command.
Let every function you want to write inherit the base interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Core_Di_Test
{


public class Class1:IWorkInterface
{
public void Start()
{
TaskDialog.Show("A", "M");
}
}


public interface IWorkInterface
{
void Start();
}
}

Test file, UI file, or other application scenarios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Class1:IExternalCommand
{

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
// TaskDialog.Show("A", "n");

RevitApi.UiApplication = Context.UiApplication;
//var host = Host.CreateDefaultBuilder();
var host = Host.CreateDefaultBuilder().ConfigureServices(build =>
{
//build.AddSingleton<IExtensionCommand, ReadFamilyParameter>();
build.AddTransient<IWorkInterface, Class1>();
}).Build();

host.Services.GetService<IExtensionCommand>().Start();

//TT.Test(commandData.Application.ActiveUIDocument.Document);

return Result.Succeeded;
}
}

This way, the main code of the function can be separated from testing, UI, and deployment, thereby reducing the coupling between codes and increasing our development efficiency.