Batch Processing, DWFx Links, Future-Proofing

The never-ending stream of Revit API topics continues.

Today, let's look at:

Unrestricted VendorId

In the past, we recommended using an Autodesk registered developer symbol or RDS as your vendor id, stored in the add-in manifest VendorId tag (starting from the Revit 2012 extensible storage and add-in wizard).

Autodesk registered developer symbols are very limited, though, consisting of only four characters from a restricted set, [A-Z], [0-9], minus '-' and underscore '_'.

The Autodesk registered developer symbol usage is now deprecated, so this restriction has been lifted for the Revit VendorId specification.

This liberalisation is already documented in the developer guide, in the Revit 2016 online help > Developers > Revit API Developers Guide > Introduction > Add-In Integration > Add-in Registration:

Accordingly, I should update my Visual Studio Revit add-in wizard to use com.typepad.thebuildingcoder instead of the current RDS TBC_... to be done asap.

Retrieving DWFx Links

Let's look at how to retrieve DWFx links from the current Revit project.

This question was raised and solved by Daniel in the Revit API discussion forum thread on getting all linked DWFx files in the Revit document:

Question: I'm trying to list all links in a document using filtered element collectors.

I get the RVT links (Revit and IFC) through the built-in category; DWG links also work fine using the ofClass(typeof(importInstance)) filter.

I thought that DWFx and point clouds also should be listed under this filter?

It seems not, though. I can't get them through that filter, and I can't see any other type to use.

Answer: While working on creating a minimal reproducible sample, I found the error.

It's kind of simple. DWFx files are not linked, even though they appear to be so.

When I changed from:

  var dwgLinks = fecDwgLinks
    .OfClass(typeof(ImportInstance))
    .ToElements()
    .Cast<ImportInstance>()
    .Where(f=> f.IsLinked);

To:

  var dwgLinks = fecDwgLinks
    .OfClass(typeof(ImportInstance))
    .ToElements()
    .Cast<ImportInstance>();

Things worked fine.

This code returns other links as well, but that is how I want it.

I am creating a tool that lists all the links.

When I use the collected elements, I use the category name, which contains the filename extension, to group the different types of links:

  var namearray = importlink.Category.Name.Split('.');
  var name = namearray.FirstOrDefault();
  var extension = string.Empty;
  if (namearray.LastOrDefault() != null)
    extension = namearray.Last();

I have created an Enum to group a list on:

  GroupingEnum lType = GroupingEnum.Unknown;
  if (extension.ToLower().Contains("dwg"))
    lType = GroupingEnum.Dwg;
  else if (extension.ToLower().Contains("dwf"))
    lType = GroupingEnum.Dwf;

This is used to group a list so that it is easy to choose the wanted elements.

Batch Processing Revit Documents

Question: I'm looking at building a Revit service that processes Revit families on demand and extracts Revit family information.

Do you know of anyone who has done this before?

I have been reading the discussion on driving Revit through a WCF service.

I'm stuck on the problem that I will run into Revit errors that can't be handled through the API or Revit will eventually crash.

I will have to kill the Revit process, skip the family and start another Revit process.

How will I detect that Revit has stopped working?

Here is my proposed architecture:

Easy so far.

But how do I catch in the queue managing software if Revit crashes or a warning dialogue pops up and stops Revit?

I could use time if Revit takes more than 2 minutes to process a family than it is not responding end the Revit process (crash it), skip this family and start up another Revit session.

How would you detect if Revit is not responding?

Answer: I think the blog post you point to is a good starting point.

You might also want to check out Daren Thomas' recent contributions on this topic, discussing the Revit Python shell in the cloud as a web server and explaining the Revit API context.

I have summarised several other related discussions in The Building Coder topic group on Idling and external events for modeless access and driving Revit from outside.

By the way, I recommend never using the Idling event, if it can possibly be avoided. External events are more flexible and do not block the entire system, like the Idling event sometimes does.

Otherwise, your architecture sounds absolutely fine to me.

Yes, you should assume that Revit will stop working after a while when driven in this manner.

That is to be expected, since it is implemented to be driven in a completely different manner, interactively, by a human user.

How to check when it stops working?

Probably the best approach is indeed to implement a timer and see how long it takes to complete the current request.

Once the timeout is exceeded, assume it died, kill it properly, and restart at that point.

This is a standard approach for driving lengthy complex batch processes.

Future-Proofing The Building Coder Samples

I continued in my perpetual struggle to future-proof The Building Coder samples by eliminating all deprecated API usage.

The result of my latest effort is release 2016.0.120.9, which compiles once again with zero warnings.