Hey, I wonder if I could get some clarity on the threading requirements for using Rhino.Inside
to create and dispose headless documents.
I’m seeing some weird behaviour where the disposal of the RhinoDoc
is causing my application to crash without a managed (.NET) exception for me to handle…
Here’s a minimal code sample that reproduces my issue. Regardless of the 3dm file you import, will crash on the line that disposes the open document, and the line “Success” will never print.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Rhino;
using Rhino.DocObjects;
using Rhino.Runtime.InProcess;
namespace RhinoInsideCrash
{
class Program
{
static Program()
{
RhinoInside.Resolver.Initialize();
Console.WriteLine($"Loading Rhino @ {RhinoInside.Resolver.RhinoSystemDirectory}");
}
[System.STAThread]
static async Task Main(string[] args)
{
await RhinoProgram.Run();
Console.WriteLine("Success!");
}
static class RhinoProgram
{
public static async Task Run()
{
//This is on the Main thread
using (new RhinoCore([], WindowStyle.NoWindow))
{
RhinoDoc open = RhinoDoc.CreateHeadless(null);
try
{
open.Import(@"C:\Users\Jedd\Documents\RhinoInsideCrash\Sample.3dm");
//Do something that actually interacts with the document...
List<RhinoObject> rhinoObjects = open.Objects.GetObjectList(ObjectType.AnyObject)
.ToList();
// Do *something* async.
// We have to use ConfigureAwait(false) here because Rhino will hog the main thread. Note, this does mean we'll be calling Dispose on a worker thread...
await Task.Delay(100).ConfigureAwait(false);
}
finally
{
Console.WriteLine("Done some stuff, about to dispose");
open?.Dispose(); //This line causes a fatal crash...
}
}
}
}
}
}
I thought that perhaps there’s some requirement to create and dispose the document on the same thread. So I did try wrapping all the code after the new RhinoCore
in a Task.Run
to keep everything on a worker thread. But same result…
I also thought, well maybe it’s not safe to use worker threads to create/dispose documents… But interestingly, if you import a non .3dm file (like a .obj, or .stl file) then the dispose works reliably.
I’ve also tried using RhinoDoc.OpenHeadless
instead of RhinoDoc.CreateHeadless
+ RhinoDoc.Import
…
Same results.
So what gives?
Ultimately my goal is to be able to open and close a headless document, while performing some kind of await async action while it’s open…
Here’s my full .NET solution. I’m using Rhino.Inside 8.0.7-beta, and Rhino 8.22.25210.13001 (2025-07-29)
RhinoInsideCrash.zip (24.5 KB)
Steps to reproduce.
-
Open solution
-
restore
-
build
-
run
-
observe non-zero exit code in console, and no “success” message gets printed…