Please note that I have found embedding binary data in ExtensionDictionaries to be just as reliable as storing string data. I have actually taken to compressing the binary data stream stored in the drawing database to minimize the impact and drawing file size, but I embed large amounts of data, so maybe this added step is not needed for your application.
Here are two methods from a class I use to Save/Load my object graph from the drawing's NOD (maybe you can rework the code to be useful to you:
Private Sub SaveEstimateDataBinary(Doc As Document)
Dim cacheData As Byte()
'serialze block state cache object to binary
Using ms As New MemoryStream()
Dim ser As New BinaryFormatter()
Dim dwgModelMem As DrawingModelMemento = _Drawing.GetMemento()
ser.Serialize(ms, dwgModelMem)
cacheData = ms.ToArray()
End Using
'compress stream
Dim compressedDwgData As Byte()
Using destMS As New MemoryStream()
Using gz As New GZipStream(destMS, CompressionMode.Compress, True)
gz.Write(cacheData, 0, cacheData.Length)
End Using
compressedDwgData = destMS.ToArray()
End Using
'max BinaryChunk length is 255 bytes
Using buff As New ResultBuffer()
Dim position As Integer = 0
Dim remaining As Integer = compressedDwgData.Length
While remaining > 0
If remaining >= 255 Then
Dim chunk(254) As Byte
Buffer.BlockCopy(compressedDwgData, position, chunk, 0, 255)
buff.Add(New TypedValue(DxfCode.BinaryChunk, chunk))
remaining -= 255
position += 255
Else
Dim chunk(remaining - 1) As Byte
Buffer.BlockCopy(compressedDwgData, position, chunk, 0, remaining)
buff.Add(New TypedValue(DxfCode.BinaryChunk, chunk))
remaining = 0
End If
End While
Using tr As Transaction = Doc.TransactionManager.StartTransaction()
Try
Using nod As DBDictionary = tr.GetObject(Doc.Database.NamedObjectsDictionaryId, OpenMode.ForWrite, False)
'write object data to drawing db
If nod.Contains(DRAWING_NOD_KEY) Then
'update existing record
Using xrec As Xrecord = tr.GetObject(nod.GetAt(DRAWING_NOD_KEY), OpenMode.ForWrite)
xrec.Data = buff
End Using
Else
'create new record
Using xrec As New Xrecord()
xrec.Data = buff
nod.SetAt(DRAWING_NOD_KEY, xrec)
tr.AddNewlyCreatedDBObject(xrec, True)
End Using
End If
End Using
tr.Commit()
Catch ex As System.Exception
'TODO: Handle error
tr.Abort()
Throw ex
End Try
End Using
End Using
End Sub
Private Function LoadEstimateDataBinary(Doc As Document) As DrawingModelMemento
Dim dwgModelMem As DrawingModelMemento = Nothing
Using objStream As New MemoryStream()
Using sr As New BinaryWriter(objStream)
Using tr As Transaction = Doc.TransactionManager.StartTransaction()
Try
Using nod As DBDictionary = tr.GetObject(Doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead, False)
If Not nod.Contains(DRAWING_NOD_KEY) Then Throw New ApplicationException("NOD does not contain key " + DRAWING_NOD_KEY)
Using xrec As Xrecord = tr.GetObject(nod.GetAt(DRAWING_NOD_KEY), OpenMode.ForRead)
Using buff As ResultBuffer = xrec.Data
If buff Is Nothing Then Throw New ApplicationException("NOD entry with key " + DRAWING_NOD_KEY + " contains no data")
Dim tvals As TypedValue() = buff.AsArray()
Dim chunk As Byte()
If tvals.Length = 0 Then Throw New ApplicationException("NOD entry with key " + DRAWING_NOD_KEY + " contains too few entries")
If tvals(0).TypeCode <> DxfCode.BinaryChunk Then Throw New ApplicationException("NOD entry with key " + DRAWING_NOD_KEY + " contains header entry with incorrect data type")
For x As Integer = 0 To tvals.Length - 1
chunk = tvals(x).Value
sr.Write(chunk)
Next
sr.Flush()
End Using
End Using
End Using
Dim compressedData As Byte() = objStream.ToArray()
Using sourceMS As New MemoryStream(compressedData)
Using destMS As New MemoryStream()
Using gz As New GZipStream(sourceMS, CompressionMode.Decompress, True)
sourceMS.Position = 0
gz.CopyTo(destMS)
End Using
destMS.Position = 0
Dim ser As New BinaryFormatter()
dwgModelMem = ser.Deserialize(destMS)
End Using
End Using
tr.Commit()
Catch ex As System.Exception
tr.Abort()
Throw ex
End Try
End Using
End Using
End Using
Return dwgModelMem
End Function
I subscribe to the Document.Database class's BeginSave (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database.BeginSave) event, writing an updated version of my object graph to the drawings NOD each time the drawing is saved.
To support AutoSaves, you need to subscribe to the DocumentLockModeChanged event of the DocumentManager class. The DocumentLockModeChangedEventArgs object passed as an argument to your handler for this event provides the GlobalCommandName property. When this property is set to "AUTO_SAVE", you should serialize your class data and write it to the ExtensionDictionary. Note that you cannot lock the drawing when code is invoked from this event handler in this context. So you need to alter your code so that you do not attempt to lock the Document (you will need to lock the Document when invoking from the BeginSave event handler).
Oh, and use the DocumentManager.DocumentCreated event to determine if the drawing which has been opened contains you plugin's data. If it does, you want to load you embedded data and initialize your application UI. Subscribe to the DocumentManager events in the Initialize method of the IExtensionApplication interface in the Autodesk.AutoCAD.Runtime namespace. Use the Terminate method of that interface to clean up after your application.
Take the information I've provided with a grain of salt; there may be a better way to accomplish some of these requirements. I do not claim to be an expert, but the methods described have proved reliable over time and testing for me.
Kevin