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 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.
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:
Here’s how you deal with blob data using the inline method:
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:
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:
In the streamed method, the blog data is fetched or stored using separate interfaces or methods.
Fetching the blob data is simple. If you change the filter to be:
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 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.