Running Network I/O in AutoCAD .NET Commands

Traditionally, AutoCAD .NET plugins work with geometry and the drawing database.
But modern workflows often require pulling data from the web
for example, fetching design inputs, configuration, or geometry parameters from a service.

Since the AutoCAD .NET API is not thread-safe, you cannot call it directly
from a background thread. This becomes tricky when performing network I/O,
which is inherently asynchronous.

The solution:

  • Perform network requests in a background task
    (Task.Run or HttpClient async calls).
  • Use SynchronizationContext.Current captured on the AutoCAD UI thread
    to post results back.
  • Modify the AutoCAD drawing safely on the main thread.

Example: Drawing Lines from Web Data

We host a simple JSON file on GitHub Pages:


{
  "lines": [
    { "start": { "x": 0, "y": 0, "z": 0 }, "end": { "x": 25, "y": 15, "z": 0 } },
    { "start": { "x": 10, "y": 5, "z": 0 }, "end": { "x": 40, "y": 30, "z": 0 } }
  ]
}

In AutoCAD, the command WEBLINES downloads this file and creates corresponding
Line entities in ModelSpace:


public async void CreateLinesFromWeb()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;

    // Capture AutoCAD main thread SynchronizationContext
    System.Threading.SynchronizationContext uiContext =
        Autodesk.AutoCAD.Runtime.SynchronizationContext.Current;

    try
    {
        // Fetch and parse JSON in background
        var lines = await Task.Run(async () =>
        {
            using HttpClient client = new HttpClient();
            string url = "https://madhukarmoogala.github.io/linepoints.json";
            string json = await client.GetStringAsync(url);

            JsonDocument docRoot = JsonDocument.Parse(json);
            var lineList = new System.Collections.Generic.List();

            foreach (var lineElem in docRoot.RootElement.GetProperty("lines").EnumerateArray())
            {
                Point3d start = new Point3d(
                    lineElem.GetProperty("start").GetProperty("x").GetDouble(),
                    lineElem.GetProperty("start").GetProperty("y").GetDouble(),
                    lineElem.GetProperty("start").GetProperty("z").GetDouble()
                );
                Point3d end = new Point3d(
                    lineElem.GetProperty("end").GetProperty("x").GetDouble(),
                    lineElem.GetProperty("end").GetProperty("y").GetDouble(),
                    lineElem.GetProperty("end").GetProperty("z").GetDouble()
                );
                lineList.Add((start, end));
            }
            return lineList;
        });

        // Post back to UI thread to modify AutoCAD Database
        uiContext.Post(_ =>
        {
            using (doc.LockDocument())
            using (Transaction tr = doc.Database.TransactionManager.StartTransaction())
            {
                BlockTable bt =
                    (BlockTable)tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead);
                BlockTableRecord ms =
                    (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace],
                                                   OpenMode.ForWrite);

                foreach (var linePair in lines)
                {
                    Point3d start = linePair.start;
                    Point3d end = linePair.end;
                    Line line = new Line(start, end);
                    ms.AppendEntity(line);
                    tr.AddNewlyCreatedDBObject(line, true);
                    ed.WriteMessage($"nCreated line from {start} → {end}");
                }

                tr.Commit();
                ed.WriteMessage("nLines created successfully from web data.");
                ed.PostCommandPrompt();
            }
        }, null);
    }
    catch (Exception ex)
    {
        ed.WriteMessage($"nError fetching/drawing lines: {ex.Message}");
    }
}

This small pattern opens the door to connecting AutoCAD commands with
cloud services, APIs, and dynamic data — safely mixing modern async programming
with AutoCAD’s single-threaded API.


Comments

4 responses to “Running Network I/O in AutoCAD .NET Commands”

  1. here’s a PyRx version

    from pyrx import Ap, Ax, Db, Ge
    import requests
    # register command
    @Ap.Command()
    def createLinesFromWeb():
    try:
    #make the request
    url = "https://madhukarmoogala.github.io/linepoints.json"
    request = requests.get(url)
    #is a Python dict
    data = request.json()
    #extract x,y,z
    lines = []
    for item in data["lines"]:
    s = item["start"]
    e = item["end"]
    lines.append(
    Db.Line(Ge.Point3d(s["x"], s["y"], s["z"]),
    Ge.Point3d(e["x"], e["y"], e["z"])))
    #add to modelspace
    db = Db.curDb()
    db.addToModelspace(lines)
    except Exception as err:
    print(err)
    

    I have a routine that scrapes web data into an AcDbTable somewhere, that’s pretty cool too

  2. Thanks, Dan, for sharing Python snippet with us :)
    Can you share your Python API Sdk for AutoCAD here, I do get occasional requests using AutoCAD API python, maybe I can share your repo.

  3. Sure,
    The repository is here https://github.com/CEXT-Dan/PyRx
    A quick video installing for AutoCAD


    I’m working on a redistributable .bundle people can just toss into Autodesk\ApplicationPlugins without having to install Python, still in the oven

  4. Maxence Delannoy Avatar
    Maxence Delannoy

    Await, with ConfigureAwait set to true by default, captures the context for us, right? I don’t see why you’re using Post()… After the await, we return to the UI execution thread (in the application context, so locking is necessary there).

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading