Optimal add-in code base approach to target multiple Revit releases

Optimal add-in code base approach to target multiple Revit releases

jeremy_tammik
Alumni Alumni
7,020 Views
37 Replies
Message 1 of 38

Optimal add-in code base approach to target multiple Revit releases

jeremy_tammik
Alumni
Alumni

Dear Revit API add-in developers,

 

Is there a common or typical approach that third-party add-in developers use to have one code base that builds add-ins for many Revit releases? 

 

If yes, can you please share an example?

 

Motivation: The next major release of the Revit API may target a different .NET development environment than Revit 2024. Therefore, the Revit development team would like to make an example application that multi-targets them both to demonstrate how one code base can build both add-ins. The goal will be to help customers supporting many Revit releases with one body of code.

 

Jeremy suggested: That sounds like a great idea and a very useful undertaking. Yes, there are numerous samples floating around illustrating various approaches to this. One problem might be to selecting the best choice. Here are a few that The Building Coder picked up:

 

 

There are several more mentioned in the Revit API discussion forum and shared in various GitHub projects; searching the former for multi brings up one or two:

 

 

Some of the Revit templates on GitHub also support multi-version compilation:

 

 

Which approach do you prefer to implement a Revit add-in code base targeting multiple Revit releases?

 

Thank you!

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
7,021 Views
37 Replies
Replies (37)
Message 21 of 38

pvhuyg
Explorer
Explorer

I am having difficulty setting up Interactivity for multiple versions in a .xaml file. In Revit versions 2025 and below, we use the following namespace:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

However, in version 2025, we still use the same namespace:

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"


0 Likes
Message 22 of 38

SamBerk
Advocate
Advocate

Hi @jeremy_tammik 

 

I found that the simplest solution to maintain the same code base for 2025 and earlier is to put the TargetFramework in a condition.  

 

Here is step by step:

  • Create a dotnet 8 class library project
  • Reference Revit 2025 dll's (RevitAPI.dll and RevitAPIUI.dll, set Copy Local to No)
  • Create configurations '2024Debug' and '2025Debug' (or release)
  • Edit the project file and put the TargetFramework and the Reference in a condition: 

 

 

 <PropertyGroup Condition="'$(Configuration)' == '2024Debug'">
   <TargetFramework>net481</TargetFramework>
 </PropertyGroup>
 <PropertyGroup Condition="'$(Configuration)' == '2025Debug'">
   <TargetFramework>net8.0</TargetFramework>
 </PropertyGroup>
 
 <ItemGroup>
    <Reference Include="RevitAPI" Condition="'$(Configuration)' == '2024Debug'">
     <HintPath>..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2024\RevitAPI.dll</HintPath>
     <Private>False</Private>
   </Reference>
   <Reference Include="RevitAPIUI" Condition="'$(Configuration)' == '2024Debug'">
     <HintPath>..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2024\RevitAPIUI.dll</HintPath>
     <Private>False</Private>
   </Reference>
   <Reference Include="RevitAPI" Condition="'$(Configuration)' == '2025Debug'">
     <HintPath>..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2025\RevitAPI.dll</HintPath>
     <Private>False</Private>
   </Reference>
   <Reference Include="RevitAPIUI" Condition="'$(Configuration)' == '2025Debug'">
     <HintPath>..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2025\RevitAPIUI.dll</HintPath>
     <Private>False</Private>
   </Reference>
 </ItemGroup>

 

 

  •  Create an App.cs file and implement IExternalApplication

 

 

public class App : IExternalApplication
{
    public Result OnStartup(UIControlledApplication application)
    {
        TaskDialog.Show("Multi-Version Addin", $"Revit version: {application.ControlledApplication.VersionNumber}");

        return Result.Succeeded;
    }

    public Result OnShutdown(UIControlledApplication application)
    {
        return Result.Succeeded;
    }
}​

 

 

  • Create an output folder for both versions ('c:\...\output\2024' and 'c:\...\output\2025')
  • Add a .addin file to your project for both versions (MyAddin2024.addin and MyAddin2025.addin)

 

 

<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
  <AddIn Type="Application">
    <Name>MyAddin</Name>
    <Assembly>C:\...\output\2024\MyAddin.dll</Assembly> (or 2025)
    <FullClassName>MyAddin.App</FullClassName>
    <ClientId>{client id}</ClientId>
    <VendorId>{vendor id}</VendorId>
    <VendorDescription>{vendor description}</VendorDescription>
  </AddIn>
</RevitAddIns>

 

 

  •  Post-build events:

 

 

      echo Configuration: $(Configuration)
      if $(Configuration) == 2024Debug goto 2024
      if $(Configuration) == 2025Debug goto 2025

      :2024
      echo Copying results to 2024
      copy "$(ProjectDir)MyAddin2024.addin" "$(AppData)\Autodesk\REVIT\Addins\2024"
      copy "$(ProjectDir)bin\$(Configuration)\net481\*.dll" "C:\...\output\2024"
      goto exit

      :2024
      echo Copying results to 2024
      copy "$(ProjectDir)MyAddin2025.addin" "$(AppData)\Autodesk\REVIT\Addins\2025"
      copy "$(ProjectDir)bin\$(Configuration)\net8.0\*.dll" "C:\...\output\2025"
      goto exit

      :exit

 

 

  • Build both configurations
  • Open Revit 2024:

SamBerk_0-1724709688908.png

  • Open Revit 2025:

SamBerk_1-1724709739994.png

 

For debugging, add to the project file:

 

 

  <PropertyGroup Condition="'$(Configuration)' == '2024Debug'">
    <StartProgram>C:\Program Files\Autodesk\Revit 2024\Revit.exe</StartProgram>
    <StartAction>Program</StartAction>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)' == '2025Debug'">
    <StartProgram>C:\Program Files\Autodesk\Revit 2025\Revit.exe</StartProgram>
    <StartAction>Program</StartAction>
  </PropertyGroup>

 

 

 

Thank you all

Message 23 of 38

nice3point
Advocate
Advocate

Step-by step guide for revit multiversion templates: https://github.com/Nice3point/RevitTemplates/wiki/Step%E2%80%90by%E2%80%90step-Guide

 

You will be able to create a project in a few steps without spending hours setting up a solution from scratch. Try it

Message 24 of 38

SONA-ARCHITECTURE
Advocate
Advocate

I'd like to make a contribution here, because after a lot of searching on this forum and also on @Jeremmy's blog, I finally found a Visua Studio solution that works for Revit versions 2021->2024 using framework 4.8 and for version 2025 using framework 8.0.

In one solution, I have a license generator project and the Revit plugin project.
Here's a preview of my .sln file

 

What you need to understand is that I have as many Release as Debug in each version of Revit. This information is then found in the plugin project configuration file, which has the .csproj extension. The Release is used to compile the plugin dll and its dependencies for use. I use Debug mode when I'm using the invaluable AddInManager.

 

 

 

Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug 2021|Any CPU = Debug 2021|Any CPU
		Debug 2021|x64 = Debug 2021|x64
		Debug 2022|Any CPU = Debug 2022|Any CPU
		Debug 2022|x64 = Debug 2022|x64
		Debug 2023|Any CPU = Debug 2023|Any CPU
		Debug 2023|x64 = Debug 2023|x64
		Debug 2024|Any CPU = Debug 2024|Any CPU
		Debug 2024|x64 = Debug 2024|x64
		Debug 2025|Any CPU = Debug 2025|Any CPU
		Debug 2025|x64 = Debug 2025|x64
		Release 2021|Any CPU = Release 2021|Any CPU
		Release 2021|x64 = Release 2021|x64
		Release 2022|Any CPU = Release 2022|Any CPU
		Release 2022|x64 = Release 2022|x64
		Release 2023|Any CPU = Release 2023|Any CPU
		Release 2023|x64 = Release 2023|x64
		Release 2024|Any CPU = Release 2024|Any CPU
		Release 2024|x64 = Release 2024|x64
		Release 2025|Any CPU = Release 2025|Any CPU
		Release 2025|x64 = Release 2025|x64
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2021|Any CPU.ActiveCfg = Debug 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2021|Any CPU.Build.0 = Debug 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2021|x64.ActiveCfg = Debug 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2021|x64.Build.0 = Debug 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2022|Any CPU.ActiveCfg = Debug 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2022|Any CPU.Build.0 = Debug 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2022|x64.ActiveCfg = Debug 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2022|x64.Build.0 = Debug 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2023|Any CPU.ActiveCfg = Debug 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2023|Any CPU.Build.0 = Debug 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2023|x64.ActiveCfg = Debug 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2023|x64.Build.0 = Debug 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2024|Any CPU.ActiveCfg = Debug 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2024|Any CPU.Build.0 = Debug 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2024|x64.ActiveCfg = Debug 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2024|x64.Build.0 = Debug 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2025|Any CPU.ActiveCfg = Debug 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2025|Any CPU.Build.0 = Debug 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2025|x64.ActiveCfg = Debug 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Debug 2025|x64.Build.0 = Debug 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2021|Any CPU.ActiveCfg = Release 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2021|Any CPU.Build.0 = Release 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2021|x64.ActiveCfg = Release 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2021|x64.Build.0 = Release 2021|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2022|Any CPU.ActiveCfg = Release 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2022|Any CPU.Build.0 = Release 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2022|x64.ActiveCfg = Release 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2022|x64.Build.0 = Release 2022|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2023|Any CPU.ActiveCfg = Release 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2023|Any CPU.Build.0 = Release 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2023|x64.ActiveCfg = Release 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2023|x64.Build.0 = Release 2023|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2024|Any CPU.ActiveCfg = Release 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2024|Any CPU.Build.0 = Release 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2024|x64.ActiveCfg = Release 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2024|x64.Build.0 = Release 2024|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2025|Any CPU.ActiveCfg = Release 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2025|Any CPU.Build.0 = Release 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2025|x64.ActiveCfg = Release 2025|Any CPU
		{9DB9E599-B676-4BA4-BA5B-C6A6E1A644FD}.Release 2025|x64.Build.0 = Release 2025|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2021|Any CPU.ActiveCfg = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2021|Any CPU.Build.0 = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2021|x64.ActiveCfg = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2021|x64.Build.0 = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2022|Any CPU.ActiveCfg = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2022|Any CPU.Build.0 = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2022|x64.ActiveCfg = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2022|x64.Build.0 = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2023|Any CPU.ActiveCfg = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2023|Any CPU.Build.0 = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2023|x64.ActiveCfg = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2023|x64.Build.0 = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2024|Any CPU.ActiveCfg = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2024|Any CPU.Build.0 = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2024|x64.ActiveCfg = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2024|x64.Build.0 = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2025|Any CPU.ActiveCfg = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2025|Any CPU.Build.0 = Debug|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2025|x64.ActiveCfg = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Debug 2025|x64.Build.0 = Debug|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2021|Any CPU.ActiveCfg = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2021|Any CPU.Build.0 = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2021|x64.ActiveCfg = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2021|x64.Build.0 = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2022|Any CPU.ActiveCfg = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2022|Any CPU.Build.0 = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2022|x64.ActiveCfg = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2022|x64.Build.0 = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2023|Any CPU.ActiveCfg = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2023|Any CPU.Build.0 = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2023|x64.ActiveCfg = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2023|x64.Build.0 = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2024|Any CPU.ActiveCfg = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2024|Any CPU.Build.0 = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2024|x64.ActiveCfg = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2024|x64.Build.0 = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2025|Any CPU.ActiveCfg = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2025|Any CPU.Build.0 = Release|Any CPU
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2025|x64.ActiveCfg = Release|x64
		{A9818572-9EC6-4536-A383-2370C9D0AFB0}.Release 2025|x64.Build.0 = Release|x64
	EndGlobalSection

 

 

Next, we configure the csproj file.
We find this first section

 

 

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="Current">
  <PropertyGroup>   
    <UseWPF>true</UseWPF>
    <UseWindowsForms>true</UseWindowsForms>
    <PlatformTarget>x64</PlatformTarget>
    <OutputType>Library</OutputType>
    <RootNamespace>SuezTools</RootNamespace>
    <AssemblyName>SuezTools</AssemblyName>
    <LangVersion>latest</LangVersion>
    <Nullable>disable</Nullable>	  
	  <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <ImplicitUsings>enable</ImplicitUsings>    
	  <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
    <Configurations>
      Debug 2021;Debug 2022;Debug 2023;Debug 2024;Debug 2025;
      Release 2021;Release 2022;Release 2023;Release 2024;Release 2025
    </Configurations>
  </PropertyGroup>

 

 

 If you use WPF forms and Windows forms, write this

 

 

<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>

 

 

If you're project will be a dll for Revit use this

 

 

<OutputType>Library</OutputType>

 

 

Framework 8 is more demanding in terms of coding rules, so if you want to be able to declare variables without having to avoid null variables, if you want to generate your own AssemblyInfo.cs file (which contains global variables such as version numbers, copyright, etc.), if you want to use implicit declarations of your using, then write this

 

 

<Nullable>disable</Nullable>	  
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ImplicitUsings>enable</ImplicitUsings>    

 

 

 Finally, for each Revit version (Debug or Release) to which you compile, you must define the version type, the framework type and also, and above all, for framework 8, force the Windows platform, as the framework now supports more platforms and you risk getting warnings

 

 

<PropertyGroup Condition="$(Configuration.Contains('Debug'))">
  <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('Release'))">
  <DebugType>pdbonly</DebugType>
  <Optimize>true</Optimize>
  <DefineConstants>$(DefineConstants);TRACE</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('2021'))">
<RevitVersion>2021</RevitVersion>
<TargetFramework>net48</TargetFramework>
<DefineConstants>$(DefineConstants);REVIT2021</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('2022'))">
<RevitVersion>2022</RevitVersion>
<TargetFramework>net48</TargetFramework>
<DefineConstants>$(DefineConstants);REVIT2022</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('2023'))">
<RevitVersion>2023</RevitVersion>
<TargetFramework>net48</TargetFramework>
<DefineConstants>$(DefineConstants);REVIT2023</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('2024'))">
<RevitVersion>2024</RevitVersion>
<TargetFramework>net48</TargetFramework>
<DefineConstants>$(DefineConstants);REVIT2024</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('2025'))">
<RevitVersion>2025</RevitVersion>
<TargetFramework>net8.0-windows</TargetFramework>  
<DefineConstants>$(DefineConstants);TRACE;REVIT2025</DefineConstants>
<SupportedOSPlatform>windows</SupportedOSPlatform>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>

 

 

Next, here's how I managed my dependencies:
For each framework, I indicated the dependencies I wanted
for the 4.8 framework, I've always used direct dependencies, and I choose which ones are local copies or not (like here Standard.Licensing for license management)
For Office.Interop.Excel, Word or Outlook dependencies, I've declared them as COM. By using a COM reference, you enable your .NET application to interact directly with Excel's COM components, which is more reliable in certain contexts. And it saved me from execution errors in Revit.
Here's an example for the Revit 2021->2024 section...

 

 

 

 <!-- Références pour les versions Revit 2021-2024 (.NET Framework 4.8) -->
 <ItemGroup Condition="$(Configuration.Contains('2021')) Or $(Configuration.Contains('2022')) Or $(Configuration.Contains('2023')) Or $(Configuration.Contains('2024'))">   
    
 
   <!-- Ajoutez ici toutes les autres références spécifiques au .NET Framework 4.8 -->
   <Reference Include="PresentationCore" />
   <Reference Include="PresentationFramework" />
   <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
     <HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
   </Reference>
   <Reference Include="Standard.Licensing">
     <HintPath>..\packages\Standard.Licensing.1.2.0\lib\net461\Standard.Licensing.dll</HintPath>
     <Private>True</Private>
   </Reference>
   <Reference Include="System" />
   <Reference Include="System.Core" />
   <Reference Include="System.Drawing" />
   <Reference Include="System.Management" />
   <Reference Include="System.Windows.Forms" />
   <Reference Include="System.Xaml" />
   <Reference Include="System.Xml.Linq" />
   <Reference Include="Microsoft.CSharp" />
   <Reference Include="System.Data" />
   <Reference Include="System.Xml" />
   <Reference Include="WindowsBase" />
   <COMReference Include="Microsoft.Office.Interop.Outlook">
     <Guid>{00062FFF-0000-0000-C000-000000000046}</Guid>
     <VersionMajor>9</VersionMajor>
     <VersionMinor>6</VersionMinor>
     <Lcid>0</Lcid>
     <WrapperTool>primary</WrapperTool>
     <Isolated>False</Isolated>
     <EmbedInteropTypes>True</EmbedInteropTypes>
   </COMReference>

 

 

Depending on the version of Revit you wish to compile, this group allows you to go directly to the 4 Revit dlls you need.

 

 

<!-- Autres références Revit si nécessaire -->
<Reference Include="RevitAPI">
  <HintPath>C:\Program Files\Autodesk\Revit $(RevitVersion)\RevitAPI.dll</HintPath>
  <Private>False</Private>
</Reference>
<Reference Include="RevitAPIUI">
  <HintPath>C:\Program Files\Autodesk\Revit $(RevitVersion)\RevitAPIUI.dll</HintPath>
  <Private>False</Private>
</Reference>
<Reference Include="AdWindows">
  <HintPath>C:\Program Files\Autodesk\Revit $(RevitVersion)\AdWindows.dll</HintPath>
  <Private>False</Private>
</Reference>
<Reference Include="UIFramework">
  <HintPath>C:\Program Files\Autodesk\Revit $(RevitVersion)\UIFramework.dll</HintPath>
  <Private>False</Private>
</Reference>

 

 

Finally, here's the section for the .net or 8.0 framework.
Here, dependencies are directly packages, and this is how the framework manages them.

 

 

 

 <!-- PackageReferences pour Revit 2025 (.NET 8) -->
 <ItemGroup Condition="$(Configuration.Contains('2025'))">
   
   <!-- Ajoutez ici toutes les autres références spécifiques au .NET 8 -->
   <PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
   <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
   <PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
   <PackageReference Include="RestSharp" Version="112.0.0" />
   <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
   <PackageReference Include="Microsoft.AspNetCore.SystemWebAdapters" Version="1.4.0" />
   <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
   <PackageReference Include="System.Management" Version="8.0.0" />
   <PackageReference Include="Standard.Licensing" Version="1.2.0" />

   <COMReference Include="Microsoft.Office.Interop.Excel">
     <WrapperTool>tlbimp</WrapperTool>
     <VersionMinor>9</VersionMinor>
     <VersionMajor>1</VersionMajor>
     <Guid>00020813-0000-0000-c000-000000000046</Guid>
     <Lcid>0</Lcid>
     <Isolated>false</Isolated>
     <EmbedInteropTypes>true</EmbedInteropTypes>
   </COMReference>

 

 

2024-10-04_16h07_05.png

 

In the postBuldEvent, I copy all of my dll in the Revit Addins folder wich is in %Appdata% not ProgamData.
When I make a Debug version, I copy files in a Debug folder wich is used by the AddInManager.

 

<PostBuildEvent>
  echo ______________
  echo PostBuildEvent

  :: __________________FICHIER ADDIN_______________________________________
  echo Copie fichier .addIn
  copy "$(ProjectDir)*.addin" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)" /y

  :: _________________FICHIERS JSON______________________________________________
  echo Copie fichiers json
  copy "$(ProjectDir)*.json" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\$(AssemblyName)" /y
  copy "$(ProjectDir)*.json" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\Debug" /y

  :: _________________FICHIERS md______________________________________________
  echo Copie fichier md de la solution dans le dossier "$(SolutionDir)LastBuild"
  copy "$(SolutionDir)README.md"  "$(SolutionDir)\LastBuild" /y

  :: ____________________DLL DEPENDANCES_REPERTOIRE ADDINS___________________
  echo Copie des dll et des pdb dans "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)"
  copy "$(ProjectDir)$(OutDir)*.dll" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\$(AssemblyName)" /y
  copy "$(ProjectDir)$(OutDir)*.pdb" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\$(AssemblyName)" /y

  :: _____________DLL DEPENDANCES_REPERTOIRE DEBUG AIM___________________
  echo Copie des dll et des pdb dans "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\Debug"
  copy "$(ProjectDir)$(OutDir)*.dll" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\Debug" /y
  copy "$(ProjectDir)$(OutDir)*.pdb" "$(AppData)\Autodesk\Revit\Addins\$(RevitVersion)\Debug" /y
</PostBuildEvent>

 

By th way, I used modeless forms and if you want to debug your code with the AddInManager, we must preload external assemblies in Debug Mode. So, before the Excecute method, put this

#if DEBUG
            // Préchargement des assemblages
            AssemblyLoader.PreloadAssemblies();
#endif

And load all dependencies you need for your code

public static class AssemblyLoader
{
    public static void PreloadAssemblies()
    {
        try
        {
            System.Reflection.Assembly.Load("Standard.Licensing, Version=1.2.0.0");
            System.Reflection.Assembly.Load("BouncyCastle.Cryptography, Version=2.4.0.0");
        }
        catch (Exception ex)
        {
            // Log l'erreur
            System.Diagnostics.Debug.WriteLine($"Erreur lors du préchargement de l'assemblage : {ex.Message}");
        }
    }
}

Maybe there is an other best solution, but, for me, it works!

 

Hope it will help you!

 

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
Message 25 of 38

JeffroH
Participant
Participant

I'm surprised more developers aren't utilizing shared projects. Shared projects seem to offer the greatest flexibility, in my opinion.

Maybe not too surprised since shared projects came out less than 10 years ago.

 

The AutoCAD API adheres better to established API design principles, particularly in not breaking existing code(changing signatures, etc.), and works really well with shared projects for multiple year releases. 

 

Centralizing your code in a shared project and using each year's project solely for build configurations, references, build events, and related setup seems easier and more efficient in my opinion.

If you want an example here are ExtensibleStorageManagerSchemaWrapperTools(referenced by ExtensibleStorageManager)projects from the SDK example ready to build for 2020-2025. All I did was take 2020 project and add conditional compilation symbols to separate code changes between the years

https://github.com/Hpad/RevitSharedProject

The only change is you will have to change build output path for the 2025 projects as the relative paths converted to full paths.

 

If you want to add a 2026 project

  • Add new project using correct .NET framework(guessing .NET 8.0 for 2026)
  • Reference the RevitAPI.dll, RevitUIAPI.dll, the shared projects.
  • Add Release and Debug conditional compilations symbols 
  • Update code with symbols(ex REVIT 2026) if required

 

 

 

Message 26 of 38

mgutierrezBM9E9
Contributor
Contributor

i AGREE WITH YOU. The only inconvenient i faced with shared project is hosting the UI WPF code. To work around that I created a separate .net framework project where I put all the UI WPF code related and which is referenced in everysingle revit add-in project. This way the shared project can recognize and invoke the WPF UI Classes.

Message 27 of 38

EvanGeer
Participant
Participant

For smaller projects, I agree that Shared Projects are a good solution. For large projects with a team of developers, Shared Projects can obscure dependencies between submodules. I've seen this lead to poor separation of concerns. If you're building a project where you would typically be delivering multiple dlls to separate your modules, then I would recommend a different approach. 

Evan Geer
evangeer.com
0 Likes
Message 28 of 38

nice3point
Advocate
Advocate

Overcoding, why do you need Shared Projects when we have Conditional compilation https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives

0 Likes
Message 29 of 38

ricaun
Advisor
Advisor

I really don't think shared projects is a good solution for building multiple Revit versions.

 

In your example you have 2 shared projects and 12 projects, to many projects to manage.

 

And like you said, to add a new version you need to create 2 more projects.

 

I don't know how you do to test inside Revit, because everything build at the same time for all the Revit versions.

 

For me looks easier to manage a single project with multiple configurations, like `Debug 2020`, `Debug 2021`, `Debug 2022`, `Debug 2023`, `Debug 2024`, `Debug 2025` and so on.

 

And in the csproj I can have the same approach with defines for the different versions.

 

In your example you could convert the shared project to a normal project with multiple configurations, using the same code, and make the csproj to select the correct Revit API reference based in the configuration. Here I convert to use multiple configuration for each Revit version: https://github.com/ricaun/RevitNotSharedProject

 

And you add a new version of Revit you just need to add a new configuration and update the csproj. So all the information about the project is contain in the project/folder.

 

This is the approach I use in my projects, and I think is the best way to manage multiple Revit versions.

 

Shared project has some use cases but for manage multiple Revit versions I think is not the best solution.

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 30 of 38

JeffroH
Participant
Participant

You can place the UI WPF code in the shared project. You just need make sure each project has all the WPF required references. One quick hack is to add a WPF window  and delete it. 

Message 31 of 38

JeffroH
Participant
Participant

I do not understand. Example places all code in the shared project and uses Conditional compilation. It is same amount code if I used one project.

 

0 Likes
Message 32 of 38

peter_hirn
Enthusiast
Enthusiast

Multiple projects vs multiple configurations is just a preference. Everyone should pick what fits their requirements best.

 

I prefer multiple projects, much like the example from @JeffroH but simplified, eg.:

 

.
├── global.json
├── renovate.json
├── Solution.slnx
├── src
│   ├── 2023
│   │   ├── 2023.csproj
│   │   └── packages.lock.json
│   ├── 2024
│   │   ├── 2024.csproj
│   │   └── packages.lock.json
│   ├── 2025
│   │   ├── 2025.csproj
│   │   └── packages.lock.json
│   ├── 2026
│   │   ├── 2026.csproj
│   │   └── packages.lock.json
│   ├── Common
│   │   ├── Command.cs
│   │   ├── Utils.cs
│   │   └── <your .cs files>
│   └── Directory.Build.props

 

global.json

{
  "sdk": {
    "version": "9.0.300"
  }
}

 

Solution.slnx

<Solution>
  <Project Path="src/2023/2023.csproj">
    <Platform Project="x64" />
  </Project>
  <Project Path="src/2024/2024.csproj">
    <Platform Project="x64" />
  </Project>
  <Project Path="src/2025/2025.csproj">
    <Platform Project="x64" />
  </Project>
  <Project Path="src/2026/2026.csproj">
    <Platform Project="x64" />
  </Project>
</Solution>

 

Shared project properties in src/Directory.Build.props

<Project>
  <PropertyGroup>
    <VersionPrefix>1.0.0</VersionPrefix>
    <AssemblyName>AssemblyName</AssemblyName>
    <Company>ACME Ltd.</Company>
    <Description>Description of the app.</Description>
    <RepositoryUrl>https://example.com</RepositoryUrl>
  </PropertyGroup>
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <LangVersion>12.0</LangVersion>
    <PlatformTarget>x64</PlatformTarget>
    <Platforms>x64</Platforms>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
    <OutputPath>bin\Debug\</OutputPath>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
    <OutputPath>bin\Release\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Content Include="../../resources/asset.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>

 

src/2023/2023.csproj

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <DefineConstants>REVIT2023_OR_GREATER</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="..\Common\*.cs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Autodesk.Forge.DesignAutomation.Revit" Version="2023.0.2" PrivateAssets="All" />
    <PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="2023.1.1" />
    <PackageReference Include="Nice3point.Revit.Api.RevitAPIUI" Version="2023.1.1"/>
  </ItemGroup>
</Project>

 

src/2026/2026.csproj

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <DefineConstants>REVIT2023_OR_GREATER;REVIT2024_OR_GREATER;REVIT2025_OR_GREATER;REVIT2026_OR_GREATER</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="..\Common\*.cs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Autodesk.Forge.DesignAutomation.Revit" Version="2026.0.0" PrivateAssets="All" />
    <PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="2026.0.4" />
    <PackageReference Include="Nice3point.Revit.Api.RevitAPIUI" Version="2026.0.4" />
  </ItemGroup>
</Project>

 

Implementation now simply goes into files in src/Common/, eg. src/Common/Utils.cs

using Autodesk.Revit.DB;

namespace MyNamespace;

internal static class Utils
{
    internal static long IdValue(ElementId id)
    {
#if REVIT2024_OR_GREATER
        return id.Value;
#else
        return id.IntegerValue;
#endif
    }
}

 

Version restrictions for automated dependency updates configured in renovate.json

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [":semanticCommits", "config:best-practices"],
  "packageRules": [
    {
      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
      "matchCurrentVersion": "!/^0/",
      "automerge": true
    },
    {
      "matchFileNames": ["src/2023/2023.csproj"],
      "matchPackageNames": [
        "Autodesk.Forge.DesignAutomation.Revit",
        "Nice3point.Revit.Api.RevitAPI",
        "Nice3point.Revit.Api.RevitAPIUI"
      ],
      "allowedVersions": "<2024"
    },
    {
      "matchFileNames": ["src/2024/2024.csproj"],
      "matchPackageNames": [
        "Autodesk.Forge.DesignAutomation.Revit",
        "Nice3point.Revit.Api.RevitAPI",
        "Nice3point.Revit.Api.RevitAPIUI"
      ],
      "allowedVersions": "<2025"
    },
    {
      "matchFileNames": ["src/2025/2025.csproj"],
      "matchPackageNames": [
        "Autodesk.Forge.DesignAutomation.Revit",
        "Nice3point.Revit.Api.RevitAPI",
        "Nice3point.Revit.Api.RevitAPIUI"
      ],
      "allowedVersions": "<2026"
    },
    {
      "matchFileNames": ["src/2026/2026.csproj"],
      "matchPackageNames": [
        "Autodesk.Forge.DesignAutomation.Revit",
        "Nice3point.Revit.Api.RevitAPI",
        "Nice3point.Revit.Api.RevitAPIUI"
      ],
      "allowedVersions": "<2027"
    },
    {
      "groupName": "revit-api",
      "matchPackageNames": ["nice3point.revit.api.**"]
    }
  ]
}

 

Message 33 of 38

Mr.Borges
Enthusiast
Enthusiast

I grab this idea from some .NET developer on the internet, changed for my AutoCAD API plays, and then I updated it to work with Revit API, but unfortunately I do not remember from where I found it.

(comment here for credits)

My solution folder:

MrBorges_0-1747757181560.png

Magic happens here inside .csproj folder:

MrBorges_1-1747757223887.png

<!RevitKit.base contents>
<Project Sdk="Microsoft.NET.Sdk">

  <!-- Common Properties -->
  <PropertyGroup>
    <RootNamespace>RevitKit</RootNamespace>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>

  <!-- Needed to remove obj file from compiling -->
  <ItemGroup>
    <Compile Remove="obj\**" />
    <EmbeddedResource Remove="obj\**" />
    <None Remove="obj\**" />
  </ItemGroup>

  <!-- Abstracted Properties-->
  <!-- Configurations/Defined Pre-compiler Flags -->
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>$(DefineConstants);$(NetVersion)</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DefineConstants>$(DefineConstants);$(NetVersion)</DefineConstants>
  </PropertyGroup>

  <ItemGroup Condition = "'$(TargetFramework)' == 'net481'">
    <!-- Revit 2022+ -->
    <PackageReference Include="Speckle.Revit.API" Version="2022.0.2.1" />
    <!-- Dynamo 2022+ -->
    <PackageReference Include="DynamoForRevit.2022.ZeroTouchUtils" Version="2025.1.24" />
  </ItemGroup>
    <ItemGroup Condition = "'$(TargetFramework)' == 'net8.0-windows10.0.17763.0'">
    <!-- Revit 2025+ -->
    <PackageReference Include="Speckle.Revit.API" Version="2025.0.0" />
    <!-- Dynamo 2025+ -->
    <PackageReference Include="DynamoForRevit.2025.ZeroTouchUtils" Version="2025.1.24" />
  </ItemGroup>
</Project>

 

<!RevitKit.paths contents>
<Project>
  <PropertyGroup>
    <MSBuildProjectExtensionsPath>..\Builds\Obj\$(NetVersion)</MSBuildProjectExtensionsPath>
    <BaseIntermediateOutputPath>..\Builds\Obj\$(NetVersion)</BaseIntermediateOutputPath>
    <IntermediateOutputPath>..\Builds\Obj\$(NetVersion)</IntermediateOutputPath>
    <BaseOutputPath>..\Builds\Bin</BaseOutputPath>
  </PropertyGroup>
</Project>
<!RevitKit.NetCore.csproj contents>
<Project>

  <PropertyGroup>
    <NetVersion>NetCore</NetVersion>
    <TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
    <GenerateDocumentationFile>True</GenerateDocumentationFile>
    <BaseOutputPath>..\Builds</BaseOutputPath>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <NoWarn>1591</NoWarn>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <NoWarn>1591</NoWarn>
  </PropertyGroup>

  <Import Project=".csproj/RevitKit.paths" />
  <Import Project=".csproj/RevitKit.base" />

  <ItemGroup>
    <Compile Remove="Dynamo\**" />
    <EmbeddedResource Remove="Dynamo\**" />
    <None Remove="Dynamo\**" />
  </ItemGroup>
</Project>
<!RevitKit.NetFramework.csproj contents>
<Project>

  <PropertyGroup>
    <NetVersion>NetFramework</NetVersion>
    <TargetFramework>net481</TargetFramework>
    <GenerateDocumentationFile>True</GenerateDocumentationFile>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <NoWarn></NoWarn>
    <WarningLevel>1</WarningLevel>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <NoWarn></NoWarn>
    <WarningLevel>1</WarningLevel>
  </PropertyGroup>

  <Import Project=".csproj/RevitKit.paths" />
  <Import Project=".csproj/RevitKit.base" />

  <ItemGroup>
    <Compile Remove="Dynamo\**" />
    <EmbeddedResource Remove="Dynamo\**" />
    <None Remove="Dynamo\**" />
  </ItemGroup>

  <ItemGroup>
    <Compile Remove="Models\DB\RKClass.cs" />
  </ItemGroup>

</Project>

The Dynamo projects uses the same approach.

Then I can do the magic:

Compile for Revit 2022+ (Net Framework) or 2025+ (Net 8)

MrBorges_2-1747757936350.png

And this beauty VSTO 2022 tell me if any method is available or not for each target (one code only for every target):

MrBorges_3-1747758199560.png

 

 

Message 34 of 38

Sean_Page
Collaborator
Collaborator

I know this thread is dated for the original request, but I just recently had this conversation and having built with various methods, I recommend and use Shared Projects for my multi-targeted apps. Maybe a little more front end setup, maybe, but for me it makes it much easier to manage and compartmentalize different versions, especially across core framework changes.

 

Also, if you get it setup correctly, there aren't any WPF or resource issues.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
Message 35 of 38

EvanGeer
Participant
Participant

This is very similar to the approach I outlined. Definitely my preference for keeping things simple and separated. 

Evan Geer
evangeer.com
Message 36 of 38

Sean_Page
Collaborator
Collaborator

I initially had issues with this, but either they have resolved the issue in VS, or there is something in the setup that needs to change because I work with WPF without any issues now across R22-R26.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 37 of 38

ricaun
Advisor
Advisor

Why you don't have a single project that target multiple target framework at the same time. I guess you don't know that is possible 🙃

 

You can target multiple frameworks using something like this.

 

<TargetFrameworks>net47;net48;net8.0-windows</TargetFrameworks>

 

So I don't need to add any other shared project...

 

I use all the time in Revit plugins.

 

Here is a csproj as sample.

https://github.com/ricaun-io/ricaun.RevitTest/blob/master/ricaun.RevitTest.Application/ricaun.RevitT...

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 38 of 38

Mr.Borges
Enthusiast
Enthusiast

Thanks @ricaun , You're right, I didn't know it was possible to have multiple framework targets. I'll give it a try. 

0 Likes