Extensible Storage

I mentioned the main new features of the

Revit 2012 API
and
also pointed out that many important developer

wishes have been resolved
.
Here is another very fundamental and longstanding wish that has been addressed, more completely than anyone might have expected:

Question: How can I store my custom application data inside the Revit file using the Revit API?

Answer: One possibility is to use a shared parameter. This is a slightly convoluted operation and involves setting up the shared parameter text file appropriately. You have the option of whether a shared parameter should or should not be visible to the user. The whole procedure is demonstrated by the FireRating SDK sample and discussed in numerous blog posts:

In Revit 2012, one of the major API enhancements is the Extensible Storage mechanism. This offers a completely new storage facility for applications which is completely invisible to the user. It is the very first item described in the What’s New section of the documentation on major enhancements:

Extensible Storage

The Revit API now allows you to create your own class-like Schema data structures and attach instances of them to any Element in a Revit model. This functionality can be used to replace the technique of storing data in hidden shared parameters. Schema-based data is saved with the Revit model and allows for higher-level, metadata-enhanced, object-oriented data structures. Schema data can be configured to be readable and/or writable to all users, just a specific application vendor, or just a specific application from a vendor. The extensible storage classes are all found in the Autodesk.Revit.DB.ExtensibleStorage namespace:

  • Schema – contains a unique schema identifier, read/write permissions, and a collection of data Field objects.
  • Entity – an object containing data corresponding to a Schema that can be inserted into a Revit Element.
  • Field – contains data name, type, and unit information and is used as the key to access corresponding data in an Entity.
  • SchemaBuilder – create Schema definitions.
  • FieldBuilder – a helper class used with SchemaBuilder when creating a new field.

The following data types are currently supported:

  • int
  • short
  • double
  • float
  • bool
  • string
  • Guid
  • ElementId
  • Autodesk.Revit.DB.UV
  • Autodesk.Revit.DB.XYZ
  • Array (as a System.Collections.Generic.IList<T>)
  • Map (as a System.Collections.Generic.IDictionary<TKey, TValue> – all types are supported for keys except double, float, XYZ, and UV)
  • Autodesk.Revit.DB.ExtensibleStorage.Entity (an instance of another Schema, also known as a SubSchema)

Simple usage of ExtensibleStorage:


/// <summary>
/// Create a data structure, attach it to a wall, 
/// populate it with data, and retrieve the data 
/// back from the wall
/// </summary>
public void StoreDataInWall(
  Wall wall,
  XYZ dataToStore )
{
  Transaction createSchemaAndStoreData
    = new Transaction( wall.Document, "tCreateAndStore" );
 
  createSchemaAndStoreData.Start();
  SchemaBuilder schemaBuilder = new SchemaBuilder(
    new Guid( "720080CB-DA99-40DC-9415-E53F280AA1F0" ) );
 
  // allow anyone to read the object
  schemaBuilder.SetReadAccessLevel(
    AccessLevel.Public );
 
  // restrict writing to this vendor only
  schemaBuilder.SetWriteAccessLevel(
    AccessLevel.Vendor );
 
  // required because of restricted write-access
  schemaBuilder.SetVendorId( "ADSK" );
 
  // create a field to store an XYZ
  FieldBuilder fieldBuilder = schemaBuilder
    .AddSimpleField( "WireSpliceLocation",
    typeof( XYZ ) );
 
  fieldBuilder.SetUnitType( UnitType.UT_Length );
 
  fieldBuilder.SetDocumentation( "A stored "
    + "location value representing a wiring "
    + "splice in a wall." );
 
  schemaBuilder.SetSchemaName( "WireSpliceLocation" );
 
  Schema schema = schemaBuilder.Finish(); // register the Schema object
 
  // create an entity (object) for this schema (class)
  Entity entity = new Entity( schema );
 
  // get the field from the schema
  Field fieldSpliceLocation = schema.GetField(
    "WireSpliceLocation" );
 
  entity.Set<XYZ>( fieldSpliceLocation, dataToStore,
    DisplayUnitType.DUT_METERS ); // set the value for this entity
 
  wall.SetEntity( entity ); // store the entity in the element
 
  // get the data back from the wall
  Entity retrievedEntity = wall.GetEntity( schema );
 
  XYZ retrievedData = retrievedEntity.Get<XYZ>(
    schema.GetField( "WireSpliceLocation" ),
    DisplayUnitType.DUT_METERS );
 
  createSchemaAndStoreData.Commit();
}

The Revit 2012 SDK includes a much more full-fledged example of making use of this technology, the ExtensibleStorageManager sample.

As Arnošt Löbel kindly pointed out, the VendorId specified above is the same as the

new required VendorId tag in the add-in manifest
.
ADSK is a vendor id used by Autodesk, and you should replace it by your own
Autodesk Registered Developer Symbol RDS.
<!–

Finally, here is an article by Saikat Bhattacharaya from our last ADN AEC newsletter which describes more details of the extensible storage mechanism:
ExtensibleStorageAPI.
–>

That should give you ample material to explore. Have fun!


Comments

8 responses to “Extensible Storage”

  1. like XDATA for AutoCAD but on steroids .. I DIGG IT!

  2. me too :-)

  3. Jon Albert Avatar
    Jon Albert

    Jeremy,
    How do you suggest handling “Revisions” to Extensible Storage Schema(s)?
    For example, if my application uses a schema with 3 fields originally, but later discover I need a 4th field.
    From my experience, if I add the 4th field to my schema, the existing schemas applied to Revit elements are not recognized as being equal to the “Revised” schema.
    Is there a built in way to handle this? Or would I need to keep track of the schema “Versions” in order to compare when needed?
    Thanks,
    Jon Albert

  4. Dear Jon,
    Thank you for a great question!
    That will definitely be a topic of my AU class on extensible storage.
    The second version of the schema would actually have to be defined as a new schema with a separate GUID.
    In the application making use of the data, you could implement support for both versions of the schema, and also automatically update from version 1 to version 2, if you like.
    So the answer is basically ‘yes, you would’.
    Cheers, Jeremy.

  5. Jon Albert Avatar
    Jon Albert

    Thanks Jeremy,
    That is basically what I had in mind. Hopefully I will not have this situation for some time, but definitely good to keep in mind when defining schema(s).
    I look forward to attending you class(s) at AU!
    Jon

  6. Dear Jon,
    Great minds think alike, and sometimes small ones like mine as well :-)
    Looking forward to seeing you there and hearing how it goes for you. Though you will almost certainly know more about it than I do by then :-)
    Cheers, Jeremy

  7. Williams Avatar
    Williams

    dear jeremy
    Es posible agregar una URL a cada elemento mediante almacenamiento extensible, me explico:
    tengo un proyecto que tiene muchos elementos ya sea vigas, columnas, muros, etc. y a cada uno de ellos quiero asignarle una URL y hacerlo uno por uno seria un poco tedioso, es por esto que he estado tratando mediante la API de revit de automatizarlo pero no lo he logrado, es posible esto?

  8. Dear Williams,
    Hola, que tal.
    Yes, sure it is possible to attach a URL to Revit elements by storing them as a string in extensible storage.
    You can use the code provided above to achieve this.
    Simply define a field of type string instead of XYZ.
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading