How to use CreateStreamedFileAsync

The StorageFile.CreateStreamedFileAsync is a pretty neat mechanism that allows you to take a stream and use it like an IStorageFile. This is useful in a number of scenarios – especially ones where you are communicating with the OS or other apps (such as when using the share charm) and the “currency” used are StorageFile objects.

One thing you could do is simply write your streams into temporary files and hand those temporary files when needed. There’s a bunch of unnecessary IO happening in these cases – you write to disk and another app reads from disk where all you really want to do is straight up pass a stream.

Enter CreateStreamedFileAsync

I needed to use this method for an app, but something felt fishy about it.. Here’s the signature of the method:

public static IAsyncOperation<StorageFile> CreateStreamedFileAsync(
string displayNameWithExtension,
StreamedFileDataRequestedHandler dataRequested,
IRandomAccessStreamReference thumbnail
)

And the signature for the StreamedFileDataRequestedHandler callback:

public delegate void StreamedFileDataRequestedHandler(
StreamedFileDataRequest stream
)

The idea is simple – you call the CreateStreamedFileAsync() method and it returns a StorageFile object which is not fully realized yet.

When the caller tries to access the StorageFile,  it will activate the callback that will take a  StreamedFileDataRequest instance which will be used provide the content of the file.

But here lies the rub… There’s no obvious “completion” semantics for the call. The class passed in has no “complete” method like other mechanisms in WinRT seem to have. When called, how will the OS know that the file completed streaming?

I searched the web, StackOverflow, MS forums and the like. While there are a few people who inquire about it, there’s no clear answer. I have not been able to find any answer. And MSDN does not have any examples on how to use this.

It took me longer than I’d care to admit, but it finally dawned on me that there is indeed a completion semantics here – each stream can be closed (or disposed) and that can be used as the explicit completion semantics. A few minutes of work and what’d’ya know? That’s how you are supposed to use it!

The  code

Here’s what the code looks like. First, the code that creates and uses the StorageFile instance (note that I am using the most simplistic example I could think of – an example that doesn’t really need to use this mechanism but requires very little code):

private async void Button_Click(object sender, RoutedEventArgs e)
{
var file = await StorageFile.CreateStreamedFileAsync("file.txt", FileGrabber, null);
FileSavePicker picker = new FileSavePicker();
picker.DefaultFileExtension = ".txt";
picker.FileTypeChoices.Add("Text", new string[] { ".txt" });
var target = await picker.PickSaveFileAsync();
await file.CopyAndReplaceAsync(target);
}

The first call we make will create the streamed file, passing in the FileGrabber callback (shown below). We then use a picker to prompt the user for a file to save and we copy our streamed file into the picked file.

Here’s the interesting bit:

private async void FileGrabber(StreamedFileDataRequest request)
{
try
{
using (var stream = request.AsStreamForWrite())
using (var streamWriter = new StreamWriter(stream))
{
for (int i = 0; i < 5000; i++)
{
await streamWriter.WriteLineAsync("This should be the contents of the file.");
}
}
request.Dispose();
}
catch (Exception ex)
{
request.FailAndClose(StreamedFileFailureMode.Incomplete);
}
}

The call takes a StreamFileDataRequest which is an IOutputStream derivative (among others).

What we do then is as follows:

  1. We transform the stream into a .NET stream (by calling .AsStreamForWrite()).
  2. We create a writer on top of it.
  3. We then write into the stream we got from the OS the content we want saved.
  4. Then – when we are done, we Dispose() of the request which will signal the OS that we are done (this bit is important since, as you can see, we are awaiting for WriteLineAsync() to complete – if there was no completion semantics, the OS would think it was done as soon as that first await was hit.
  5. On failure, we make sure to call FailAndClose().

That’s it pretty much! Hopefully you find this and it saves you a bit of time.

Advertisements
This entry was posted in Dev, Windows8 and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s