Many presentations at the Autodesk Technical Summit were confidential, but not all.
One important class on published functionality of general interest that we can share here is 1-3 Referenced Files as a Service – a new way to provide data to Revit by Diane Christoforo, Revit Senior Software Engineer.
How did we transform Revit to reference data from services instead of files? When one Revit project can consist of many different files – CAD links, other linked Revit models, the keynote table, assembly codes, rendering decals – how do you manage all that data in a cloud environment?
In this talk, we'd like to introduce the Referenced Files as a Service project. With this new service, anyone can create a Revit add-on to allow Revit to reference data from any source. It supports arbitrary data sources such as a website, database or Vault. (Normal files still work too!)
As an added bonus, Revit can think of these resources as "resources" and not specifically as "files". In the case of keynotes and assembly codes, no file ever has to exist on disk at any point in the process.
In this talk, we'll cover two interesting examples. First, we'll show you how to get Revit links straight off of the Autodesk wiki. Second, we'll show how to build a keynote "file" from a database. We'll talk about how Revit's architecture changed to support these examples, and how transforming the product to a service architecture simplifies the process of working with new data.
We'll also talk about the challenges we encountered working on the project. We had to do some creative testing to work with functionality that wasn't compatible with our normal test framework. This was also the first time most of the team was working on the referenced files code, and we learned some useful lessons about getting team-members up to speed.
Here is an effective summary of the ideas underlying this framework.
Click here to browse the full slide deck presented at the Autodesk Technical Summit in Toronto.
For more immediate access, I extracted and reformatted the pure text content below.
For optimal understanding, you might want to go through the slide deck and text below in parallel:
Here's a very misleading picture of a Revit model showing one single Revit RVT project file:
A real customer project uses data from many sources – other linked Revit models, DWGs, DWF markups, keynotes, rendering decals, shared parameters, etc.
Here are some questions from users and corresponding hypothetical answers from previous versions of Revit:
[Q] I'm going to download this model from Autodesk 360. You can automatically get all the links and set them up, right?
[A] The developers haven't taught me how to use A360.
[Q] We want to put our files on this website. You can get them from there, right?
[A] What's a website?
[Q] We want Revit to build one keynote table from two files so we don't have to put it together by hand. You can do that, right?
[A] The developers haven't taught me how to do that.
Revit only knows how to handle files on disk or models on Revit server.
Every time we want to get data from someplace new, we have to:
The cloud doesn't have 'files', so even if we did implement all the individual features people request, we still have a problem.
Now people can provide the data from whatever source they like!
Converting our own code to use the new framework was both a good proof-of-concept and a good bug-finder.
The new external resource service framework is built on top of Revit's existing ExternalServices framework.
We added two interfaces:
All of the plugins are Revit API add-ons. We added a new ExternalService called the ExternalResourceService. Plugin developers can write their own instance of IExternalResourceServer (and optionally IExternalResourceUIServer, if they want to provide any feedback to the user.)
You can use the External Resources framework to build a plugin supplying:
What are these things?
Revit uses each of these as follows:
Keynotes and assembly codes have virtually the same implementation, so the following examples will focus on Revit links and keynotes.
This two-minute demo video shows loading the keynote table from a wiki page on the Autodesk wiki, modifying the wiki content, reloading the data into the model, and modifying a linked file through the external resource service:
This demo was also shown in the Revit 2015 News and DevDays presentations.
An ExternalResourceReference object describes a resource:
Instead of storing file paths, external resources now store a new structure called an ExternalResourceReference encapsulating 'filename', 'path' and 'path on disk or Revit Server'.
Local resources have these as well.
Inside the ExternalResourceReference:
Resource maps can be as simple as:
'resource' = '4'
They can also be more complicated:
'name' = 'hospital third floor restroom' 'user' = 'dchris' 'language' = 'en-us' 'format' = 'txt' 'last-accessed' = '3-26-14'
With regards to the reference map, our local resources store the path on disk, and whether the path is relative or absolute.
The plugin that works with the wiki stores the id of the wiki page in its ExternalResourceReference. This means that, even if the title of the page changes, Revit still gets any updates made to that page.
void IExternalResourceServer.LoadResource( Guid loadRequestId, ExternalResourceType resourceType, ExternalResourceReference desiredResource, ExternalResourceLoadContext loadContext, ExternalResourceLoadContent loadContent)
ExternalResourceLoadContext provides information such as: what was the previous resource (so the plugin can tell if it's loading the same resource), whether the load was an automatic or explicit action (The plugin may want to do different actions on file open versus when the user presses the 'reload' button), and the name of the Revit model requesting the resource.
Each resource type has its own subclass.
Keynotes and assembly codes can be built directly.
The plugin builds a table of key/value pairs and returns it to Revit.
No files needed anywhere!
Revit links have to return a locally cached path.
Revit's still the only thing that can build a Revit model.
The user doesn't need to know or care that there's a local copy of the model.
The plugin also sets a success/failure value, so Revit can quickly see whether the operation succeeded or not. The default value is 'uninitialized', so we also have some idea of whether something went terribly wrong on the server's end.
Other IExternalResourceServer functions:
For AreSameResources – originally we just compared the referenceInformation, but we realized that two resources might have different strings but still be considered 'the same' by the server. As an example, internally you can use relative or absolute paths. But the relative and absolute versions of the same file are still ... the same file, even though their reference information would be different.
We don't know what will go wrong.
How can Revit respond to errors like these?
Revit can't anticipate everything that can go wrong on the server end. We let the plugin do error handling because the plugin knows how to fix its own problems.
These situations are managed using the IExternalResourceUIServer.HandleLoadResourceResults method:
void IExternalResourceUIServer.HandleLoadResourceResults( Document document, IList<ExternalResourceLoadData> loadData)
These are the details of the function the plugin uses to provide results back to Revit.
There are two notable things here:
You can download the Revit 2015 SDK including the ExternalResourceServer add-in SDK sample add-in from the Revit Developer Centre.
The Kiwi Solutions Easy Keynoter add-in shows one impressive practical use of the Revit 2015 'referenced files as a service' feature and solves several long standing issues with regards to keynotes in Revit.