Create an Exchange Container
The first step in creating a Data Exchange using the Data Exchange SDK is to create an empty Data Exchange container. This container is created on the hosting provider, such as Autodesk docs. and is used to store and manage the data for the Data Exchanges.
To create the exchange container, call the CreateExchangeAsync method on the IClient Interface.
Use the hosting provider APIs to list and navigate through the hubs, projects, and folders that you have access to.
After calling the CreateExchangeAsync method, it will return the ExchangeDetails object. This object contains details such as CollectionId, ExchangeId, HubId, and more. These details together form the DataExchangeIdentifier, which serves as a unique identifier for a specific Data Exchange. You can use this identifier later when you want to read or write data to a particular Data Exchange.
Note: At this point, we have only created an empty exchange container. In the subsequent sections, you will learn how to add data to the Data Exchange, which is stored within the exchange container.
var ExchangeCreateRequest = new ExchangeCreateRequestACC()
{
Host = HostingProvider,
Contract = new Autodesk.DataExchange.ContractProvider.ContractProvider(),
Description = string.Empty,
FileName = name,
HubId = hubId,
ACCFolderURN = folderUrn,
ProjectId = projectId,
ProjectType = projectType
};
var ExchangeDetails = await Client.CreateExchangeAsync(ExchangeCreateRequest);
// The DataExchangeIdentifier will be required to identify the exchange for further API calls.
var DataExchangeIdentifier = new DataExchangeIdentifier
{
CollectionId = ExchangeDetails.CollectionID,
ExchangeId = ExchangeDetails.ExchangeID,
HubId = ExchangeDetails.HubId
};
Add data to the exchange container
You can add data to the exchange container using the ElementDataModel class.
Understanding the ElementDataModel class
The ElementDataModel class is a high-level data model abstraction over the base ExchangeData client-side model. This provides a convenient way to create and modify an exchange’s data on the client-side.
Element is a representation of an instance/entity within the Data Exchange. Elements are made up of a collection of Parameters and geometries and contain data about the Element such as units, transformation, and other metadata.
The ElementDataModel abstraction provides an Elements property, which is a list of all the elements that exist within the exchange up to that version. The ElementDataModel also contains information about deltas that have been received after the initial retrieval and can provide a list of elements that were created, modified, or deleted for a specific set of revisions. Additionally, the ElementDataModel offers the TopLevelElements property, which retrieves a list of the top-level elements within this Data Exchange.
Previously, Elements property was used to get the top-level elements and then called the GetFlattenedListOfElements method to obtain all the elements in the exchange. However, there is no longer a need to call any method to get all the elements present in the exchange, as the Elements property now retrieves all the elements in the exchange.
The GetElementGeometriesByElementsAsync
method gets the geometries such as BRep, Mesh, and Primitive Geometry for a list of elements and is the preferred method to retrieve geometries due to performance optimizations. Similarly, the GetElementGeometryByElementAsync(Element element) method helps in retrieving Geometry information associated with a single Element.
Apart from the retrieval methods, the ElementDataModel abstraction also provides methods to create, modify, and delete elements from the list. The methods CreateGeometry and SetElementGeometryByElement are used in creating and mapping geometry to the elements of a Data Exchange.
The ElementDataModel also contains SetViewableWorldCoordinates method for setting the viewable world coordinates of the ACC viewable. The previously used GenerateViewableAsync
method is now deprecated. Use ElementDataModel.SetViewableWorldCoordinates for setting the coordinates during viewable generation. Please note that the SetViewableWorldCoordinates call should be made prior to the publish/sync (SyncExchangeDataAsync) call for proper functionality.
ElementDataModel.SetViewableWorldCoordinates(new ViewableWorldCoordinates()
{
//default value will be UP=0 0 1, Front=0 -1 0, North=0 1 0
UP = new Math.Vector3d(1, 0, 0),
Front = new Math.Vector3d(0, 0, 1),
North = new Math.Vector3d(0, 0, -1)
});
The SDK supports writing the following basic geometry data types:
- Brep/Mesh/IFC geometry through any generic file format, for example, BRep(STP), Mesh(OBJ), and IFC(IFC).
- Primitive geometry.
Brep/Mesh/IFC Geometry
The following code samples demonstrate how you can add Brep/Mesh/IFC geometry to the elements of an exchange.
- Create the ElementDataModel wrapper by calling the ElementDataModel.Create method and pass the instance of the exchange client (IClient).
- Call the AddElement method on the ElementDataModel to add a new element to the exchange. In the AddElement method, pass the id, name, category, family, and type of the element you want to add. This method is ideal when you want to add elements only at one level, that is, when there are no child elements.
To add a child element to an existing element, call the AddElement method and pass the parent element as a parameter.
- Create Geometry using the ElementDataModel.CreateGeometry method and pass an instance of GeometryProperties. The GeometryProperties constructor requires a file path (such as STEP, IFC, OBJ, etc.) and an instance of
RenderStyle
.The
RenderStyle
instance holds the color details of the geometry in the Data Exchange. To apply the desired color to the geometry, create aRenderStyle
instance with the required color and pass it, along with the file path, to the GeometryProperties constructor. This will apply the specified color to the geometry in the Data Exchange.Note: The RenderStyle applies single color to the entire body of the Data Exchange, so if your body contains different color and you pass the
RenderStyle
instance, the geometry will be overridden with the single color. The ideal scenario to useRenderStyle
instance is when you want to apply single color to your geometry.If the
RenderStyle
instance is passed with a null value, the geometry will derive its color from the file specified in the first parameter of the GeometryProperties constructor. This file must contain the original color used to create the model of the Data Exchange, and the same color will then be applied to the geometry. - Establish the relationship between the element and the geometry using the ElementDataModel.SetElementGeometryByElement method. This will add the geometry to the element of the exchange.
Add geometry to the elements at one level (when child elements are not present)
RGBA rgba = new RGBA(0,0,0,0);
RenderStyle CommonRenderStyle = new RenderStyle("Name", rgba, 1);
// Create ElementDataModel wrapper
var ExchangeDataWrapper = ElementDataModel.Create(IClient);
// Adds elements to the exchange (child elements are not present)
var Element = ExchangeDataWrapper.AddElement(new ElementProperties("Id","elementname" "category", "family", "type"));
// Create Geometry
var Path = "FilePath";
var Geometry = ExchangeDataWrapper.CreateGeometry(new GeometryProperties((Path, CommonRenderStyle));
// Map elements and geometry.
var ElementGeometry = new List<ElementGeometry> { Geometry };
ExchangeDataWrapper.SetElementGeometryByElement(Element, ElementGeometry);
Add geometries to the elements at hierarchy (when parent and child elements are present)
// Adds elements to the parent and child elements of the exchange
// Add parent elements to the exchange.
var RebarParentElement = ExchangeDataWrapper.AddElement(new ElementProperties("Id","elementname", "category", "family", "type"));
// Add child elements to the exchange
var RebarChildElement = ExchangeDataWrapper.AddElement(new ElementProperties { ElementId = $"Rebar-{i}-{j + 1}", Name = $"Rebar-{i}-{j + 1}", Transformation = childElementMatrix }, RebarParentElement);
// Create Geometry
var Path = "FilePath";
var Geometry = ExchangeDataWrapper.CreateGeometry(new GeometryProperties((Path, CommonRenderStyle));
// Map elements and geometry.
var RebarElementGeometry = new List<ElementGeometry>();
RebarElementGeometry.Add(Geometry);
ExchangeDataWrapper.SetElementGeometryByElement(RebarChildElement, RebarElementGeometry);
Primitive Geometry
Generate a basic geometry using the Autodesk.GeometryPrimitive class.
Create Primitive Geometry using the ElementDataModel.CreatePrimitiveGeometry method. This method requires GeometryProperties instance which requires the primitive geometry definition and a RenderStyle instance.
If you want to add multiple primitive geometries to an element efficiently, it is recommended to use instance of GeometryContainer to create multiple primitive geometry.
Here is an example of how to add two lines to a single element using GeometryContainer:
var lineGeomContainer = new GeometryContainer()
{
Curves = new CurveArray()
{
new Line()
{
Position = new PrimitiveGeometry.Math.Point3d(0, 0, 0),
Direction = new PrimitiveGeometry.Math.Vector3d(1, 0, 0),
Range = new ParamRange(ParamRange.RangeType.Finite, -1000, 1000)
},
new Line()
{
Position = new PrimitiveGeometry.Math.Point3d(0, 0, 0),
Direction = new PrimitiveGeometry.Math.Vector3d(1, 0, 0),
Range = new ParamRange(ParamRange.RangeType.Finite, -1000, 1000)
},
}
};
var element = ElementDataModel.AddElement(new ElementProperties("Id","elementname", "category", "family", "type"));
// Create Geometry
var elementPrimitiveGeometry = ElementDataModel.CreatePrimitiveGeometry(new GeometryProperties(primitivegeometry, RenderStyle));
// Map elements and geometry.
var elementGeometry = new List<ElementGeometry> { elementPrimitiveGeometry };
ElementDataModel.SetElementGeometryByElement(element, elementGeometry);
Apply Transformations to elements
You can apply the transformation to a Data Exchange element by calling the overload of ElementDataModel.AddElement method, which accepts an ElementProperties construct with a 4d transformation matrix.
var ElementProperty = new ElementProperties
{
Name = "Name_For_Element_Propeties",
ElementId = "Id",
Category = "category",
Family = "family",
Type = "type",
Transformation = new Transformation
{
Matrix = new Matrix4d(new float[] {
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1})
}
};
var element = ElementDataModel.AddElement(ElementProperty);
Set Units to elements
The default values of LengthUnit and DisplayLengthUnit of the data exchange element and geometry are set to feet if not set explicitly.
Important: It is recommended that you set the LengthUnit to match the host application’s document unit. For example, if you create a model in the host application in millimeter and create a data exchange without setting the length unit explicitly, then the data exchange will use the default units of measurement, which is ‘feet’, leading to a mismatch of units. This may lead to inaccurate data, unless you perform scaling of the geometry during both the creation and loading of the exchange to correct the values.
To set units on the element use the ElementProperties object as shown in the following code sample.
var element = ElementDataModel.AddElement(new ElementProperties("Id","elementname", "category", "family", "type")
{
LengthUnit = UnitFactory.MilliMeter,
DisplayLengthUnit = UnitFactory.MilliMeter
});
To set units on the element geometry use the GeometryProperties object as shown in the following code sample.
// Set units using GeometryProperties
var Geometry = ElementDataModel.CreateGeometry(new GeometryProperties(Path, RenderStyle)
{
LengthUnit = UnitFactory.MilliMeter,
DisplayLengthUnit = UnitFactory.MilliMeter,
DisplayAngleUnit = UnitFactory.Radian
});
The Autodesk.DataExchange.SchemaObjects.Units.UnitFactory includes commonly supported units such as feet, meter, and inches.
Add Parameters to elements
There are two general types of parameters that can be added to an element:
- Built-In Parameters: Generate a ParameterDefinition instance using the static ParameterDefinition.Create method, which takes an Autodesk.Parameters.Parameter enum and a ParameterDataType enum as inputs. The specific type of parameter instance is determined by the ParameterDataType provided. After creating the parameter instance, assign a value to it.
- Custom Parameters: Use the static ParameterDefinition.Create method to generate a ParameterDefinition instance, where the method requires a string schemaId and an enum ParameterDataType as inputs. The nature of the parameter instance produced depends upon the provided ParameterDataType. Use IsCustomParameter=true instead of IsForceCheckFSSSChemaPresent which is deprecated in order to mark this parameter as custom parameter. Subsequently, assign a value to the recently instantiated parameter instance.
To create the schemaId, you will require the schemaNamespace. When an exchange container is first created using the IClient.CreateExchangeAsync method, it returns an ExchangeDetails object, which contains a property called schemaNamespace. This schemaNamespace can be used to produce the schema ID. As a best practice, we should ideally avoid using ForgeParametersCLR or ForgeUnitsCLR directly for parameter processing (for example, create, update, etc.) to minimize the risk of breaking changes caused by updates to these assemblies.
Create the parameter with the help of Element.CreateInstanceParameterAsync method and pass the instance of CustomParameter.
// Instance parameters
// Built-In Parameters
var Parameter = ParameterDefinition.Create(Autodesk.Parameters.Parameter.<Built-In-Parameter>, ParameterDataType);
((<Cast-As-Per-DataType>)Parameter).Value = data;
element.CreateInstanceParameterAsync(Parameter);
// Custom Parameters
var SchemaId = "exchange.parameter." + schemaNamespace + ":<parameterTypeSchema>";
ParameterDefinition CustomParameter = ParameterDefinition.Create(SchemaId, ParameterDataType);
CustomParameter.Name =;
CustomParameter.SampleText =;
CustomParameter.Description =;
CustomParameter.ReadOnly =;
customParameterFloat.IsCustomParameter = true;
CustomParameter.GroupID = Group.General.DisplayName();
((<Cast-As-Per-DataType>)CustomParameter).Value = data;
element.CreateInstanceParameterAsync(CustomParameter);
Create the parameter with the help of ElementDataModel.CreateTypeParameterAsync method and pass the instance of CustomParameter.
Type parameters are parameters that apply to all elements of a specific type. Modifying a type parameter will apply that change to all elements that belong to that type. This simplifies the management of common properties based on a common type.
To create a type parameter, first ensure that the “type” has been defined. A type is automatically defined when an element specifies a type during its creation. Once the following line in the code sample is executed, the “MyType” type is defined and can be used to set type parameters.
var Element = model.AddElement(new ElementProperties("<Id>", "<elementname>", "<category>", "<family>", "MyType"));
At this point, other elements with the same type can also be created. All of these elements will share the same type parameters.
To create a type parameter, use the ElementDataModel.CreateTypeParameterAsync method by passing in the “MyType” string and the parameter to set. This differs from instance parameters, where the parameter is set to the individual element. Type parameters, on the other hand, are shared across all elements of that type. An element’s TypeParameters
property lists all the type parameters associated with that element.
// Instance parameters
// Built-In Parameters
var Parameter = ParameterDefinition.Create(parameterType, ParameterDataType.Int64);
(Int64ParameterDefinition)Parameter).Value = 100;
ElementDataModel.CreateTypeParameterAsync("MyType", Parameter);
// Custom Parameters
var SchemaId = "exchange.parameter." + schemaNamespace + ":<parameterTypeSchema>";
ParameterDefinition CustomParameter = ParameterDefinition.Create(SchemaId, ParameterDataType);
CustomParameter.Name =;
CustomParameter.SampleText =;
CustomParameter.Description =;
CustomParameter.ReadOnly =;
customParameterFloat.IsCustomParameter = true;
CustomParameter.GroupID = Group.General.DisplayName();
((<Cast-As-Per-DataType>)CustomParameter).Value = data;
ElementDataModel.CreateTypeParameterAsync("Generic Object",CustomParameter);
ParameterDefinition types as per parameter data type:
- BoolParameterDefinition -> Bool
- Int64ParameterDefinition -> int64
- MeasurableParameterDefinition -> float
- StringParameterDefinition -> string
Publish/Sync
In the preceding steps, we have already created the ElementDataModel and added geometry and parameters into it locally. To sync or update this data to the Data Exchange make a call to the SyncExchangeDataAsync method on the IClient interface.
var ExchangeIdentifier = new DataExchangeIdentifier
{
CollectionId = CollectionID,
ExchangeId = ExchangeID,
HubId = hubId
};
var ExchangeData = ElementDataModel.ExchangeData;
await IClient.SyncExchangeDataAsync(ExchangeIdentifier, ExchangeData);
Viewable generation
Once the data has been synced to the Data Exchange, you can generate a visual representation of the data by calling the GenerateViewableAsync method on the IClient interface. This method requires inputs such as the exchange id, collection id, and viewableWorldCoordinates.
IClient.GenerateViewableAsync(ExchangeId, CollectionId);
The ExchangeId and CollectionId can be retrieved from the ExchangeDetails object returned by the CreateExchangeAsync method.