diff --git a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj
index 703d1b4325..2453ed25a0 100644
--- a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj
+++ b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj
@@ -9,10 +9,12 @@
false
false
"$(SolutionDir)transform_all.bat" "$(ProjectDir)"
+ false
bin\
false
None
AssemblyInfoGenerator
+ bin\$(Configuration)\
false
diff --git a/src/BUILDSYSTEM_TODO.md b/src/BUILDSYSTEM_TODO.md
new file mode 100644
index 0000000000..16feb3e378
--- /dev/null
+++ b/src/BUILDSYSTEM_TODO.md
@@ -0,0 +1,103 @@
+# Build System Cleanup — Open Questions & TODOs
+
+These are known issues and open design questions in the build system that need
+to be resolved, particularly for the `D4R_DA_2027` branch targeting Revit 2027 /
+net10.
+
+---
+
+## 1. Platform naming is confusing and redundant
+
+`CS_SDK.props` defines three platforms:
+
+| Platform | TargetFramework | Notes |
+|------------|---------------------|-------|
+| `NET80` | `net8.0-windows` | Interactive Revit build (Revit 2026) |
+| `NET10_DA` | `net8.0-windows` | **Same TFM as NET80 on the 2026 branch — name implies net10 but it's net8** |
+| `NET100` | `net10.0-windows` | Revit 2027 targeting net10 |
+
+For the `D4R_DA_2027` branch (Revit 2027), `NET100` is the primary TFM.
+`NET10_DA` is now genuinely net10 on this branch (unlike on 2026), but the naming
+is still confusing without context.
+
+**Important:** `_DA` in the platform name is a meaningful build profile — it is not just a
+TFM alias. Any platform whose name contains `_DA` triggers these behaviours across multiple projects:
+
+| Project | What `_DA` removes |
+|---|---|
+| `CS_SDK.props` | Defines `DESIGN_AUTOMATION` compile constant |
+| `DynamoRevit.csproj` | Removes `DynamoRevit.cs`, `DynamoRevitApp.cs`, entire `ViewModel/` (interactive startup + ribbon) |
+| `RevitNodesUI.csproj` | Removes all WPF controls, selection dialogs, XAML pages |
+| `RevitServices.csproj` | Removes `Threading/*.cs` (UI thread marshalling, not needed in headless DA) |
+
+So the `_DA` suffix carries real semantic weight. The problem is solely the `NET10`
+prefix on the 2026 branch, which implied net10 when the TFM was actually net8.
+
+**Questions:**
+- Should DA just use `NET100` with a separate property/flag to denote DA vs interactive,
+ rather than a separate platform name?
+- If `NET10_DA` stays, should it be renamed (e.g. `NET100_DA`) to align with the actual TFM name?
+
+---
+
+## 2. Solution file responsibilities are unclear
+
+| Solution | Projects included | Typical build command |
+|-----------------------|--------------------------------|-----------------------|
+| `DynamoRevit.DA.sln` | DADynamoApp + deps only | `/p:Platform=NET10_DA` |
+| `DynamoRevit.All.sln` | Everything incl. tests | `/p:Platform=NET80` or `NET100` |
+
+`DADynamoApp` is **not** listed explicitly in `All.sln` — it is pulled in as a
+transitive project reference from `RevitSystemTests`. This causes the solution to
+build it without a proper platform mapping, which leads to build errors under
+`dotnet build` with .NET SDK 10 (see issue 3 below).
+
+**Questions:**
+- Should `DADynamoApp` be a first-class explicit project in `All.sln`?
+- Should `DA.sln` be a proper subset configuration of `All.sln`, or kept fully separate?
+- Is there a reason DA uses `NET10_DA` platform instead of `NET100`? If not, unify them
+ and remove the extra platform.
+
+---
+
+## 3. `dotnet build` vs VS MSBuild inconsistency
+
+`DynamoRevit.All.sln` builds cleanly with VS MSBuild:
+```
+& "C:\Program Files\Microsoft Visual Studio\18\Professional\MSBuild\Current\Bin\MSBuild.exe" DynamoRevit.All.sln -p:Configuration=Debug -p:Platform=NET100 -m
+```
+
+But fails with `dotnet build` using .NET SDK 10:
+```
+dotnet build DynamoRevit.All.sln -c Debug /p:Platform=NET100
+```
+
+Two known `dotnet build`-only failures:
+
+**a) `DADynamoApp` — `MSB3992: 'RootElementName' is not set`**
+- Root cause: `EnableDynamicLoading=true` causes SDK 10 to set
+ `UseAttributeForTargetFrameworkInfoPropertyNames=true`, which requires
+ `RootElementName` to be set explicitly. VS MSBuild does not have this requirement.
+- Possible fixes: set `false`,
+ or set `DADynamoApp` explicitly.
+
+**b) `DynamoRevitIcons` — `ResGen.exe not supported on .NET Core MSBuild`**
+- Pre-existing issue. The `.resx` code generation step uses ResGen.exe which is
+ not available in the .NET Core MSBuild toolchain.
+- Possible fix: migrate resource generation to use `` without
+ ResGen, or exclude from `dotnet build` paths.
+
+**Question:** Is `dotnet build` a supported/required path in CI, or does CI always
+use VS MSBuild? The `Jenkinsfile` delegates to `DynamoRevitUtils` — need to check
+those build scripts to confirm.
+
+---
+
+## 4. Research needed / action items
+
+- [ ] Check `DynamoRevitUtils` Jenkins scripts: which solution, which platform, `dotnet` or VS MSBuild?
+- [ ] Confirm whether `NET10_DA` is used in any CI job for this branch
+- [ ] Decide on NET10_DA rename/merge with NET100
+- [ ] Decide whether All.sln should be the canonical "build everything" solution
+- [ ] Fix `dotnet build` compatibility if CI requires it (MSB3992 + ResGen)
+- [ ] Add `DADynamoApp` explicitly to `All.sln` with correct platform mapping
diff --git a/src/Config/CS_SDK.props b/src/Config/CS_SDK.props
index f4df74e1b9..072b747ad6 100644
--- a/src/Config/CS_SDK.props
+++ b/src/Config/CS_SDK.props
@@ -4,8 +4,9 @@
x64
false
- NET80;NET100
+ NET80;NET10_DA;NET100
net8.0-windows
+ net10.0-windows
net10.0-windows
17.0
Preview Release
@@ -40,9 +41,13 @@
true
TRACE
+
+ $(DefineConstants);DESIGN_AUTOMATION
+
false
+ all
diff --git a/src/DADynamoApp/DAApplication.cs b/src/DADynamoApp/DAApplication.cs
new file mode 100644
index 0000000000..834c3415c8
--- /dev/null
+++ b/src/DADynamoApp/DAApplication.cs
@@ -0,0 +1,63 @@
+
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.DB;
+using System.Diagnostics;
+using System.Reflection;
+
+namespace DADynamoApp
+{
+ [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
+ [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
+ public class DAApplication : IExternalDBApplication
+ {
+ private string ParentPath;
+ private string CurrentDirectory;
+ private readonly string PythonDllFolder = "pythonDependencies";
+
+ private DAEntrypoint daEntryPoint;
+
+ public ExternalDBApplicationResult OnShutdown(ControlledApplication application)
+ {
+ AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_ProcessExit;
+ AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
+ return daEntryPoint.OnShutdown(application);
+ }
+
+ public ExternalDBApplicationResult OnStartup(ControlledApplication application)
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
+ AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+
+ CurrentDirectory = Directory.GetCurrentDirectory();
+ ParentPath = Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName;
+
+ Console.WriteLine("<> Starting to load DAEntrypoint");
+
+ daEntryPoint ??= new DAEntrypoint();
+
+ return daEntryPoint.OnStartup(application);
+ }
+
+ private static void CurrentDomain_ProcessExit(object? sender, EventArgs e)
+ {
+ Process proc = Process.GetCurrentProcess();
+ Console.WriteLine($"Dynamo exiting with Peak physical memory {proc.PeakWorkingSet64} bytes");
+ if (proc.HasExited)
+ {
+ Console.WriteLine($"Dynamo exiting with code {proc.ExitCode}");
+ }
+ }
+
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Console.WriteLine($"Unhandled exception: {e}");
+ }
+
+ private Assembly? CurrentDomain_AssemblyResolve(object? sender, ResolveEventArgs args)
+ {
+ return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(ParentPath, [Path.Combine(CurrentDirectory, PythonDllFolder)], args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DADynamoApp/DADynamoApp.csproj b/src/DADynamoApp/DADynamoApp.csproj
new file mode 100644
index 0000000000..c9631efb7a
--- /dev/null
+++ b/src/DADynamoApp/DADynamoApp.csproj
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+ enable
+ enable
+ false
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ $(REVITAPI)\RevitAPI.dll
+ False
+
+
+
+
+
+
+
+
+ runtime
+
+
+
+
+
+
+
+
+
+ $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Models.dll
+ False
+
+
+ $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Server.dll
+ False
+
+
+ $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Workflows.dll
+ False
+
+
+
+
+
+
diff --git a/src/DADynamoApp/DAEntrypoint.cs b/src/DADynamoApp/DAEntrypoint.cs
new file mode 100644
index 0000000000..5478e7086a
--- /dev/null
+++ b/src/DADynamoApp/DAEntrypoint.cs
@@ -0,0 +1,597 @@
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.DB;
+using DesignAutomationFramework;
+using DSCPython;
+using Dynamo.Applications;
+using Dynamo.Graph.Nodes;
+using Dynamo.Graph.Workspaces;
+using Dynamo.Models;
+using Dynamo.PythonServices;
+using Dynamo.Scheduler;
+using DynamoPlayer;
+using Greg.AuthProviders;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using RevitServices.Elements;
+using RevitServices.Persistence;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using static Dynamo.Models.DynamoModel;
+using DateTime = System.DateTime;
+
+namespace DADynamoApp
+{
+ public class DAEntrypoint
+ {
+ private DynamoModel model;
+ internal static DynamoPlayerLoggerConfiguration logConfig = new DynamoPlayerLoggerConfiguration() { DynamoLogLevel = Dynamo.Logging.LogLevel.Console, LogLevel = DynamoPlayer.LogLevel.Information };
+ private string DynamoPath;
+ private string DynamoRevitPath;
+ private ControlledApplication controlledApplication;
+
+ // Store event handler references for cleanup
+ private readonly Dictionary evaluationStartedHandler,
+ EventHandler evaluationCompletedHandler,
+ Dictionary[]> nodeHandlers)>
+ workspaceHandlers = [];
+
+ private string LoadMessage;
+ private string WorkItemFolder;
+ private readonly string PythonDllFolder = "pythonDependencies";
+
+
+ private List Updaters = [];
+
+ public ExternalDBApplicationResult OnShutdown(ControlledApplication application)
+ {
+ model?.Dispose();
+
+ controlledApplication.DocumentClosing -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing;
+ controlledApplication.DocumentClosed -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed;
+ controlledApplication.DocumentOpened -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened;
+
+ return ExternalDBApplicationResult.Succeeded;
+ }
+
+ public ExternalDBApplicationResult OnStartup(ControlledApplication application)
+ {
+ controlledApplication = application;
+
+ WorkItemFolder = Directory.GetCurrentDirectory();
+ Console.WriteLine($"<> Work folder is '{WorkItemFolder}'");
+
+ DynamoRevitPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ DynamoPath = Directory.GetParent(DynamoRevitPath).FullName;
+
+ var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location;
+ var hostDir = Path.GetDirectoryName(hostloc);
+
+ Console.WriteLine("<> Starting to load D4DA");
+
+ try
+ {
+ RevitServicesUpdater.Initialize(Updaters);
+ Console.WriteLine("<> D4DA Loaded");
+
+ RevitServices.Transactions.TransactionManager.SetupManager(new RevitServices.Transactions.AutomaticTransactionStrategy());
+ // TODO: do we need element binding in Design Automations?
+ ElementBinder.IsEnabled = true;
+
+ controlledApplication.DocumentClosing += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing;
+ controlledApplication.DocumentClosed += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed;
+ controlledApplication.DocumentOpened += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened;
+
+ DesignAutomationBridge.DesignAutomationReadyEvent += HandleDesignAutomationReadyEvent;
+
+ return ExternalDBApplicationResult.Succeeded;
+ }
+ catch (Exception ex)
+ {
+ return ExternalDBApplicationResult.Failed;
+ }
+ }
+
+ private static string GetRevitContext(Autodesk.Revit.ApplicationServices.Application app)
+ {
+ var r = new Regex(@"\b(Autodesk |Structure |MEP |Architecture )\b");
+ return r.Replace(app.VersionName, "");
+ }
+
+ ///
+ /// Extracts the 'token' value from the work item JSON content.
+ /// This is robust to casing differences and supports BoundArguments as an object.
+ /// Returns null if token cannot be found.
+ ///
+ private string? ExtractTokenFromWorkItem(string workItemContent)
+ {
+ if (string.IsNullOrWhiteSpace(workItemContent)) return null;
+
+ try
+ {
+ var job = JObject.Parse(workItemContent);
+
+ // Find BoundArguments (case-insensitive)
+ JToken? boundToken = null;
+ if (!job.TryGetValue("BoundArguments", out boundToken))
+ {
+ foreach (var prop in job.Properties())
+ {
+ if (string.Equals(prop.Name, "BoundArguments", StringComparison.OrdinalIgnoreCase))
+ {
+ boundToken = prop.Value;
+ break;
+ }
+ }
+ }
+
+ if (boundToken == null) return null;
+
+ // If it's an object, try direct lookup
+ if (boundToken.Type == JTokenType.Object)
+ {
+ var boundObj = (JObject)boundToken;
+
+ // try exact key 'token' then case-insensitive
+ if (boundObj.TryGetValue("adsk3LeggedToken", out var tokVal))
+ {
+ return tokVal.Type == JTokenType.String ? tokVal.Value() : tokVal.ToString();
+ }
+
+ foreach (var prop in boundObj.Properties())
+ {
+ if (string.Equals(prop.Name, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase))
+ {
+ return prop.Value.Type == JTokenType.String ? prop.Value.Value() : prop.Value.ToString();
+ }
+ }
+ }
+
+ // Fallback: convert to dictionary and search case-insensitively
+ var boundDict = boundToken.ToObject>();
+ if (boundDict != null)
+ {
+ foreach (var kv in boundDict)
+ {
+ if (string.Equals(kv.Key, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase))
+ {
+ return kv.Value.Type == JTokenType.String ? kv.Value.Value() : kv.Value.ToString();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"ExtractTokenFromWorkItem failed: {ex.Message}");
+ }
+
+ return null;
+ }
+
+ public void HandleDesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e)
+ {
+ Console.WriteLine("<> DA event raised.");
+
+ var workItemId = Environment.ExpandEnvironmentVariables("%DAS_WORKITEM_ID%");
+
+ Console.WriteLine($"<> WorkItemId is '{workItemId}'");
+
+ var workItemFileName = $"{workItemId}_job.das";
+ var workItemExists = File.Exists(workItemFileName);
+ Console.WriteLine($"Looking for WorkItem file at '{workItemFileName}', exists: {workItemExists}");
+ if (workItemExists)
+ {
+ var workItemContent = File.ReadAllText(workItemFileName);
+
+ var token = ExtractTokenFromWorkItem(workItemContent);
+ if (!string.IsNullOrEmpty(token))
+ {
+ Console.WriteLine($"<> Extracted token from workItem content.");
+ }
+ }
+
+ // Local Change
+ //WorkItemFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+
+ var dynTempDir = Path.Combine(WorkItemFolder, "dyn_tmp");
+ var app = e.DesignAutomationData?.RevitApp;
+ Console.WriteLine("<> Preparing Dynamo model. Vers 1");
+
+ SetupDARequest? setupReq = null;
+ var setupReqPath = Path.Combine(WorkItemFolder, "setup.json");
+ if (File.Exists(setupReqPath))
+ {
+ try
+ {
+ var setupRequest = File.ReadAllText(setupReqPath);
+ Console.WriteLine(setupRequest);
+
+ setupReq = JsonConvert.DeserializeObject(setupRequest, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+
+ // Ensure we have a pre-built graph output folder.
+ var graphOutputFolder = Path.Combine(WorkItemFolder, "output");
+ try
+ {
+ //The output folder is basically a feature that we provide to DAAS_DA users.
+ //It offers an out of the box place where graphs can produce data / content(ex.images, xml reports etc).
+ //If creation of the folder fails, then most likely the graph execution will have nodes that fail and will report those nodes back to the user. ALso the output.zip file will not be sent back to the user.
+ //This ootb "output" folder feature may be scrapped for something more generic in the future
+ Console.WriteLine("Checking for output folder");
+ if (!Directory.Exists(graphOutputFolder))
+ {
+ Console.WriteLine("Output folder does not exist. Creating..");
+ Directory.CreateDirectory(graphOutputFolder);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Failed to create output folder. {ex.Message}");
+ }
+
+ Document? doc = null;
+ var cModel = setupReq?.OpenCloudModelLocation;
+ if (cModel != null)
+ {
+ try
+ {
+ Console.WriteLine($"Opening cloud model with Region: {cModel.Region}, Project: {cModel.ProjectGuid}, Model: {cModel.ModelGuid}");
+
+ var cloudModelPath = ModelPathUtils.ConvertCloudGUIDsToCloudPath(cModel.Region, cModel.ProjectGuid, cModel.ModelGuid);
+ Console.WriteLine(doc == null ? $"Cloud model path is {JsonConvert.SerializeObject(cloudModelPath)}" : "doc is not null before opening cloud model");
+ doc = app?.OpenDocumentFile(cloudModelPath, new OpenOptions());
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+ else if (setupReq?.LocalModelFileName != null)
+ {
+ try
+ {
+ var localModelPath = Path.Combine(WorkItemFolder, setupReq.LocalModelFileName);
+ Console.WriteLine($"Opening local model at {localModelPath}");
+ doc = app?.OpenDocumentFile(localModelPath);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+ else
+ {
+ doc = e.DesignAutomationData?.RevitDoc;
+ }
+
+ // Startup a new project, maybe an option we can have ?
+ //app.NewProjectDocument(Autodesk.Revit.DB.UnitSystem.Metric);
+
+ if (doc == null) throw new InvalidOperationException("Could not open revit document.");
+
+ var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location;
+ var asmLocation = controlledApplication.SharedComponentsLocation;
+ Console.WriteLine($"using asm at location {asmLocation}");
+ Console.WriteLine($"Is Loaded {LoadMessage}");
+
+ // need this for cloud, does not work on local
+ var userDataFolder = Path.Combine(dynTempDir, "Dynamo Revit");
+ var commonDataFolder = Path.Combine(dynTempDir, "Dynamo");
+
+ DocumentManager.Instance.PrepareForDesignAutomation(app);
+
+ var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(asmLocation, DynamoPath);
+ var geometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(DynamoPath, loadedLibGVersion);
+
+ PreInstallPythonDependencies();
+
+ model = Dynamo.Applications.Models.RevitDynamoModel.Start(
+ new DefaultStartConfiguration
+ {
+ DynamoCorePath = DynamoPath,
+ DynamoHostPath = DynamoRevitPath,
+ GeometryFactoryPath = geometryFactoryPath,
+ PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder),
+ Context = GetRevitContext(app),
+ AuthProvider = new RevitOAuth2Provider(SynchronizationContext.Current ?? new SynchronizationContext()),
+ ProcessMode = TaskProcessMode.Synchronous,
+ CLIMode = true,
+ IsHeadless = true,
+ IsServiceMode = true,
+ Logger = new DALogger(WorkItemFolder)
+ });
+
+ LoadMessage = model != null ? "loaded" : "no loaded";
+
+ SetupProfilingHandlers(model);
+
+ var playerHost = new PlayerHostDynamoDefault(model, new DynamoPlayerLogger(logConfig));
+ var workflows = new DynamoModelWorkflows(
+ playerHost,
+ new DynamoPlayerLogger(logConfig));
+
+ var controller = new DynamoControllerImplementation(playerHost, workflows,
+ new DynamoPlayerLogger(logConfig));
+
+ DynamoPlayerLogger.Initialize(playerHost);
+
+ workflows.LoadDependencies(new GraphTarget() { DependenciesPath = WorkItemFolder });
+
+ var dynHandler = new Handler(playerHost, [new DARunGraphController(controller, model, WorkItemFolder)]);
+
+ var runContent = File.ReadAllText(Path.Combine(WorkItemFolder, "run.json"));
+ var testFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+
+ var output = string.Empty;
+ try
+ {
+ var res = dynHandler.HandleRoute("POST", "/v1/graph/run", runContent);
+ output = res.Result;
+
+ // Force transaction close for now.
+ // This is already called on RevitDynamoModel.OnEvaluationCompleted.
+ // TODO: figure out if this is required here (I noticed, a couple of times, saving the rvt failed after running a graph)
+ // ex. Operation is not permitted when there is any open sub-transaction, transaction, or transaction group.
+ // DYN-10310
+ RevitServices.Transactions.TransactionManager.Instance?.ForceCloseTransaction();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+
+ Console.WriteLine(output);
+ File.WriteAllText(Path.Combine(WorkItemFolder, "result.json"), output);
+
+ // Default, save the rvt
+ bool saveRvt = setupReq?.GenerateOutputModel ?? true;
+ Console.WriteLine($"{nameof(saveRvt)} is set to {saveRvt}");
+ if (saveRvt)
+ {
+ try
+ {
+ if (doc.IsModelInCloud)
+ {
+ Console.WriteLine("Document is in cloud.");
+ if (doc.IsWorkshared) // work-shared/C4R model
+ {
+ Console.WriteLine("Document is C4R.");
+ // Syncronize with central
+ //SynchronizeWithCentralOptions swc = new SynchronizeWithCentralOptions();
+ //swc.SetRelinquishOptions(new RelinquishOptions(/*relinquishAll*/true));// Should this be configurable?
+ //doc.SynchronizeWithCentral(new TransactWithCentralOptions(), swc);
+
+ // Save the project locally (this will detach the model from the cloud, but we will re-upload at a new location)
+ doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName));
+ }
+ else
+ {// Single user cloud model
+ Console.WriteLine("Document is single-user cloud model.");
+
+ // Save the project locally (this will detach the model from the cloud, but we will re-upload at a new location)
+ doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName));
+
+ /* TODO: figure out if we need to make this work and how.
+
+ doc.SaveCloudModel();
+
+ Console.WriteLine($"uploading with token {token}");
+ // TODO: For single-user cloud models, we need to publish the model after saving so that the changes are reflected in the cloud.
+ var cmPath = doc.GetCloudModelPath();
+ var dmClient = new DataManagementClient(null, new StaticAuthenticationProvider(token));
+ var projId = "b." + setupReq.SaveCloudModelLocation.AccountId;
+
+ var publishTask = dmClient.ExecutePublishModelAsync(projId, new PublishModelPayload()
+ {
+ Type = TypeCommands.Commands,
+ Attributes = new PublishModelPayloadAttributes()
+ {
+ Extension = new PublishModelPayloadAttributesExtension()
+ {
+ Type = TypeCommandtypePublishmodel.CommandsautodeskBim360C4RModelPublish,
+ VarVersion = "1.0.0"
+ }
+ },
+ Relationships = new PublishModelPayloadRelationships()
+ {
+ Resources = new PublishModelPayloadRelationshipsResources()
+ {
+ Data = new List
+ {
+ new PublishModelPayloadRelationshipsResourcesData()
+ {
+ Id = cmPath.GetModelGUID().ToString(),
+ Type = TypeItem.Items
+ }
+ }
+ }
+ }
+ });
+
+ publishTask.Wait();
+ PublishModel respo = publishTask.Result;
+ Console.WriteLine($"Publish result: {JsonConvert.SerializeObject(respo)}");
+ */
+ }
+ }
+ else
+ {
+ /* TODO: Figure ou tif this is useful.
+ var newLoc = setupReq?.SaveCloudModelLocation;
+ if (newLoc != null)
+ {
+ Console.WriteLine($"Saving to new cloud model location with AccountId: {newLoc.AccountId}, ProjectId: {newLoc.ProjectId}, FolderId: {newLoc.FolderId}, ModelName: {newLoc.ModelName}");
+ doc.SaveAsCloudModel(newLoc.AccountId, newLoc.ProjectId, newLoc.FolderId, newLoc.ModelName ?? Path.GetFileName(doc.PathName));
+ }*/
+
+ // Save locally
+ doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName), new SaveAsOptions() { OverwriteExistingFile = true });
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+
+ try
+ {
+ // If the out put folder exists and is empty, then delete it so we don't generate empty output zip files.
+ if (Directory.Exists(graphOutputFolder) && !Directory.EnumerateFileSystemEntries(graphOutputFolder).Any())
+ {
+ Console.WriteLine("The output folder is empty.");
+ Directory.Delete(graphOutputFolder);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Failed to delete the empty output folder. {ex.Message}");
+ }
+
+ e.Succeeded = true;
+ }
+
+ private void SetupProfilingHandlers(DynamoModel model)
+ {
+ model.WorkspaceOpened += ws =>
+ {
+ if (ws is not HomeWorkspaceModel homeWorkspace) return;
+
+ var nodeHandlers = new Dictionary[]>();
+
+ EventHandler evaluationStartedHandler = (sender, args) =>
+ {
+ homeWorkspace.EngineController.EnableProfiling(true, homeWorkspace, homeWorkspace.Nodes);
+ model.Logger.Log($"Profiling enabled for {homeWorkspace.Name} dynamo workspace");
+ };
+
+ EventHandler evaluationCompletedHandler = (sender, args) =>
+ {
+ if (workspaceHandlers.TryGetValue(homeWorkspace, out var handlers))
+ {
+ CleanupWorkspaceHandlers(homeWorkspace, handlers.evaluationStartedHandler, handlers.evaluationCompletedHandler, handlers.nodeHandlers);
+ }
+ };
+
+ foreach (var node in homeWorkspace.Nodes)
+ {
+ Action beginHandler = nm =>
+ {
+ model.Logger.Log($"Node {nm.Name} started execution.");
+ };
+
+ Action endHandler = nm =>
+ {
+ if (model.Logger is DALogger daLogger)
+ {
+ var outputSummary = daLogger.SerializeNodeOutputs(nm, homeWorkspace.EngineController);
+ if (!string.IsNullOrEmpty(outputSummary))
+ model.Logger.Log($"Node {nm.Name} outputs: {outputSummary}");
+
+ var runtimeStatus = homeWorkspace.EngineController.LiveRunnerRuntimeCore.RuntimeStatus;
+ var nodeMessages = DALogger.GetNodeMessages(runtimeStatus, nm.GUID);
+ if (!string.IsNullOrEmpty(nodeMessages))
+ model.Logger.Log($"Node {nm.Name} messages: {nodeMessages}");
+ }
+
+ model.Logger.Log($"Node {nm.Name} finished execution.");
+ };
+
+ node.NodeExecutionBegin += beginHandler;
+ node.NodeExecutionEnd += endHandler;
+
+ nodeHandlers[node] = [beginHandler, endHandler];
+ }
+
+ homeWorkspace.EvaluationStarted += evaluationStartedHandler;
+ homeWorkspace.EvaluationCompleted += evaluationCompletedHandler;
+
+ workspaceHandlers[homeWorkspace] = (evaluationStartedHandler, evaluationCompletedHandler, nodeHandlers);
+ };
+ }
+
+ private void CleanupWorkspaceHandlers(
+ HomeWorkspaceModel workspace,
+ EventHandler? evaluationStartedHandler,
+ EventHandler? evaluationCompletedHandler,
+ Dictionary[]> nodeHandlers)
+ {
+ if (evaluationStartedHandler != null)
+ workspace.EvaluationStarted -= evaluationStartedHandler;
+
+ if (evaluationCompletedHandler != null)
+ workspace.EvaluationCompleted -= evaluationCompletedHandler;
+
+ foreach (var kvp in nodeHandlers)
+ {
+ var node = kvp.Key;
+ var nodeHandlerArray = kvp.Value;
+
+ if (nodeHandlerArray.Length >= 2)
+ {
+ node.NodeExecutionBegin -= nodeHandlerArray[0];
+ node.NodeExecutionEnd -= nodeHandlerArray[1];
+ }
+ }
+
+ workspaceHandlers.Remove(workspace);
+ }
+
+ private void PreInstallPythonDependencies()
+ {
+ try
+ {
+ // Preload all python assemblies at the PythonDllFolder.
+ foreach (var pyDll in Directory.EnumerateFiles(Path.Combine(WorkItemFolder, PythonDllFolder), "*.dll"))
+ {
+ Assembly.LoadFrom(pyDll);
+ }
+
+ var pyIncluded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name == "Python.Included");
+ if (pyIncluded == null)
+ {
+ throw new Exception("Could not find Python.Included assembly");
+ }
+ var type = pyIncluded.GetType("Python.Included.Installer");
+ if (type == null)
+ {
+ throw new Exception("null Installer type");
+ }
+ var property = type.GetProperty("INSTALL_PATH", BindingFlags.Public | BindingFlags.Static);
+ if (property == null)
+ {
+ throw new Exception("null INSTALL_PATH property");
+ }
+
+ // Set the python install location to the DA workfolder (that is the only place we have wrie access)
+ property.SetValue(null, WorkItemFolder);
+
+ // Dynamo's 'VerifyEngineReferences' wants all the PythonEngine's dependencies to be in the Dynamo folder.
+ // Temporary until we fix it on the Dynamo side.
+ if (PythonEngineManager.Instance.AvailableEngines.Count == 0)
+ {
+ PropertyInfo instanceProp = typeof(CPythonEvaluator).GetProperty("Instance", BindingFlags.NonPublic | BindingFlags.Static);
+ if (instanceProp != null)
+ {
+ PythonEngine engine = (PythonEngine)instanceProp.GetValue(null);
+ if (engine == null)
+ {
+ throw new Exception($"Could not get a valid PythonEngine instance");
+ }
+
+ PythonEngineManager.Instance.AvailableEngines.Add(engine);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Could not setup python " + ex.Message);
+ }
+ }
+ }
+}
diff --git a/src/DADynamoApp/DALogger.cs b/src/DADynamoApp/DALogger.cs
new file mode 100644
index 0000000000..a40d6da0ee
--- /dev/null
+++ b/src/DADynamoApp/DALogger.cs
@@ -0,0 +1,160 @@
+using Dynamo.Configuration;
+using Dynamo.Graph.Nodes;
+using Dynamo.Logging;
+using ProtoCore;
+using System.Reflection;
+using System.Text.Json;
+
+namespace DADynamoApp;
+
+///
+/// Logger for DynamoRevit Design Automation runs. Writes all log messages to stdout
+/// with a UTC timestamp. Also provides node output serialization for profiling.
+///
+public class DALogger : DynamoLogger
+{
+ // Cached reflection members for Player's WatchNodeHandler methods
+ private static MethodInfo? getNodeValueMethod;
+ private static MethodInfo? processWatchTreeMethod;
+
+ private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault
+ };
+
+ public DALogger(string logDirectory)
+ : base(new DebugSettings(), logDirectory, false, true, false)
+ {
+ Console.WriteLine($"DALogger initialized. LogPath: {this.LogPath}");
+ }
+
+ protected override void Log(string message, LogLevel level, bool reportModification)
+ {
+ Console.WriteLine($"{DateTime.UtcNow:u} : {message}");
+ base.Log(message, level, reportModification);
+ }
+
+ ///
+ /// Serializes node output values by getting data from the runtime mirror
+ /// and using Player's serialization logic via reflection.
+ ///
+ public string SerializeNodeOutputs(NodeModel node, Dynamo.Engine.EngineController engineController, int maxLength = 2000)
+ {
+ try
+ {
+ var variableName = node.AstIdentifierForPreview.Value;
+ if (string.IsNullOrEmpty(variableName)) return string.Empty;
+
+ var runtimeMirror = engineController.GetMirror(variableName);
+ if (runtimeMirror == null) return string.Empty;
+
+ var mirrorData = runtimeMirror.GetData();
+ if (mirrorData == null) return string.Empty;
+
+ var valueContainer = GetNodeValueStringFromMirrorData(mirrorData);
+ if (valueContainer == null) return string.Empty;
+
+ var valueString = JsonSerializer.Serialize(valueContainer, jsonOptions);
+ if (string.IsNullOrEmpty(valueString)) return string.Empty;
+
+ if (valueString.Length > maxLength)
+ valueString = valueString.Substring(0, maxLength) + $"... (truncated from {valueString.Length} chars)";
+
+ return valueString;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error serializing node outputs: {ex}");
+ return string.Empty;
+ }
+ }
+
+ private static object? GetNodeValueStringFromMirrorData(object mirrorData)
+ {
+ try
+ {
+ var obj = GetNodeValueViaReflection(mirrorData);
+ if (obj == null) return null;
+
+ if (obj is System.Collections.IList list && list.Count == 0)
+ return new { Value = "Empty List" };
+
+ if (obj is System.Collections.IDictionary dict && dict.Count == 0)
+ return new { Value = "Empty Dictionary" };
+
+ return ProcessWatchTreeViaReflection(obj);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error in GetNodeValueStringFromMirrorData: {ex}");
+ return null;
+ }
+ }
+
+ private static object? GetNodeValueViaReflection(object mirrorData)
+ {
+ if (getNodeValueMethod == null)
+ {
+ var assembly = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows")
+ ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found");
+
+ var type = assembly.GetType("DynamoPlayer.WatchNodeHandler")
+ ?? throw new InvalidOperationException("WatchNodeHandler type not found");
+
+ getNodeValueMethod = type.GetMethod("GetNodeValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
+ ?? throw new InvalidOperationException("GetNodeValue method not found");
+ }
+
+ try
+ {
+ return getNodeValueMethod.Invoke(null, [mirrorData]);
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw new InvalidOperationException($"GetNodeValue invocation failed: {ex.InnerException?.Message}", ex.InnerException);
+ }
+ }
+
+ private static object? ProcessWatchTreeViaReflection(object obj)
+ {
+ if (processWatchTreeMethod == null)
+ {
+ var assembly = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows")
+ ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found");
+
+ var type = assembly.GetType("DynamoPlayer.WatchNodeHandler")
+ ?? throw new InvalidOperationException("WatchNodeHandler type not found");
+
+ processWatchTreeMethod = type.GetMethod("ProcessWatchTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
+ ?? throw new InvalidOperationException("ProcessWatchTree method not found");
+ }
+
+ try
+ {
+ return processWatchTreeMethod.Invoke(null, [obj, null]);
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw new InvalidOperationException($"ProcessWatchTree invocation failed: {ex.InnerException?.Message}", ex.InnerException);
+ }
+ }
+
+ ///
+ /// Gets runtime warnings for a specific node as a JSON string.
+ ///
+ internal static string GetNodeMessages(RuntimeStatus runtimeStatus, Guid nodeId)
+ {
+ var warnings = new List();
+
+ foreach (var warning in runtimeStatus.Warnings)
+ {
+ if (warning.GraphNodeGuid == nodeId)
+ warnings.Add(warning.Message);
+ }
+
+ return JsonSerializer.Serialize(new { warnings = warnings.Count > 0 ? warnings : null }, jsonOptions);
+ }
+}
diff --git a/src/DADynamoApp/DARunGraphController.cs b/src/DADynamoApp/DARunGraphController.cs
new file mode 100644
index 0000000000..e061599b44
--- /dev/null
+++ b/src/DADynamoApp/DARunGraphController.cs
@@ -0,0 +1,33 @@
+using Dynamo.Models;
+using DynamoPlayer;
+
+namespace DADynamoApp
+{
+ internal class DARunGraphController : DynamoController
+ {
+ IDynamoController implementation;
+ string workFolder = string.Empty;
+ DynamoModel model;
+
+ public DARunGraphController(IDynamoController implementation, DynamoModel model, string workFolder) : base(implementation)
+ {
+ this.workFolder = workFolder;
+ this.implementation = implementation;
+ this.model = model;
+ }
+
+ [Route("graph/run", Name = "post-graph-run")]
+ public new Task PostGraphRun([FromBody] RunGraph body)
+ {
+ if (body.Target is CurrentGraphTarget)
+ {
+ this.model.OpenFileFromPath(Path.Combine(workFolder, "run.dyn"));
+ }
+ else if (body.Target is PathGraphTarget pGraphTarget)
+ {
+ pGraphTarget.Path = Path.Combine(this.workFolder, pGraphTarget.Path);
+ }
+ return implementation.PostGraphRunAsync(body);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DADynamoApp/SetupDARequest.cs b/src/DADynamoApp/SetupDARequest.cs
new file mode 100644
index 0000000000..ab16a6a8f7
--- /dev/null
+++ b/src/DADynamoApp/SetupDARequest.cs
@@ -0,0 +1,72 @@
+using Newtonsoft.Json;
+
+namespace DADynamoApp
+{
+ ///
+ /// Configuration details for a cloud model.
+ ///
+ internal class OpenCloudModelLocation
+ {
+ ///
+ /// Represents the region where the cloud model is hosted.
+ ///
+ public string Region;
+
+ ///
+ /// Represents the unique identifier for a project.
+ ///
+ public Guid ProjectGuid;
+
+ ///
+ /// Represents the unique identifier for the model.
+ ///
+ public Guid ModelGuid;
+ }
+
+ ///
+ /// Represents the save location for the current DA work model.
+ ///
+ internal class SaveCloudModelLocation
+ {
+ ///
+ /// Gets or sets the unique identifier for the account.
+ ///
+ public Guid AccountId { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier for the project.
+ ///
+ public Guid ProjectId { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier for the folder.
+ ///
+ public string FolderId { get; set; }
+
+ ///
+ /// Gets or sets the name of the model to be created on the save operation.
+ ///
+ public string ModelName { get; set; } = string.Empty;
+ }
+
+ ///
+ /// Request body used to setup aspects of the Design Automation environment.
+ ///
+ internal class SetupDARequest
+ {
+ //
+ // Summary:
+ // Save the revit document to the default result.rvt file.
+ [JsonProperty(nameof(GenerateOutputModel), Required = Required.DisallowNull, NullValueHandling = NullValueHandling.Ignore)]
+ public bool GenerateOutputModel { get; set; } = false;
+
+ ///
+ /// Gets or sets the name of the Revit model file.
+ ///
+ public string LocalModelFileName { get; set; } = string.Empty;
+
+ public OpenCloudModelLocation? OpenCloudModelLocation { get; set; } = null;
+
+ public SaveCloudModelLocation? SaveCloudModelLocation { get; set; } = null;
+ }
+}
diff --git a/src/DynamoRevit.All.sln b/src/DynamoRevit.All.sln
index f6ddc375d4..11ff170857 100644
--- a/src/DynamoRevit.All.sln
+++ b/src/DynamoRevit.All.sln
@@ -61,6 +61,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamoRevitIcons", "DynamoRevitIcons\DynamoRevitIcons.csproj", "{A31E274C-524A-40CA-85FF-595D3DB53777}"
ProjectSection(ProjectDependencies) = postProject
+ {92A46535-D870-4E1A-AED0-7492789E9C4A} = {92A46535-D870-4E1A-AED0-7492789E9C4A}
{133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016}
EndProjectSection
EndProject
diff --git a/src/DynamoRevit.DA.sln b/src/DynamoRevit.DA.sln
new file mode 100644
index 0000000000..a6c778b0fc
--- /dev/null
+++ b/src/DynamoRevit.DA.sln
@@ -0,0 +1,99 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32328.378
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{FA7BE306-A3B0-45FA-9D87-0C69E6932C13}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodes", "Libraries\RevitNodes\RevitNodes.csproj", "{0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016}
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodesUI", "Libraries\RevitNodesUI\RevitNodesUI.csproj", "{75940ACC-3708-4526-8D91-7E3365BAF682}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitServices", "Libraries\RevitServices\RevitServices.csproj", "{E4701F9E-41AB-4044-8166-85D924FEB632}"
+ ProjectSection(ProjectDependencies) = postProject
+ {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016}
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrations", "Libraries\Migrations\Migrations.csproj", "{06B9E5B0-7C50-4351-9D88-E159DC25755F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016}
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "AssemblySharedInfoGenerator\AssemblyInfoGenerator.csproj", "{133FC760-5699-46D9-BEA6-E816B5F01016}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4466E6F6-F644-43AB-96B3-5ECE1622E711}"
+ ProjectSection(SolutionItems) = preProject
+ ..\.version = ..\.version
+ ..\CHANGELOG.md = ..\CHANGELOG.md
+ ..\README.md = ..\README.md
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{9568462D-249F-4494-856B-5B25751DB361}"
+ ProjectSection(SolutionItems) = preProject
+ Config.xml = Config.xml
+ Config\CS_SDK.props = Config\CS_SDK.props
+ Config\dynamo-nuget.config = Config\dynamo-nuget.config
+ Config\packages-template.aget = Config\packages-template.aget
+ Config\packages.aget = Config\packages.aget
+ Config\user_local.props = Config\user_local.props
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DADynamoApp", "DADynamoApp\DADynamoApp.csproj", "{66A0E1C8-2514-48B7-8406-536983F57F88}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamoRevit", "DynamoRevit\DynamoRevit.csproj", "{BD7126B6-E716-4024-854F-6DA2CFA25B84}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|NET10_DA = Debug|NET10_DA
+ Release|NET10_DA = Release|NET10_DA
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA
+ {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET10_DA.Build.0 = Debug|NET10_DA
+ {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET10_DA.ActiveCfg = Release|NET10_DA
+ {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET10_DA.Build.0 = Release|NET10_DA
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13}
+ {75940ACC-3708-4526-8D91-7E3365BAF682} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13}
+ {E4701F9E-41AB-4044-8166-85D924FEB632} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13}
+ {06B9E5B0-7C50-4351-9D88-E159DC25755F} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13}
+ {9568462D-249F-4494-856B-5B25751DB361} = {4466E6F6-F644-43AB-96B3-5ECE1622E711}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {757AAA40-191F-4673-9B04-8270A3370BCA}
+ EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ SharedUtilities\SharedUtilities.projitems*{66a0e1c8-2514-48b7-8406-536983f57f88}*SharedItemsImports = 5
+ SharedUtilities\SharedUtilities.projitems*{bd7126b6-e716-4024-854f-6da2cfa25b84}*SharedItemsImports = 5
+ EndGlobalSection
+EndGlobal
diff --git a/src/DynamoRevit/DynamoRevit.cs b/src/DynamoRevit/DynamoRevit.cs
index 475d302b19..f36742255b 100644
--- a/src/DynamoRevit/DynamoRevit.cs
+++ b/src/DynamoRevit/DynamoRevit.cs
@@ -527,34 +527,6 @@ private static void UpdateSystemPathForProcess()
#region Initialization
- ///
- /// DynamoShapeManager.dll is a companion assembly of Dynamo core components,
- /// we do not want a static reference to it (since the Revit add-on can be
- /// installed anywhere that's outside of Dynamo), we do not want a duplicated
- /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath
- /// method, and call it to get the geometry factory assembly path.
- ///
- /// The path where DynamoShapeManager.dll can be
- /// located.
- /// The version of DynamoShapeManager.dll
- /// Returns the full path to geometry factory assembly.
- ///
- public static string GetGeometryFactoryPath(string corePath, Version version)
- {
- var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll");
- var assembly = Assembly.LoadFrom(dynamoAsmPath);
- if (assembly == null)
- throw new FileNotFoundException("File not found", dynamoAsmPath);
-
- var utilities = assembly.GetType("DynamoShapeManager.Utilities");
- var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2");
-
- return (getGeometryFactoryPath.Invoke(null,
- new object[] { corePath, version }) as string);
- }
-
-
-
private static void PreloadDynamoCoreDlls()
{
// Assume Revit Install folder as look for root. Assembly name is compromised.
@@ -611,16 +583,17 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma
// when Dynamo runs on top of Revit we must load the same version of ASM as revit
// so tell Dynamo core we've loaded that version.
- var loadedLibGVersion = PreloadAsmFromRevit();
+ var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation;
+ var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(asmLocation, DynamoRevitApp.DynamoCorePath);
return RevitDynamoModel.Start(
new RevitDynamoModel.RevitStartConfiguration()
{
DynamoCorePath = corePath,
DynamoHostPath = dynamoRevitRoot,
- GeometryFactoryPath = GetGeometryFactoryPath(corePath, loadedLibGVersion),
- PathResolver = new RevitPathResolver(userDataFolder, corePath),
+ GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(corePath, loadedLibGVersion),
+ PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder),
Context = GetRevitContext(commandData),
SchedulerThread = new RevitSchedulerThread(commandData.Application),
StartInTestMode = isAutomationMode,
@@ -631,61 +604,6 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma
});
}
- internal static Version PreloadAsmFromRevit()
- {
- var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation;
-
- Version libGVersion = findRevitASMVersion(asmLocation);
- var dynCorePath = DynamoRevitApp.DynamoCorePath;
- // Get the corresponding libG preloader location for the target ASM loading version.
- // If there is exact match preloader version to the target ASM version, use it,
- // otherwise use the closest below.
- var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynCorePath);
-
- // [Tech Debt] (Will refactor the code later)
- // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo.
- Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation);
- DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation);
- return preLoadLibGVersion;
- }
-
- // [Tech Debt] (Will refactor the code later)
- ///
- /// Return the preload version of LibG.
- ///
- ///
- ///
- internal static Version PreloadLibGVersion(string preloaderLocation)
- {
- preloaderLocation = new DirectoryInfo(preloaderLocation).Name;
- var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase);
-
- var match = regExp.Match(preloaderLocation);
- if (match.Groups.Count == 4)
- {
- return new Version(
- Convert.ToInt32(match.Groups[1].Value),
- Convert.ToInt32(match.Groups[2].Value),
- Convert.ToInt32(match.Groups[3].Value));
- }
-
- return new Version();
- }
-
- ///
- /// Returns the version of ASM which is installed with Revit at the requested path.
- /// This version number can be used to load the appropriate libG version.
- ///
- /// path where asm dlls are located, this is usually the product(Revit) install path
- ///
- internal static Version findRevitASMVersion(string asmLocation)
- {
- var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll");
- var product = lookup.GetProductFromInstallPath(asmLocation);
- var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3);
- return libGversion;
- }
-
private static DynamoViewModel InitializeCoreViewModel(RevitDynamoModel revitDynamoModel)
{
var viewModel = DynamoRevitViewModel.Start(
@@ -1164,116 +1082,4 @@ public static void AddIdleAction(Action a)
}
}
}
-
- ///
- /// Defines parameters used for loading internal Dynamo Revit packages
- ///
- [Serializable()]
- public class InternalPackage
- {
- ///
- /// keeps the path to the node file
- ///
- public string NodePath { get; set; }
-
- ///
- /// keeps the path to the layoutSpecs.json file
- ///
- public string LayoutSpecsPath { get; set; }
-
- ///
- /// keeps paths to additional assembly load paths
- ///
- public List AdditionalAssemblyLoadPaths { get; set; }
- }
- internal static class DynamoRevitInternalNodes
- {
- private const string InternalNodesDir = "nodes";
- private static IEnumerable GetAllInternalPackageFiles()
- {
- string currentAssemblyPath = Assembly.GetExecutingAssembly().Location;
- string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath);
-
- string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir);
- if (false == Directory.Exists(internalNodesDir))
- {
- return new List();
- }
-
- string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir);
-
- List internalPackageFiles = new List();
- foreach (string dir in internalNodesFolders)
- {
- string internalPackageFile = Path.Combine(dir, "internalPackage.xml");
- if (true == File.Exists(internalPackageFile))
- {
- internalPackageFiles.Add(internalPackageFile);
- }
- }
- return internalPackageFiles;
- }
- private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles)
- {
- List internalPackages = new List();
- string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
-
- foreach (string internalPackageFile in internalPackageFiles)
- {
- try
- {
- string internalPackageDir = Path.GetDirectoryName(internalPackageFile);
- using (StreamReader reader = new StreamReader(internalPackageFile))
- {
- XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage));
- InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage;
-
- // convert to absolute path, if needed
- if (false == Path.IsPathRooted(intPackage.NodePath))
- {
- intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath);
- }
-
- // convert to absolute path, if needed
- if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath))
- {
- intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath);
- }
-
- // convert to absolute paths, if needed
- if (null != intPackage.AdditionalAssemblyLoadPaths && intPackage.AdditionalAssemblyLoadPaths.Count > 0)
- {
- intPackage.AdditionalAssemblyLoadPaths = intPackage.AdditionalAssemblyLoadPaths
- .Select(p => !Path.IsPathRooted(p) ? Path.Combine(basePath, p) : p)
- .Where(Path.Exists).ToList();
- }
-
- internalPackages.Add(intPackage);
- }
- }
- catch (Exception)
- {
- Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile));
- }
- }
-
- return internalPackages;
- }
- internal static IEnumerable GetNodesToPreload()
- {
- IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
- return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath);
- }
- internal static IEnumerable GetLayoutSpecsFiles()
- {
- IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
- return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath);
- }
-
- internal static IEnumerable GetAdditionalAssemblyLoadPaths()
- {
- IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
- return ParseinternalPackageFiles(internalPackageFiles).SelectMany(pkg => pkg.AdditionalAssemblyLoadPaths);
- }
- }
-}
\ No newline at end of file
+}
diff --git a/src/DynamoRevit/DynamoRevit.csproj b/src/DynamoRevit/DynamoRevit.csproj
index 2a543c362d..29302bf267 100644
--- a/src/DynamoRevit/DynamoRevit.csproj
+++ b/src/DynamoRevit/DynamoRevit.csproj
@@ -10,40 +10,26 @@
true
- prompt
- 3
- full
$(NoWarn);618
- true
- false
MinimumRecommendedRules.ruleset
- false
- $(BuildDependsOn);AfterBuildMigrated
- if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir)
- DynamoRevitDS
- true
- true
-
-
- None
-
-
- false
- TRACE;DEBUG
- false
-
-
- true
- TRACE
-
-
- true
-
-
- if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir)
- x64
-
+ false
+ $(BuildDependsOn);AfterBuildMigrated
+ if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir)
+ DynamoRevitDS
+ true
+ true
+
+
+ None
+
+
+ true
+
+
+ if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir)
+ x64
+
@@ -81,6 +67,33 @@
Resources.en-US.Designer.cs
+
+
+ $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll
+ $(DYNAMOBUILDPATH)\ProtoCore.dll
+ False
+
+
+ $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll
+ $(DYNAMOBUILDPATH)\DynamoCore.dll
+ False
+
+
+ $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll
+ $(DYNAMOBUILDPATH)\DynamoUtilities.dll
+ False
+
+
+ $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoShapeManager.dll
+ $(DYNAMOBUILDPATH)\DynamoShapeManager.dll
+ False
+
+
+ $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoInstallDetective.dll
+ $(DYNAMOBUILDPATH)\DynamoInstallDetective.dll
+ False
+
+
@@ -98,6 +111,11 @@
+
+
+
+
+
@@ -107,7 +125,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/src/DynamoRevit/DynamoRevitApp.cs b/src/DynamoRevit/DynamoRevitApp.cs
index e6a7b58f39..46d5c0cc0c 100644
--- a/src/DynamoRevit/DynamoRevitApp.cs
+++ b/src/DynamoRevit/DynamoRevitApp.cs
@@ -26,8 +26,6 @@
namespace Dynamo.Applications
{
-
-
[Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual),
Regeneration(RegenerationOption.Manual)]
public class DynamoRevitApp : IExternalApplication
@@ -95,7 +93,6 @@ private static string GetDynamoRoot(string dynamoRevitRoot)
private static string dynamopath;
private static readonly Queue idleActionQueue = new Queue(10);
- private static EventHandlerProxy proxy;
private AddInCommandBinding dynamoCommand;
private Result loadDependentComponents()
@@ -253,9 +250,10 @@ public static void AddIdleAction(Action a)
}
}
+ [Obsolete("This property will be made internal")]
public static EventHandlerProxy EventHandlerProxy
{
- get { return proxy; }
+ get { return EventHandlerProxy.Instance; }
}
// should be handled by the ModelUpdater class. But there are some
@@ -286,28 +284,26 @@ private void SubscribeApplicationEvents()
{
UIControlledApplication.Idling += OnApplicationIdle;
- proxy = new EventHandlerProxy();
-
- UIControlledApplication.ViewActivated += proxy.OnApplicationViewActivated;
- UIControlledApplication.ViewActivating += proxy.OnApplicationViewActivating;
+ UIControlledApplication.ViewActivated += EventHandlerProxy.Instance.OnApplicationViewActivated;
+ UIControlledApplication.ViewActivating += EventHandlerProxy.Instance.OnApplicationViewActivating;
- ControlledApplication.DocumentClosing += proxy.OnApplicationDocumentClosing;
- ControlledApplication.DocumentClosed += proxy.OnApplicationDocumentClosed;
- ControlledApplication.DocumentOpened += proxy.OnApplicationDocumentOpened;
+ ControlledApplication.DocumentClosing += EventHandlerProxy.Instance.OnApplicationDocumentClosing;
+ ControlledApplication.DocumentClosed += EventHandlerProxy.Instance.OnApplicationDocumentClosed;
+ ControlledApplication.DocumentOpened += EventHandlerProxy.Instance.OnApplicationDocumentOpened;
}
private void UnsubscribeApplicationEvents()
{
UIControlledApplication.Idling -= OnApplicationIdle;
- UIControlledApplication.ViewActivated -= proxy.OnApplicationViewActivated;
- UIControlledApplication.ViewActivating -= proxy.OnApplicationViewActivating;
+ UIControlledApplication.ViewActivated -= EventHandlerProxy.Instance.OnApplicationViewActivated;
+ UIControlledApplication.ViewActivating -= EventHandlerProxy.Instance.OnApplicationViewActivating;
- ControlledApplication.DocumentClosing -= proxy.OnApplicationDocumentClosing;
- ControlledApplication.DocumentClosed -= proxy.OnApplicationDocumentClosed;
- ControlledApplication.DocumentOpened -= proxy.OnApplicationDocumentOpened;
+ ControlledApplication.DocumentClosing -= EventHandlerProxy.Instance.OnApplicationDocumentClosing;
+ ControlledApplication.DocumentClosed -= EventHandlerProxy.Instance.OnApplicationDocumentClosed;
+ ControlledApplication.DocumentOpened -= EventHandlerProxy.Instance.OnApplicationDocumentOpened;
- proxy = null;
+ EventHandlerProxy.Instance = null;
}
private void SubscribeAssemblyEvents()
@@ -333,35 +329,7 @@ private void UnsubscribeAssemblyEvents()
///
public static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
{
- var assemblyPath = string.Empty;
- var assemblyName = new AssemblyName(args.Name).Name + ".dll";
-
- try
- {
- assemblyPath = Path.Combine(DynamoRevitApp.DynamoCorePath, assemblyName);
- if(File.Exists(assemblyPath))
- {
- return Assembly.LoadFrom(assemblyPath);
- }
-
- var assemblyLocation = Assembly.GetExecutingAssembly().Location;
- var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
-
- // Try "Dynamo 0.x\Revit_20xx" folder first...
- assemblyPath = Path.Combine(assemblyDirectory, assemblyName);
- if (!File.Exists(assemblyPath))
- {
- // If assembly cannot be found, try in "Dynamo 0.x" folder.
- var parentDirectory = Directory.GetParent(assemblyDirectory);
- assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName);
- }
-
- return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null);
- }
- catch (Exception ex)
- {
- throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex);
- }
+ return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(DynamoCorePath, null, args);
}
private void SubscribeDocumentChangedEvent()
diff --git a/src/DynamoRevit/Models/RevitDynamoModel.cs b/src/DynamoRevit/Models/RevitDynamoModel.cs
index bb5e59564f..b2b160d954 100644
--- a/src/DynamoRevit/Models/RevitDynamoModel.cs
+++ b/src/DynamoRevit/Models/RevitDynamoModel.cs
@@ -8,8 +8,11 @@
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
+#if !DESIGN_AUTOMATION
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Events;
+using RevitServices.Threading;
+#endif
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Nodes.ZeroTouch;
using Dynamo.Graph.Workspaces;
@@ -27,7 +30,6 @@
using RevitServices.Elements;
using RevitServices.Materials;
using RevitServices.Persistence;
-using RevitServices.Threading;
using RevitServices.Transactions;
using Category = Revit.Elements.Category;
using Element = Autodesk.Revit.DB.Element;
@@ -39,7 +41,9 @@ public class RevitDynamoModel : DynamoModel
{
public interface IRevitStartConfiguration : IStartConfiguration
{
+#if !DESIGN_AUTOMATION
DynamoRevitCommandData ExternalCommandData { get; set; }
+#endif
}
public struct RevitStartConfiguration : IRevitStartConfiguration
@@ -55,7 +59,9 @@ public struct RevitStartConfiguration : IRevitStartConfiguration
public string GeometryFactoryPath { get; set; }
public IAuthProvider AuthProvider { get; set; }
public string PackageManagerAddress { get; set; }
+#if !DESIGN_AUTOMATION
public DynamoRevitCommandData ExternalCommandData { get; set; }
+#endif
public IEnumerable Extensions { get; set; }
public TaskProcessMode ProcessMode { get; set; }
//the property will contain revit host information, to be passed on to Dynamo.
@@ -69,9 +75,10 @@ public struct RevitStartConfiguration : IRevitStartConfiguration
///
private bool updateCurrentUIDoc;
+#if !DESIGN_AUTOMATION
private readonly DynamoRevitCommandData externalCommandData;
-
- #region Events
+#endif
+#region Events
public event EventHandler RevitDocumentChanged;
@@ -155,7 +162,7 @@ protected override void OnWorkspaceAdded(WorkspaceModel workspace)
var dm = DocumentManager.Instance;
if (dm.CurrentDBDocument != null)
{
- SetRunEnabledBasedOnContext(dm.CurrentUIDocument.ActiveView);
+ SetRunEnabledBasedOnContext(dm.CurrentDBDocument.ActiveView);
}
}
@@ -185,7 +192,7 @@ public bool IsInMatchingDocumentContext
return false; // There's no current document stored.
// Selection is not allowed in perspective view mode.
- var view3D = dm.CurrentUIDocument.ActiveView as View3D;
+ var view3D = dm.CurrentDBDocument.ActiveView as View3D;
if ((view3D != null) && view3D.IsPerspective)
return false; // There's no view, or in perspective view.
@@ -216,12 +223,12 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) :
base(configuration)
{
DisposeLogic.IsShuttingDown = false;
-
+#if !DESIGN_AUTOMATION
externalCommandData = configuration.ExternalCommandData;
-
+ SubscribeApplicationEvents(configuration.ExternalCommandData);
+#endif
SubscribeRevitServicesUpdaterEvents();
- SubscribeApplicationEvents(configuration.ExternalCommandData);
InitializeDocumentManager();
SubscribeDocumentManagerEvents();
SubscribeTransactionManagerEvents();
@@ -230,7 +237,7 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) :
}
- #endregion
+#endregion
#region trace reconciliation
@@ -325,12 +332,14 @@ public override void PostTraceReconciliation(Dictionary> orph
}
else
{
+#if !DESIGN_AUTOMATION
// Delete all the orphans.
IdlePromise.ExecuteOnIdleAsync(
() =>
{
DeleteOrphanedElements(orphanedIds, Logger);
});
+#endif
}
}
@@ -422,7 +431,7 @@ private static void DeleteOrphanedElements(IEnumerable orphanedIds, ILog
}
}
- #endregion
+#endregion
#region Initialization
@@ -473,7 +482,7 @@ private void SetupPythonEngine(PythonEngine engine)
engine.EvaluationStarted += OnPythonEvalStart;
}
- catch(FileNotFoundException ex)
+ catch (FileNotFoundException ex)
{
Logger.Log(ex);
}
@@ -540,6 +549,7 @@ private void SetupPython()
internal void InitializeDocumentManager()
{
+#if !DESIGN_AUTOMATION
// Set the intitial document.
var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument;
if (activeUIDocument != null)
@@ -549,6 +559,7 @@ internal void InitializeDocumentManager()
OnRevitDocumentChanged();
}
+#endif
}
private static void InitializeMaterials()
@@ -556,10 +567,14 @@ private static void InitializeMaterials()
// Ensure that the current document has the needed materials
// and graphic styles to support visualization in Revit.
var mgr = MaterialsManager.Instance;
+#if !DESIGN_AUTOMATION
IdlePromise.ExecuteOnIdleAsync(mgr.InitializeForActiveDocumentOnIdle);
+#else
+ mgr.InitializeForActiveDocumentOnIdle();
+#endif
}
- #endregion
+#endregion
#region Event subscribe/unsubscribe
@@ -595,6 +610,7 @@ private void UnsubscribeDocumentManagerEvents()
DocumentManager.OnLogError -= Logger.Log;
}
+#if !DESIGN_AUTOMATION
private bool hasRegisteredApplicationEvents;
private void SubscribeApplicationEvents(DynamoRevitCommandData commandData)
{
@@ -603,11 +619,11 @@ private void SubscribeApplicationEvents(DynamoRevitCommandData commandData)
return;
}
- DynamoRevitApp.EventHandlerProxy.ViewActivating += OnApplicationViewActivating;
- DynamoRevitApp.EventHandlerProxy.ViewActivated += OnApplicationViewActivated;
- DynamoRevitApp.EventHandlerProxy.DocumentClosing += OnApplicationDocumentClosing;
- DynamoRevitApp.EventHandlerProxy.DocumentClosed += OnApplicationDocumentClosed;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += OnApplicationDocumentOpened;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating += OnApplicationViewActivating;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += OnApplicationViewActivated;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing += OnApplicationDocumentClosing;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed += OnApplicationDocumentClosed;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += OnApplicationDocumentOpened;
hasRegisteredApplicationEvents = true;
}
@@ -619,16 +635,17 @@ private void UnsubscribeApplicationEvents(DynamoRevitCommandData commandData)
return;
}
- DynamoRevitApp.EventHandlerProxy.ViewActivating -= OnApplicationViewActivating;
- DynamoRevitApp.EventHandlerProxy.ViewActivated -= OnApplicationViewActivated;
- DynamoRevitApp.EventHandlerProxy.DocumentClosing -= OnApplicationDocumentClosing;
- DynamoRevitApp.EventHandlerProxy.DocumentClosed -= OnApplicationDocumentClosed;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened -= OnApplicationDocumentOpened;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating -= OnApplicationViewActivating;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= OnApplicationViewActivated;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing -= OnApplicationDocumentClosing;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed -= OnApplicationDocumentClosed;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= OnApplicationDocumentOpened;
hasRegisteredApplicationEvents = false;
}
+#endif
- #endregion
+#endregion
#region Application event handler
///
@@ -666,6 +683,7 @@ private void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs
HandleApplicationDocumentClosed();
}
+#if !DESIGN_AUTOMATION
///
/// Handler for Revit's ViewActivating event.
/// Addins are not available in some views in Revit, notably perspective views.
@@ -688,8 +706,8 @@ private void OnApplicationViewActivated(object sender, ViewActivatedEventArgs e)
{
HandleRevitViewActivated();
}
-
- #endregion
+#endif
+#endregion
#region Public methods
@@ -707,7 +725,11 @@ protected override void PreShutdownCore(bool shutdownHost)
{
if (shutdownHost)
{
+#if !DESIGN_AUTOMATION
DynamoRevitApp.AddIdleAction(ShutdownRevitHostOnce);
+#else
+ ShutdownRevitHostOnce();
+#endif
}
base.PreShutdownCore(shutdownHost);
@@ -715,7 +737,6 @@ protected override void PreShutdownCore(bool shutdownHost)
private static void ShutdownRevitHostOnce()
{
- var uiApplication = DocumentManager.Instance.CurrentUIApplication;
ShutdownRevitHost();
}
@@ -728,10 +749,13 @@ protected override void ShutDownCore(bool shutDownHost)
// unsubscribe events
RevitServicesUpdater.Instance.UnRegisterAllChangeHooks();
+#if !DESIGN_AUTOMATION
UnsubscribeApplicationEvents(externalCommandData);
+#endif
UnsubscribeDocumentManagerEvents();
UnsubscribeRevitServicesUpdaterEvents();
UnsubscribeTransactionManagerEvents();
+
PythonEngineManager.Instance.AvailableEngines.ToList().ForEach(engine => CleanUpPythonEngine(engine));
PythonEngineManager.Instance.AvailableEngines.CollectionChanged -= OnPythonEngineCollectionChanged;
@@ -741,9 +765,11 @@ protected override void ShutDownCore(bool shutDownHost)
protected override void PostShutdownCore(bool shutdownHost)
{
base.PostShutdownCore(shutdownHost);
-
+
+#if !DESIGN_AUTOMATION
// Always reset current UI document on shutdown
DocumentManager.Instance.CurrentUIDocument = null;
+#endif
}
///
@@ -830,7 +856,7 @@ var ws in Workspaces.OfType())
// If there is a current document, then set the run enabled
// state based on whether the view just activated is
// the same document.
- if (DocumentManager.Instance.CurrentUIDocument != null)
+ if (DocumentManager.Instance.CurrentDBDocument != null)
{
var newEnabled = newView != null &&
newView.Document.Equals(DocumentManager.Instance.CurrentDBDocument);
@@ -849,7 +875,7 @@ var ws in Workspaces.OfType())
}
}
- #endregion
+#endregion
#region Event handlers
@@ -863,14 +889,15 @@ private void HandleApplicationDocumentOpened()
// If the current document is null, for instance if there are
// no documents open, then set the current document, and
// present a message telling us where Dynamo is pointing.
- if (DocumentManager.Instance.CurrentUIDocument == null)
+ if (DocumentManager.Instance.CurrentDBDocument == null)
{
+#if !DESIGN_AUTOMATION
var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument;
DocumentManager.Instance.CurrentUIDocument = activeUIDocument;
if (activeUIDocument != null)
DocumentManager.Instance.HandleDocumentActivation(activeUIDocument.ActiveView);
-
+#endif
OnRevitDocumentChanged();
foreach (HomeWorkspaceModel ws in Workspaces.OfType())
@@ -901,6 +928,7 @@ private void HandleApplicationDocumentClosing(Document doc)
///
private void HandleApplicationDocumentClosed()
{
+#if !DESIGN_AUTOMATION
// If the active UI document is null, it means that all views have been
// closed from all document. Clear our reference, present a warning,
// and disable running.
@@ -933,6 +961,7 @@ private void HandleApplicationDocumentClosed()
{
SetRunEnabledBasedOnContext(uiDoc.ActiveView);
}
+#endif
}
///
@@ -944,11 +973,12 @@ private void HandleRevitViewActivated()
{
// If there is no active document, then set it to whatever
// document has just been activated
- if (DocumentManager.Instance.CurrentUIDocument == null)
+ if (DocumentManager.Instance.CurrentDBDocument == null)
{
+#if !DESIGN_AUTOMATION
DocumentManager.Instance.CurrentUIDocument =
DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument;
-
+#endif
OnRevitDocumentChanged();
InitializeMaterials();
@@ -974,6 +1004,7 @@ private void ResetForNewDocument()
private static void ShutdownRevitHost()
{
+#if !DESIGN_AUTOMATION
// this method cannot be called without Revit 2014
var exitCommand = RevitCommandId.LookupPostableCommandId(PostableCommand.ExitRevit);
var uiApplication = DocumentManager.Instance.CurrentUIApplication;
@@ -986,6 +1017,7 @@ private static void ShutdownRevitHost()
"A command in progress prevented Dynamo from " +
"closing revit. Dynamo update will be cancelled.");
}
+#endif
}
private void TransactionManager_FailuresRaised(FailuresAccessor failuresAccessor)
diff --git a/src/DynamoRevit/Properties/AssemblyInfo.cs b/src/DynamoRevit/Properties/AssemblyInfo.cs
index 5996d78d11..58ea1f6a8b 100644
--- a/src/DynamoRevit/Properties/AssemblyInfo.cs
+++ b/src/DynamoRevit/Properties/AssemblyInfo.cs
@@ -9,4 +9,5 @@
[assembly: AssemblyCulture("")]
[assembly: Guid("082cab33-cbc7-4e58-ae25-f0962f325d6e")]
[assembly: InternalsVisibleTo("RevitTestServices")]
-[assembly: InternalsVisibleTo("RevitSystemTests")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("RevitSystemTests")]
+[assembly: InternalsVisibleTo("DADynamoApp")]
\ No newline at end of file
diff --git a/src/DynamoRevit/Utilities/ASMPreloader.cs b/src/DynamoRevit/Utilities/ASMPreloader.cs
new file mode 100644
index 0000000000..24c860cf06
--- /dev/null
+++ b/src/DynamoRevit/Utilities/ASMPreloader.cs
@@ -0,0 +1,91 @@
+using Autodesk.Revit.ApplicationServices;
+using DynamoInstallDetective;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace Dynamo.Applications
+{
+ internal static class ASMPrealoaderUtils
+ {
+ ///
+ /// Returns the version of ASM which is installed with Revit at the requested path.
+ /// This version number can be used to load the appropriate libG version.
+ ///
+ /// path where asm dlls are located, this is usually the product(Revit) install path
+ ///
+ internal static Version findRevitASMVersion(string asmLocation)
+ {
+ var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll");
+ var product = lookup.GetProductFromInstallPath(asmLocation);
+ var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3);
+ return libGversion;
+ }
+
+ // [Tech Debt] (Will refactor the code later)
+ ///
+ /// Return the preload version of LibG.
+ ///
+ ///
+ ///
+ internal static Version PreloadLibGVersion(string preloaderLocation)
+ {
+ preloaderLocation = new DirectoryInfo(preloaderLocation).Name;
+ var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase);
+
+ var match = regExp.Match(preloaderLocation);
+ if (match.Groups.Count == 4)
+ {
+ return new Version(
+ Convert.ToInt32(match.Groups[1].Value),
+ Convert.ToInt32(match.Groups[2].Value),
+ Convert.ToInt32(match.Groups[3].Value));
+ }
+
+ return new Version();
+ }
+
+ internal static Version PreloadAsmFromRevit(string asmLocation, string dynamoCorePath)
+ {
+ Version libGVersion = findRevitASMVersion(asmLocation);
+ // Get the corresponding libG preloader location for the target ASM loading version.
+ // If there is exact match preloader version to the target ASM version, use it,
+ // otherwise use the closest below.
+ var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynamoCorePath);
+
+ // [Tech Debt] (Will refactor the code later)
+ // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo.
+ Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation);
+ DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation);
+ return preLoadLibGVersion;
+ }
+
+
+ ///
+ /// DynamoShapeManager.dll is a companion assembly of Dynamo core components,
+ /// we do not want a static reference to it (since the Revit add-on can be
+ /// installed anywhere that's outside of Dynamo), we do not want a duplicated
+ /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath
+ /// method, and call it to get the geometry factory assembly path.
+ ///
+ /// The path where DynamoShapeManager.dll can be
+ /// located.
+ /// The version of DynamoShapeManager.dll
+ /// Returns the full path to geometry factory assembly.
+ ///
+ public static string GetGeometryFactoryPath(string corePath, Version version)
+ {
+ var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll");
+ var assembly = Assembly.LoadFrom(dynamoAsmPath);
+ if (assembly == null)
+ throw new FileNotFoundException("File not found", dynamoAsmPath);
+
+ var utilities = assembly.GetType("DynamoShapeManager.Utilities");
+ var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2");
+
+ return (getGeometryFactoryPath.Invoke(null,
+ new object[] { corePath, version }) as string);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs
new file mode 100644
index 0000000000..7b0460f5fa
--- /dev/null
+++ b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Xml.Serialization;
+
+namespace Dynamo.Applications
+{
+ ///
+ /// Defines parameters used for loading internal Dynamo Revit packages
+ ///
+ [Serializable()]
+ public class InternalPackage
+ {
+ ///
+ /// keeps the path to the node file
+ ///
+ public string NodePath { get; set; }
+
+ ///
+ /// keeps the path to the layoutSpecs.json file
+ ///
+ public string LayoutSpecsPath { get; set; }
+
+ ///
+ /// keeps paths to additional assembly load paths
+ ///
+ public List AdditionalAssemblyLoadPaths { get; set; }
+ }
+
+ internal static class DynamoRevitInternalNodes
+ {
+ private const string InternalNodesDir = "nodes";
+ private static IEnumerable GetAllInternalPackageFiles()
+ {
+ string currentAssemblyPath = Assembly.GetExecutingAssembly().Location;
+ string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath);
+
+ string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir);
+ if (false == Directory.Exists(internalNodesDir))
+ {
+ return new List();
+ }
+
+ string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir);
+
+ List internalPackageFiles = new List();
+ foreach (string dir in internalNodesFolders)
+ {
+ string internalPackageFile = Path.Combine(dir, "internalPackage.xml");
+ if (true == File.Exists(internalPackageFile))
+ {
+ internalPackageFiles.Add(internalPackageFile);
+ }
+ }
+ return internalPackageFiles;
+ }
+ private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles)
+ {
+ List internalPackages = new List();
+ string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
+
+ foreach (string internalPackageFile in internalPackageFiles)
+ {
+ try
+ {
+ string internalPackageDir = Path.GetDirectoryName(internalPackageFile);
+ using (StreamReader reader = new StreamReader(internalPackageFile))
+ {
+ XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage));
+ InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage;
+
+ // convert to absolute path, if needed
+ if (false == Path.IsPathRooted(intPackage.NodePath))
+ {
+ intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath);
+ }
+
+ // convert to absolute path, if needed
+ if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath))
+ {
+ intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath);
+ }
+
+ // convert to absolute paths, if needed
+ if (null != intPackage.AdditionalAssemblyLoadPaths && intPackage.AdditionalAssemblyLoadPaths.Count > 0)
+ {
+ intPackage.AdditionalAssemblyLoadPaths = intPackage.AdditionalAssemblyLoadPaths
+ .Select(p => !Path.IsPathRooted(p) ? Path.Combine(basePath, p) : p)
+ .Where(Path.Exists).ToList();
+ }
+
+ internalPackages.Add(intPackage);
+ }
+ }
+ catch (Exception)
+ {
+ Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile));
+ }
+ }
+
+ return internalPackages;
+ }
+ internal static IEnumerable GetNodesToPreload()
+ {
+ IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
+ return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath);
+ }
+ internal static IEnumerable GetLayoutSpecsFiles()
+ {
+ IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
+ return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath);
+ }
+
+ internal static IEnumerable GetAdditionalAssemblyLoadPaths()
+ {
+ IEnumerable internalPackageFiles = GetAllInternalPackageFiles();
+ return ParseinternalPackageFiles(internalPackageFiles).SelectMany(pkg => pkg.AdditionalAssemblyLoadPaths);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs
new file mode 100644
index 0000000000..bd9f2acbab
--- /dev/null
+++ b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+
+internal class DynamoRevitAssemblyResolver
+{
+ ///
+ /// Handler to the ApplicationDomain's AssemblyResolve event.
+ /// If an assembly's location cannot be resolved, an exception is
+ /// thrown. Failure to resolve an assembly will leave Dynamo in
+ /// a bad state, so we should throw an exception here which gets caught
+ /// by our unhandled exception handler and presents the crash dialogue.
+ ///
+ ///
+ ///
+ ///
+ internal static Assembly ResolveDynamoAssembly(string dynamoCorePath, List additionalPaths, ResolveEventArgs args)
+ {
+ var assemblyPath = string.Empty;
+ var assemblyName = new AssemblyName(args.Name).Name + ".dll";
+
+ try
+ {
+ assemblyPath = Path.Combine(dynamoCorePath, assemblyName);
+ if (File.Exists(assemblyPath))
+ {
+ return Assembly.LoadFrom(assemblyPath);
+ }
+
+ if (additionalPaths != null)
+ {
+ foreach (var additionalPath in additionalPaths)
+ {
+ assemblyPath = Path.Combine(additionalPath, assemblyName);
+ if (File.Exists(assemblyPath))
+ {
+ return Assembly.LoadFrom(assemblyPath);
+ }
+ }
+ }
+
+ var assemblyLocation = Assembly.GetExecutingAssembly().Location;
+ var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
+
+ // Try "Dynamo 0.x\Revit_20xx" folder first...
+ assemblyPath = Path.Combine(assemblyDirectory, assemblyName);
+ if (!File.Exists(assemblyPath))
+ {
+ // If assembly cannot be found, try in "Dynamo 0.x" folder.
+ var parentDirectory = Directory.GetParent(assemblyDirectory);
+ assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName);
+ }
+
+ return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message + ex.StackTrace);
+ throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex);
+ }
+ }
+}
diff --git a/src/DynamoRevitIcons/DynamoRevitIcons.csproj b/src/DynamoRevitIcons/DynamoRevitIcons.csproj
index 730d043221..420827688c 100644
--- a/src/DynamoRevitIcons/DynamoRevitIcons.csproj
+++ b/src/DynamoRevitIcons/DynamoRevitIcons.csproj
@@ -7,16 +7,6 @@
prompt
4
-
- full
- false
- TRACE;DEBUG;ENABLE_DYNAMO_SCHEDULER
-
-
- pdbonly
- true
- TRACE
-
true
diff --git a/src/Libraries/Migrations/Migrations.csproj b/src/Libraries/Migrations/Migrations.csproj
index 24d523a8a7..377b84b838 100644
--- a/src/Libraries/Migrations/Migrations.csproj
+++ b/src/Libraries/Migrations/Migrations.csproj
@@ -7,22 +7,8 @@
true
true
$(NoWarn);CS3001;CS3002
- prompt
- 4
- false
$(OutputPath)\nodes\
-
- true
- full
- false
- DEBUG;TRACE
-
-
- pdbonly
- true
- TRACE
-
diff --git a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs
index aed5db9d5b..772a1ff3af 100644
--- a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs
+++ b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs
@@ -570,7 +570,7 @@ private static AdaptiveComponent[] InternalByPoints(Point[][] points, FamilyType
throw new Exception(string.Format(Properties.Resources.DesiredNumberOfPoints, i, desiredNumOfPoints, numOfPoints));
}
- var creationData = DocumentManager.Instance.CurrentUIApplication.Application.Create.
+ var creationData = DocumentManager.Instance.CurrentDBDocument.Application.Create.
NewFamilyInstanceCreationData(familyType.InternalFamilySymbol, aPoints);
if (creationData != null)
diff --git a/src/Libraries/RevitNodes/Elements/Element.cs b/src/Libraries/RevitNodes/Elements/Element.cs
index c15b480880..3c5d078ebe 100644
--- a/src/Libraries/RevitNodes/Elements/Element.cs
+++ b/src/Libraries/RevitNodes/Elements/Element.cs
@@ -287,6 +287,7 @@ public virtual void Dispose()
// Do not delete Revit owned elements
if (!IsRevitOwned && remainingBindings == 0 && !didRevitDelete)
{
+#if !DESIGN_AUTOMATION
if(this.InternalElement is View && InternalElement.IsValidObject)
{
Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document);
@@ -300,6 +301,7 @@ public virtual void Dispose()
throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, this.ToString()));
}
}
+#endif
DocumentManager.Instance.DeleteElement(new ElementUUID(InternalUniqueId));
}
else
@@ -493,7 +495,7 @@ public Element SetParameterByName(string parameterName, object value)
public Element OverrideColorInView(Color color)
{
TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument);
- var view = DocumentManager.Instance.CurrentUIDocument.ActiveView;
+ var view = DocumentManager.Instance.CurrentDBDocument.ActiveView;
var ogs = new Autodesk.Revit.DB.OverrideGraphicSettings();
var patternCollector = new FilteredElementCollector(DocumentManager.Instance.CurrentDBDocument);
@@ -519,7 +521,7 @@ public Element OverrideColorInView(Color color)
public Element OverrideInView(Revit.Filter.OverrideGraphicSettings overrides, bool hide = false)
{
TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument);
- var view = DocumentManager.Instance.CurrentUIDocument.ActiveView;
+ var view = DocumentManager.Instance.CurrentDBDocument.ActiveView;
view.SetElementOverrides(InternalElementId, overrides.InternalOverrideGraphicSettings);
if (hide) view.HideElements(new List() { InternalElementId });
else view.UnhideElements(new List() { InternalElementId });
@@ -535,7 +537,7 @@ public Revit.Filter.OverrideGraphicSettings OverridesInView
{
get
{
- var view = DocumentManager.Instance.CurrentUIDocument.ActiveView;
+ var view = DocumentManager.Instance.CurrentDBDocument.ActiveView;
return new Filter.OverrideGraphicSettings(view.GetElementOverrides(InternalElementId));
}
diff --git a/src/Libraries/RevitNodes/Elements/LinkElement.cs b/src/Libraries/RevitNodes/Elements/LinkElement.cs
index bca2639e9a..1337e9c112 100644
--- a/src/Libraries/RevitNodes/Elements/LinkElement.cs
+++ b/src/Libraries/RevitNodes/Elements/LinkElement.cs
@@ -50,12 +50,12 @@ public static class LinkElement
}
return matchingLinkInstances;
}
-
+ // TODO: move to a UI library
+#if !DESIGN_AUTOMATION
// helper for zooming to clicked green Id
internal static void ZoomToLinkedElement(Element element)
{
-
UIDocument uiDoc = DocumentManager.Instance.CurrentUIDocument;
Autodesk.Revit.DB.View activeView = uiDoc.ActiveView;
// get active UI view to use
@@ -65,12 +65,12 @@ internal static void ZoomToLinkedElement(Element element)
// use the center of the BoundingBox as zoom center
BoundingBoxXYZ bb = element.InternalElement.get_BoundingBox(null);
// if the BBox cannot be found, attempt to find it using the active view
- if (bb==null)
+ if (bb == null)
{
- bb=element.InternalElement.get_BoundingBox(activeView);
+ bb = element.InternalElement.get_BoundingBox(activeView);
}
// finally, if the BB cannot be found at all
- if (bb==null)
+ if (bb == null)
{
TaskDialog.Show("Revit", "No good view can be found.");
return;
@@ -88,6 +88,7 @@ internal static void ZoomToLinkedElement(Element element)
uiview.ZoomAndCenterRectangle(min, max);
}
}
+#endif
// helper to return element's location with transform
internal static object GetLinkElementLocation(Element linkElement)
diff --git a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs
index b28407d482..34d73a7fb7 100644
--- a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs
+++ b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs
@@ -773,6 +773,7 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal
}
}
}
+#if !DESIGN_AUTOMATION
if(newSheet == null)
{
Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document);
@@ -789,7 +790,8 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal
}
}
Document.Delete(elementIds);
- }
+ }
+#endif
}
if (newSheet == null && TraceElements.Count == 0)
@@ -842,7 +844,7 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal
return newSheet;
}
- #endregion
+#endregion
#region Internal static constructors
diff --git a/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs b/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs
index a59fd464ff..a0f51fe807 100644
--- a/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs
+++ b/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs
@@ -72,7 +72,7 @@ private void InitStructuralPlanView(Autodesk.Revit.DB.Level level)
/// A StructuralPlanView if successful.
public static StructuralPlanView ByLevel(Level level)
{
- if (!DocumentManager.Instance.CurrentUIApplication.Application.IsStructureEnabled)
+ if (!DocumentManager.Instance.CurrentDBDocument.Application.IsStructureEnabled)
{
throw new InvalidOperationException(Properties.Resources.StructuralPlanNotEnabled);
}
diff --git a/src/Libraries/RevitNodes/Elements/Views/View.cs b/src/Libraries/RevitNodes/Elements/Views/View.cs
index f8ab6d7cc6..5050e95d26 100644
--- a/src/Libraries/RevitNodes/Elements/Views/View.cs
+++ b/src/Libraries/RevitNodes/Elements/Views/View.cs
@@ -618,6 +618,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl
{
newViewName = prefix + view.Name + suffix;
}
+
+#if !DESIGN_AUTOMATION
Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document);
var openedViews = uIDocument.GetOpenUIViews().ToList();
@@ -630,6 +632,7 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl
else
count--;
}
+#endif
if (count == 0)
{
@@ -651,6 +654,7 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl
var param = newView.InternalView.get_Parameter(BuiltInParameter.VIEW_NAME);
param.Set(newViewName);
}
+#if !DESIGN_AUTOMATION
if (viewElement != null)
{
var shouldClosedViews = openedViews.FindAll(x => viewElement.Id == x.ViewId);
@@ -664,7 +668,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl
throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, viewElement.ToString()));
}
}
- }
+ }
+#endif
}
ElementBinder.CleanupAndSetElementForTrace(Document, newView.InternalElement);
@@ -704,7 +709,7 @@ private static Boolean CheckUniqueViewName(String viewName)
return IsUnique;
}
- #endregion
+#endregion
#region CropBox
diff --git a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs
index 1d6207cd65..31666a56c9 100644
--- a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs
+++ b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs
@@ -6,3 +6,4 @@
[assembly: Guid("17f8f9d8-c00e-4c11-9eb1-06a716689de9")]
[assembly: InternalsVisibleTo("RevitNodesTests")]
[assembly: InternalsVisibleTo("DynamoRevitDS")]
+[assembly: InternalsVisibleTo("DADynamoApp")]
diff --git a/src/Libraries/RevitNodes/RevitNodes.csproj b/src/Libraries/RevitNodes/RevitNodes.csproj
index 4d9940c1cf..1a2b42f9e0 100644
--- a/src/Libraries/RevitNodes/RevitNodes.csproj
+++ b/src/Libraries/RevitNodes/RevitNodes.csproj
@@ -8,9 +8,6 @@
false
$(OutputPath)\$(UICulture)\RevitNodes.xml
$(NoWarn);1591;CA2200
- false
- prompt
- 4
DSRevitNodes
true
true
@@ -18,16 +15,6 @@
None
-
- full
- false
- DEBUG;TRACE
-
-
- pdbonly
- true
- TRACE
-
diff --git a/src/Libraries/RevitNodes/Transaction/Transaction.cs b/src/Libraries/RevitNodes/Transaction/Transaction.cs
index fbafb5faab..8d67caa323 100644
--- a/src/Libraries/RevitNodes/Transaction/Transaction.cs
+++ b/src/Libraries/RevitNodes/Transaction/Transaction.cs
@@ -30,7 +30,9 @@ public static object Start(object input)
public static object End(object input)
{
TransactionManager.Instance.ForceCloseTransaction();
+#if !DESIGN_AUTOMATION
DocumentManager.Instance.CurrentUIDocument.RefreshActiveView();
+#endif
return input;
}
}
diff --git a/src/Libraries/RevitNodesUI/Elements.cs b/src/Libraries/RevitNodesUI/Elements.cs
index 43050bb310..5207504224 100644
--- a/src/Libraries/RevitNodesUI/Elements.cs
+++ b/src/Libraries/RevitNodesUI/Elements.cs
@@ -28,6 +28,7 @@
using BuiltinNodeCategories = Revit.Elements.BuiltinNodeCategories;
using View = Revit.Elements.Views.View;
using RevitServices.Transactions;
+using Autodesk.Revit.ApplicationServices;
namespace DSRevitNodesUI
{
@@ -281,8 +282,10 @@ public ElementsInView()
OutPorts.Add(new PortModel(PortType.Output, this, new PortData("elements", Properties.Resources.PortDataAllVisibleElementsToolTip)));
RegisterAllPorts();
- DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged;
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged;
+#endif
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated;
RevitDynamoModel_RevitDocumentChanged(null, null);
@@ -291,8 +294,10 @@ public ElementsInView()
[JsonConstructor]
public ElementsInView(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts)
{
- DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged;
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged;
+#endif
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated;
RevitDynamoModel_RevitDocumentChanged(null, null);
@@ -300,8 +305,10 @@ public ElementsInView(IEnumerable inPorts, IEnumerable out
public override void Dispose()
{
- DynamoRevitApp.EventHandlerProxy.ViewActivated -= RevitDynamoModel_RevitDocumentChanged;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged;
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= RevitDynamoModel_RevitDocumentChanged;
+#endif
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdaterOnElementsUpdated;
diff --git a/src/Libraries/RevitNodesUI/RevitDropDown.cs b/src/Libraries/RevitNodesUI/RevitDropDown.cs
index b6e5231266..14935c8bd8 100644
--- a/src/Libraries/RevitNodesUI/RevitDropDown.cs
+++ b/src/Libraries/RevitNodesUI/RevitDropDown.cs
@@ -48,14 +48,14 @@ public abstract class RevitDropDownBase : DSDropDownBase
protected RevitDropDownBase(string value) : base(value)
{
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged;
}
[JsonConstructor]
public RevitDropDownBase(string value, IEnumerable inPorts, IEnumerable outPorts) : base(value, inPorts, outPorts)
{
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged;
}
void Controller_RevitDocumentChanged(object sender, EventArgs e)
@@ -90,7 +90,7 @@ private void Updater_ElementsUpdated(object sender, ElementUpdateEventArgs e)
public override void Dispose()
{
RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged;
base.Dispose();
}
diff --git a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj
index e4a62734e3..fa7c8d9f73 100644
--- a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj
+++ b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj
@@ -1,32 +1,31 @@
-
-
-
-
- DSRevitNodesUI
- DSRevitNodesUI
- $(OutputPath)\nodes\
- prompt
- 4
- false
- true
- false
-
-
-
- true
- full
- false
- DEBUG;TRACE
-
-
- pdbonly
- true
- TRACE
-
-
-
-
+
+
+
+
+ DSRevitNodesUI
+ DSRevitNodesUI
+ $(OutputPath)\nodes\
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
$(REVITAPI)\RevitAPI.dll
@@ -36,9 +35,9 @@
$(REVITAPI)\RevitAPIUI.dll
False
-
-
+
+
ComboControl.xaml
@@ -56,7 +55,7 @@
-
+
False
diff --git a/src/Libraries/RevitNodesUI/RevitTypes.cs b/src/Libraries/RevitNodesUI/RevitTypes.cs
index f4bc73c43a..7bbb3eb98f 100644
--- a/src/Libraries/RevitNodesUI/RevitTypes.cs
+++ b/src/Libraries/RevitNodesUI/RevitTypes.cs
@@ -1,20 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using Newtonsoft.Json;
-using Autodesk.DesignScript.Geometry;
-using Autodesk.DesignScript.Runtime;
-using DSRevitNodesUI;
-using RVT = Autodesk.Revit.DB;
-using RevitServices.Persistence;
-using RevitServices.Transactions;
-
-using Dynamo.Utilities;
-using Dynamo.Models;
-using Dynamo.Nodes;
using ProtoCore.AST.AssociativeAST;
-using CoreNodeModels.Properties;
using Dynamo.Graph.Nodes;
namespace DSRevitNodesUI
diff --git a/src/Libraries/RevitNodesUI/Selection.cs b/src/Libraries/RevitNodesUI/Selection.cs
index a2eecc2011..081ab4b91b 100644
--- a/src/Libraries/RevitNodesUI/Selection.cs
+++ b/src/Libraries/RevitNodesUI/Selection.cs
@@ -161,7 +161,7 @@ protected RevitSelection(SelectionType selectionType,
: base(selectionType, selectionObjectType, message, prefix)
{
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged;
}
[JsonConstructor]
@@ -171,7 +171,7 @@ public RevitSelection(SelectionType selectionType,
: base(selectionType, selectionObjectType, message, prefix, selectionIdentifier, inPorts, outPorts)
{
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged;
}
#endregion
@@ -192,7 +192,7 @@ public override void Dispose()
base.Dispose();
RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged;
if (revitDynamoModel != null)
{
diff --git a/src/Libraries/RevitNodesUI/SiteLocation.cs b/src/Libraries/RevitNodesUI/SiteLocation.cs
index 397696e066..5b1c081a13 100644
--- a/src/Libraries/RevitNodesUI/SiteLocation.cs
+++ b/src/Libraries/RevitNodesUI/SiteLocation.cs
@@ -1,8 +1,10 @@
using Dynamo.Applications;
using Dynamo.Applications.Models;
+#if !DESIGN_AUTOMATION
using Dynamo.Controls;
-using Dynamo.Graph.Nodes;
using Dynamo.Wpf;
+#endif
+using Dynamo.Graph.Nodes;
using Newtonsoft.Json;
using ProtoCore.AST.AssociativeAST;
using Revit.GeometryConversion;
@@ -15,7 +17,8 @@
namespace DSRevitNodesUI
{
- public class SiteLocationNodeViewCustomization : INodeViewCustomization
+#if !DESIGN_AUTOMATION
+ public class SiteLocationNodeViewCustomization : INodeViewCustomization
{
public void CustomizeView(SiteLocation model, NodeView nodeView)
{
@@ -28,6 +31,7 @@ public void Dispose()
}
}
+#endif
[NodeName("SiteLocation"), NodeCategory(BuiltinNodeCategories.ANALYZE),
NodeDescription("SiteLocationDescription", typeof(Properties.Resources)), IsDesignScriptCompatible]
@@ -47,10 +51,12 @@ public SiteLocation()
ArgumentLacing = LacingStrategy.Disabled;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated;
-
+
+#if !DESIGN_AUTOMATION
DynamoRevitApp.AddIdleAction(() => Update());
+#endif
}
[JsonConstructor]
@@ -61,17 +67,19 @@ public SiteLocation(IEnumerable inPorts, IEnumerable outPo
ArgumentLacing = LacingStrategy.Disabled;
- DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated;
+#if !DESIGN_AUTOMATION
DynamoRevitApp.AddIdleAction(() => Update());
+#endif
}
#region public methods
public override void Dispose()
{
- DynamoRevitApp.EventHandlerProxy.DocumentOpened -= model_RevitDocumentChanged;
+ RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= model_RevitDocumentChanged;
RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdater_ElementsUpdated;
base.Dispose();
}
diff --git a/src/Libraries/RevitNodesUI/SunPath.cs b/src/Libraries/RevitNodesUI/SunPath.cs
index eee3f8fd9c..82d1dfb2be 100644
--- a/src/Libraries/RevitNodesUI/SunPath.cs
+++ b/src/Libraries/RevitNodesUI/SunPath.cs
@@ -2,9 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
-
+#if !DESIGN_AUTOMATION
using Autodesk.Revit.UI.Events;
-
+#endif
using Dynamo.Applications;
using Dynamo.Applications.Models;
using Dynamo.Graph.Nodes;
@@ -32,33 +32,38 @@ public SunSettings()
RegisterAllPorts();
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated;
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated;
DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated());
+#endif
}
[JsonConstructor]
public SunSettings(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts)
{
RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated;
-
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated;
DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated());
+#endif
}
public override void Dispose()
{
RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated;
- DynamoRevitApp.EventHandlerProxy.ViewActivated -= CurrentUIApplication_ViewActivated;
-
+#if !DESIGN_AUTOMATION
+ RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= CurrentUIApplication_ViewActivated;
+#endif
base.Dispose();
}
+#if !DESIGN_AUTOMATION
private void CurrentUIApplication_ViewActivated(object sender, ViewActivatedEventArgs e)
{
CurrentUIApplicationOnViewActivated();
}
-
+#endif
private void CurrentUIApplicationOnViewActivated()
{
settingsID =
diff --git a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs
index 424765351a..e80e72b116 100644
--- a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs
+++ b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs
@@ -1,6 +1,5 @@
using System;
using Autodesk.Revit.DB.Events;
-using Autodesk.Revit.UI.Events;
namespace RevitServices.EventHandler
{
@@ -8,13 +7,18 @@ namespace RevitServices.EventHandler
/// This is a event handler proxy class to serve as a proxy between the event publisher and
/// the event subscriber
///
+ [Obsolete("This class will be made internal")]
public class EventHandlerProxy
{
public event EventHandler DocumentOpened;
public event EventHandler DocumentClosing;
public event EventHandler DocumentClosed;
- public event EventHandler ViewActivating;
- public event EventHandler ViewActivated;
+#if !DESIGN_AUTOMATION
+ public event EventHandler ViewActivating;
+ public event EventHandler ViewActivated;
+#endif
+
+ internal static EventHandlerProxy Instance = new();
public void OnApplicationDocumentOpened(object sender, DocumentOpenedEventArgs args)
{
@@ -31,15 +35,17 @@ public void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs a
InvokeEventHandler(DocumentClosed, sender, args);
}
- public void OnApplicationViewActivating(object sender, ViewActivatingEventArgs args)
+#if !DESIGN_AUTOMATION
+ public void OnApplicationViewActivating(object sender, Autodesk.Revit.UI.Events.ViewActivatingEventArgs args)
{
InvokeEventHandler(ViewActivating, sender, args);
}
- public void OnApplicationViewActivated(object sender, ViewActivatedEventArgs args)
+ public void OnApplicationViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs args)
{
InvokeEventHandler(ViewActivated, sender, args);
}
+#endif
private void InvokeEventHandler(EventHandler eventHandler, object sender, T args) where T: EventArgs
{
diff --git a/src/Libraries/RevitServices/Persistence/DocumentManager.cs b/src/Libraries/RevitServices/Persistence/DocumentManager.cs
index b92124e6a7..6c853e3cf6 100644
--- a/src/Libraries/RevitServices/Persistence/DocumentManager.cs
+++ b/src/Libraries/RevitServices/Persistence/DocumentManager.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
-using Autodesk.Revit.UI;
using RevitServices.Elements;
using RevitServices.Transactions;
@@ -116,6 +116,8 @@ public void HandleDocumentActivation(View revitView)
ActiveDocumentHashCode = revitView.Document.GetHashCode();
}
+ private Document currentDBDocument;
+
///
/// Provides the currently active DB document.
/// This is based on the CurrentUIDocument
@@ -123,8 +125,15 @@ public void HandleDocumentActivation(View revitView)
public Document CurrentDBDocument {
get
{
+#if !DESIGN_AUTOMATION
var c = CurrentUIDocument;
return c == null ? null : c.Document;
+#else
+ return currentDBDocument;
+#endif
+ }
+ set {
+ currentDBDocument = value;
}
}
@@ -143,17 +152,24 @@ public Document CurrentDBDocument {
///
public int ActiveDocumentHashCode { get; private set; }
+
+ ///
+ /// Provides the current Application
+ ///
+ internal Application CurrentApplication { get; set; }
+
+#if !DESIGN_AUTOMATION
///
/// Provides the currently active UI document.
/// This is the document to which Dynamo is bound.
///
- public UIDocument CurrentUIDocument {get; set; }
+ public Autodesk.Revit.UI.UIDocument CurrentUIDocument {get; set; }
///
/// Provides the current UIApplication
///
- public UIApplication CurrentUIApplication { get; set; }
-
+ public Autodesk.Revit.UI.UIApplication CurrentUIApplication { get; set; }
+#endif
///
/// Trigger a document regeneration in the idle context or without
/// depending on the state of the transaction manager.
@@ -171,5 +187,26 @@ public static void Regenerate()
Instance.CurrentDBDocument.Regenerate();
}
}
+
+ ///
+ /// Setup the CurrentDBDocument and CurrentApplication.
+ ///
+ ///
+ internal void PrepareForDesignAutomation(Application app)
+ {
+ if (app == null)
+ {
+ return;
+ }
+ CurrentApplication = app;
+ foreach (Document d in app.Documents)
+ {
+ if (!d.IsLinked)
+ {
+ CurrentDBDocument = d;
+ break;
+ }
+ }
+ }
}
}
diff --git a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs
index fa60dc9887..a0d3de35aa 100644
--- a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs
+++ b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -9,3 +10,7 @@
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("026be738-81b6-4a11-bc14-36ee3f718921")]
+[assembly: InternalsVisibleTo("DADynamoApp")]
+[assembly: InternalsVisibleTo("RevitNodes")]
+[assembly: InternalsVisibleTo("DSRevitNodesUI")]
+[assembly: InternalsVisibleTo("DynamoRevitDS")]
\ No newline at end of file
diff --git a/src/Libraries/RevitServices/RevitServices.csproj b/src/Libraries/RevitServices/RevitServices.csproj
index 0e1c032d73..15d4015a59 100644
--- a/src/Libraries/RevitServices/RevitServices.csproj
+++ b/src/Libraries/RevitServices/RevitServices.csproj
@@ -20,29 +20,10 @@ limitations under the License.
8.0.30703
false
-
true
true
-
- true
- full
- false
- TRACE;DEBUG
- prompt
- 4
- false
-
-
- full
- true
- TRACE
- prompt
- 4
- true
- false
-
$(REVITAPI)\RevitAPI.dll
@@ -75,6 +56,7 @@ limitations under the License.
+
diff --git a/test/Libraries/RevitIntegrationTests/DALoggerTests.cs b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs
new file mode 100644
index 0000000000..4387568d48
--- /dev/null
+++ b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs
@@ -0,0 +1,68 @@
+using System;
+using System.IO;
+using DADynamoApp;
+using NUnit.Framework;
+using RevitTestServices;
+using RTF.Framework;
+
+namespace RevitSystemTests
+{
+ [TestFixture]
+ class DALoggerTests : RevitSystemTestBase
+ {
+ private StringWriter capturedOutput;
+ private TextWriter originalOutput;
+
+ [SetUp]
+ public override void Setup()
+ {
+ base.Setup();
+ capturedOutput = new StringWriter();
+ originalOutput = Console.Out;
+ Console.SetOut(capturedOutput);
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ Console.SetOut(originalOutput);
+ capturedOutput?.Dispose();
+ base.TearDown();
+ }
+
+ // TODO: Refactor DAEntrypoint so that all post-model-startup logic lives in a separate
+ // internal DAApp class that accepts a DynamoModel in its constructor. DAEntrypoint would
+ // just create the model and hand it to new DAApp(model). This test could then do:
+ // var app = new DAApp(ViewModel.Model);
+ // app.SetupProfilingHandlers();
+ // ...which tests the actual DA code path without needing to create a DAEntrypoint at all,
+ // and makes it straightforward to test graph running too (pass a work item folder).
+
+ ///
+ /// Verifies that DAEntrypoint.SetupProfilingHandlers wires up node execution events that
+ /// call DALogger.SerializeNodeOutputs and write profiling output to stdout.
+ ///
+ [Test]
+ [TestModel(@".\empty.rfa")]
+ public void SetupProfilingHandlers_WritesNodeOutputToStdout()
+ {
+ // Use the actual production method — SetupProfilingHandlers subscribes to WorkspaceOpened
+ // and wires all the profiling/serialization handlers on the model we already have.
+ var entrypoint = new DAEntrypoint();
+ entrypoint.SetupProfilingHandlers(Model);
+
+ string dynPath = Path.GetFullPath(Path.Combine(workingDirectory, @".\Core\SanityCheck.dyn"));
+ ViewModel.OpenCommand.Execute(dynPath);
+ RunCurrentModel();
+
+ var output = capturedOutput.ToString();
+
+ // Profiling start/end lines must appear
+ StringAssert.Contains("Node Point.ByCoordinates started execution.", output);
+ StringAssert.Contains("Node Point.ByCoordinates finished execution.", output);
+
+ // DALogger.SerializeNodeOutputs must have returned something for the Point node
+ StringAssert.Contains("Node Point.ByCoordinates outputs:", output);
+ }
+ }
+}
diff --git a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj
index 9fa6b44a42..8a8ef3ddaa 100644
--- a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj
+++ b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj
@@ -54,6 +54,7 @@
+
diff --git a/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs b/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs
index 3353d12176..ce95e3d909 100644
--- a/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs
+++ b/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs
@@ -54,7 +54,7 @@ private int CheckNumTriangles(DirectShape ds)
private static DirectShape CreateDirectShapeFromQuadPoints(Point p1, Point p2, Point p3, Point p4)
{
var index = IndexGroup.ByIndices(0, 1, 2, 3);
- var mesh = Mesh.ByPointsIndexGroups(new List() { p1, p2, p3, p4 }, new List() { index });
+ var mesh = Mesh.ByPointsFaceIndices(new List() { p1, p2, p3, p4 }, new List() { index });
var mat = DocumentManager.Instance.ElementsOfType().First();
var ds = DirectShape.ByMesh(mesh, Category.ByName("OST_GenericModel"), Material.ByName(mat.Name), "a mesh");
mesh.Dispose();
@@ -191,7 +191,7 @@ public void ByMeshNameCategoryMaterial_ValidInput()
var index1 = IndexGroup.ByIndices(0,1,2);
- var mesh= Mesh.ByPointsIndexGroups(new List() { p1, p2, p3 }, new List() { index1 });
+ var mesh= Mesh.ByPointsFaceIndices(new List() { p1, p2, p3 }, new List() { index1 });
var mat = DocumentManager.Instance.ElementsOfType().First();
var ds = DirectShape.ByMesh(mesh, Category.ByName("OST_GenericModel"), Material.ByName(mat.Name), "a mesh");
@@ -220,7 +220,7 @@ public void ByMeshAndBySurfaceBothLocatedSameMetric()
var index1 = IndexGroup.ByIndices(0, 1, 2);
- var mesh = Mesh.ByPointsIndexGroups(new List() { p1, p2, p3 }, new List() { index1 });
+ var mesh = Mesh.ByPointsFaceIndices(new List() { p1, p2, p3 }, new List() { index1 });
var surf = Surface.ByPerimeterPoints(new List() { p1, p2, p3 });
var mat = DocumentManager.Instance.ElementsOfType().First();
diff --git a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj
index 04c65a4544..9c3a52d318 100644
--- a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj
+++ b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj
@@ -25,25 +25,6 @@ limitations under the License.
None
-
- true
- full
- false
- DEBUG;TRACE
- prompt
- 4
- AnyCPU
- false
-
-
- pdbonly
- true
- TRACE
- prompt
- 4
- true
- false
-
$(REVITAPI)\RevitAPI.dll
diff --git a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs
index 1be498945d..360078c97f 100644
--- a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs
+++ b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs
@@ -43,7 +43,8 @@ public override void Setup()
protected override TestSessionConfiguration GetTestSessionConfiguration()
{
var asmLocation = AppDomain.CurrentDomain.BaseDirectory;
- return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, DynamoRevit.PreloadAsmFromRevit());
+ Version version = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, DynamoRevitApp.DynamoCorePath);
+ return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, version);
}
private static void SetupTransactionManager()
diff --git a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs
index a9dc823849..c020e7658a 100644
--- a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs
+++ b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs
@@ -267,13 +267,13 @@ protected override void StartDynamo(TestSessionConfiguration testConfig)
// Init DynamoTestPath to get DynamoSettings.xml which under user data folder
PreferenceSettings.DynamoTestPath = string.Empty;
//preload ASM and instruct dynamo to load that version of libG.
- var requestedLibGVersion = DynamoRevit.PreloadAsmFromRevit();
+ var requestedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, testConfig.DynamoCorePath);
DynamoRevit.RevitDynamoModel = RevitDynamoModel.Start(
new RevitDynamoModel.RevitStartConfiguration()
{
StartInTestMode = true,
- GeometryFactoryPath = DynamoRevit.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion),
+ GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion),
DynamoCorePath = testConfig.DynamoCorePath,
PathResolver = revitTestPathResolver,
Context = DynamoRevit.GetRevitContext(commandData),