Is there a way to convert a System.IO.Stream to a Windows.Storage.Streams.IRandomAccessStream?

C#.NetWindowsWindows 8

C# Problem Overview


In Windows 8; I would like to pass the contents of a MemoryStream to a class that accepts a parameter of type Windows.Storage.Streams.IRandomAccessStream. Is there any way to convert this MemoryStream to an IRandomAccessStream?

C# Solutions


Solution 1 - C#

To use the extensions: you must add "using System.IO"

In Windows8, .NET and WinRT types are generally converted to/from compatible types under the hood so you don't have to care about it.

For streams, however, there are helper methods to convert between WinRT and .NET streams: For converting from WinRT streams -> .NET streams:

InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere.
System.IO.Stream inputStream = win8Stream.AsStream()

For converting from .NET streams -> WinRT streams:

Windows.Storage.Streams.IInputStream inStream = stream.AsInputStream();
Windows.Storage.Streams.IOutputStream outStream = stream.AsOutputStream();

UPDATE: 2013-09-01

Let it not be said that Microsoft doesn't listen to it's developer community ;)

In the announcement for .NET FX 4.5.1, Microsoft states that:

> Many of you have been wanting a way to convert a .NET Stream to a Windows Runtime IRandomAccessStream. Let’s just call it an AsRandomAccessStream extension method. We weren't able to get this feature into Windows 8, but it was one of our first additions to Windows 8.1 Preview. > > You can now write the following code, to download an image with HttpClient, load it in a BitmapImage and then set as the source for a Xaml Image control.

    //access image via networking i/o
    var imageUrl = "http://www.microsoft.com/global/en-us/news/publishingimages/logos/MSFT_logo_Web.jpg";
    var client = new HttpClient();
    Stream stream = await client.GetStreamAsync(imageUrl);
    var memStream = new MemoryStream();
    await stream.CopyToAsync(memStream);
    memStream.Position = 0;
    var bitmap = new BitmapImage();
    bitmap.SetSource(memStream.AsRandomAccessStream());
    image.Source = bitmap;

HTH.

Solution 2 - C#

Found a more elegant solution:

public static class MicrosoftStreamExtensions
{
public static IRandomAccessStream AsRandomAccessStream(this Stream stream)
{
return new RandomStream(stream);
}




}




class RandomStream : IRandomAccessStream
{
Stream internstream;



public RandomStream(Stream underlyingstream)
{
    internstream = underlyingstream;
}

public IInputStream GetInputStreamAt(ulong position)
{
    //THANKS Microsoft! This is GREATLY appreciated!
    internstream.Position = (long)position;
    return internstream.AsInputStream();
}

public IOutputStream GetOutputStreamAt(ulong position)
{
    internstream.Position = (long)position;
    return internstream.AsOutputStream();
}

public ulong Size
{
    get
    {
        return (ulong)internstream.Length;
    }
    set
    {
        internstream.SetLength((long)value);
    }
}

public bool CanRead
{
    get { return this.internstream.CanRead; }
}

public bool CanWrite
{
    get { return this.internstream.CanWrite; }
}

public IRandomAccessStream CloneStream()
{
    throw new NotSupportedException();
}

public ulong Position
{
    get { return (ulong)this.internstream.Position; }
}

public void Seek(ulong position)
{
    this.internstream.Seek((long)position, SeekOrigin.Begin);
}

public void Dispose()
{
    this.internstream.Dispose();
}

public Windows.Foundation.IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
{
    return this.GetInputStreamAt(this.Position).ReadAsync(buffer, count, options);
}

public Windows.Foundation.IAsyncOperation<bool> FlushAsync()
{
    return this.GetOutputStreamAt(this.Position).FlushAsync();
}

public Windows.Foundation.IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer)
{
    return this.GetOutputStreamAt(this.Position).WriteAsync(buffer);
}




}

}

Solution 3 - C#

After some experimenting I found the following code to be working.

using System;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage.Streams;

partial class MainPage
{
    public MainPage()
    {
        var memoryStream = new MemoryStream(new byte[] { 65, 66, 67 });
        ConvertToRandomAccessStream(memoryStream, UseRandomAccessStream);
        InitializeComponent();
    }

    void UseRandomAccessStream(IRandomAccessStream stream)
    {
        var size = stream.Size;
    } // put breakpoint here to check size

    private static async void ConvertToRandomAccessStream(MemoryStream memoryStream,
         Action<IRandomAccessStream> callback)
    {
        var randomAccessStream = new InMemoryRandomAccessStream();
        var outputStream = randomAccessStream.GetOutputStreamAt(0);
        var dw = new DataWriter(outputStream);
        var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
        task.Start();
        await task;
        await dw.StoreAsync();
        var success = await outputStream.FlushAsync();
        callback(randomAccessStream);
    }
}

UPDATE: I also tried more elegant method implementation:

    private static void ConvertToRandomAccessStream(MemoryStream memoryStream,
        Action<IRandomAccessStream> callback)
    {
        var randomAccessStream = new InMemoryRandomAccessStream();
        var outputStream = randomAccessStream.GetOutputStreamAt(0);
        RandomAccessStream.Copy(memoryStream.AsInputStream(), outputStream);
        callback(randomAccessStream);
    }

Strangely, it doesn't work. When I call stream.Size later, I get zero.

UPDATE I changed the function to return the IRandomAccessStream rather than using the callback function

public static async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
{
	var randomAccessStream = new InMemoryRandomAccessStream();

	var outputStream = randomAccessStream.GetOutputStreamAt(0);
	var dw = new DataWriter(outputStream);
	var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
	task.Start();
	
	await task;
	await dw.StoreAsync();
	
	await outputStream.FlushAsync();
	
	return randomAccessStream;
}

Solution 4 - C#

There is no built-in way method on Windows 8. For Windows 8.1 we added a Stream.AsRandomAccessStream() extension method:

internal static IRandomAccessStream ToRandomAccessStream(byte[] array)
{
    MemoryStream stream = new MemoryStream(array);
    return stream.AsRandomAccessStream();
}

Solution 5 - C#

None of the above works for me today (maybe some API changes since the answers were posted). The only way that works is

IRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();
using (var inputStream = stream.AsInputStream())
{
    await RandomAccessStream.CopyAsync(inputStream, inMemoryStream);
}
inMemoryStream.Seek(0);

Solution 6 - C#

This code snippet turns a stream (stream) into an InMemoryRandomAccessStream (ims) which implement IRandomAccessStream. The trick is that CopyTo has to be called on a background thread.

        InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream();
        var imsWriter = ims.OpenWrite();
        await Task.Factory.StartNew(() => stream.CopyTo(imsWriter));

Solution 7 - C#

Take a look to this link:

How To Convert Byte Array To IRandomAccessStream

It also gives examples and an implementation of a byte array constructor (and one for .NET streams), useful if you want to use the SetSource or SetSourceAsync methods of BitmapImage class (as in my case).

Hope this helps someone...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbbosakView Question on Stackoverflow
Solution 1 - C#Rich TurnerView Answer on Stackoverflow
Solution 2 - C#bbosakView Answer on Stackoverflow
Solution 3 - C#Roman BoikoView Answer on Stackoverflow
Solution 4 - C#Immo LandwerthView Answer on Stackoverflow
Solution 5 - C#Igor KulmanView Answer on Stackoverflow
Solution 6 - C#Robert LevyView Answer on Stackoverflow
Solution 7 - C#MAXEView Answer on Stackoverflow