Dealing with blob data in HealthVault XML
I recently had a request for more information on dealing with blob data using our newly-released Mobile support, which finally got me to write something about low-level blob support.
This information applies to any application that isn’t using the .NET SDK to talk to HealthVault. If you are using the .NET SDK, I recommend using the support that is provided in the SDK.
HealthVault Blob Options
HealthVault provides the capability of storing additional data – such as documents, images, etc. – as a blob of data attached to any of the HealthVault data types.
HealthVault provides two ways for applications to manage blob data; an inline method where the blob data is passed with the rest of the data for an item instance, and a streaming approach where blob data is accessed through http get and put requests.
Inline blob data
This method passes the blob data in a base64-encoded format with the rest of the item data. It’s the simpler of the methods to use, but it has the following drawbacks:
- The total size of a HealthVault request has a maximum, which limits the space available for blob data to approximately 5MB (this limit is subject to change).
- The total size of a HealthVault response has a maximum size, which limits how much blob data can be retrieved, especially if multiple objects with blobs are returned.
- When the blob data is fetched for an object, data for all blobs is fetched; it isn’t possible to fetch the data for a single blob.
- Network use will be a little higher and data will be slower since the base64 encoding is a little (about 1/3) bigger than the raw bytes.
Here’s how you deal with blob data using the inline method:
Fetching blob data as inline data
Here’s the “<info>” section of a GetThings request:
<info>
<group>
<filter>
<type-id>3d34d87e-7fc1-4153-800f-f56592cb0d17</type-id>
<thing-state>Active</thing-state>
</filter>
<format>
<section>core</section>
<section>blobpayload</section>
<xml/>
<type-version-format>3d34d87e-7fc1-4153-800f-f56592cb0d17</type-version-format>
<blob-payload-request>
<blob-format>
<blob-format-spec>inline</blob-format-spec>
</blob-format>
</blob-payload-request>
</format>
</group>
</info>
The “<section>blobpayload</section>” line specifies that in addition to the core part of the data item, any blob data should be passed back along with the rest of the XML. If you forget to do that, you won’t get any blob data…
This query returns a <blob-payload> section that comes after the <data-xml> section:
<blob-payload>
<blob>
<blob-info>
<name />
<content-type>text/plain</content-type>
<hash-info>
<algorithm>SHA256Block</algorithm>
<params>
<block-size>2097152</block-size>
</params>
<hash>K9OYLkNyHLtTKRinTVTPh4WqbsZQ5l3jcUBIoMieNIc=</hash>
</hash-info>
</blob-info>
<content-length>11</content-length>
<base64data>U2FtcGxlIFRleHQ=</base64data>
</blob>
</blob-payload>
The following elements are important:
- name: The name of the blob.
- content-type: The content type that was specified when the blob was saved
- content-length: The length of the blob
- base64data: The blob data
Uploading blob data as inline data
Here’s an example of saving a blob as inline data. The blob is passed at the same time the rest of the data for the instance is passed.
<info>
<thing>
<type-id>3d34d87e-7fc1-4153-800f-f56592cb0d17</type-id>
<thing-state>Active</thing-state>
<flags>0</flags>
<data-xml>...</data-xml>
<blob-payload>
<blob>
<blob-info>
<name/>
<content-type>text/plain</content-type>
</blob-info>
<content-length>4</content-length>
<base64data>U2FtcGxlIFRleHQ=</base64data>
</blob>
</blob-payload>
</thing>
</info>
The <data-xml> section is removed for the sake of brevity. The important parts are:
- name: The name of the blob
- content-type: The encoding of the data
- content-length: The length of the data in bytes
- base64data: The data expressed in base64 format
Streamed blob data
In the streamed method, the blog data is fetched or stored using separate interfaces or methods.
Fetching blob data as streamed data
Fetching the blob data is simple. If you change the filter to be:
<blob-format-spec>streamed</blob-format-spec>
Instead of the base64data element, you will get a blob-ref-url element that looks something like this:
You can then download the blob data directly using the URL.
Uploading blob data as streamed data
Uploading blob data through the streamed interface is considerably more complex; it requires calling the BeginPutBlob method to get the destination url and then uploading in chunks of data that are a specific size (it also supports signing data, which makes things even more complex).
If you are interested in using this to load large blobs, let me know, and I’ll try to update this to show that approach as well.