Windows Store 8.1: WebView.NavigateToStream does not work when altering stream - xaml

I am currently trying to use the WebView to display encrypted data (using DPP). The issue is that I am not able to get the WebView to show anything if the stream is manipulated in any way after reading the StorageFile into an IRandomAccessStream (ie. unencrypt the data).
This issue can easily be reproduced by using the source provided by Microsoft: http://code.msdn.microsoft.com/windowsapps/XAML-WebView-control-sample-58ad63f7
and altering the "StreamUriWinRTResolver" class to convert the IRandomAccessStream to a memory stream and then back again. Basically, in S4_NavToStream.xaml.cs at line 128, change this:
StorageFile f = item as StorageFile;
IRandomAccessStream stream = await f.OpenAsync(FileAccessMode.Read);
return stream.GetInputStreamAt(0);
With this:
StorageFile f = item as StorageFile;
IRandomAccessStream randStream = await f.OpenAsync(FileAccessMode.Read);
var stream = randStream.AsStream();
MemoryStream ms = new MemoryStream();
stream.CopyTo(ms);
return ms.AsInputStream();
This will show a blank page when run. I'm starting to think this is a bug, unless of course I'm using the stream conversions incorrectly. Has anybody tried anything similar?

Thomas Huber has very graciously answered my question over on social.msdn.microsoft.com. Full answer here:
http://social.msdn.microsoft.com/Forums/en-US/f51ab699-66c3-4961-8952-fbe341bf3e23/windows-81-webviewnavigatetostream-does-not-work-when-altering-the-stream
In summary, the issue is around the conversion of the memory stream to an input stream. This is the correct working code:
StorageFile f = item as StorageFile;
IRandomAccessStream randStream = await f.OpenAsync(FileAccessMode.Read);
var stream = randStream.AsStream();
var ms = new MemoryStream();
stream.CopyTo(ms);
InMemoryRandomAccessStream msras = new InMemoryRandomAccessStream();
DataWriter dw = new DataWriter(msras);
dw.WriteBytes(ms.ToArray());
await dw.StoreAsync();
var inputStream= msras.GetInputStreamAt(0);
return inputStream;

Related

.NET Core API saving image upload asynchronously with ImageSharp, MemoryStream and FileStream

I have a .NET Core API that I'd like to extend to save uploaded images asynchronously.
Using ImageSharp I should be able to check uploads and resize if predefined size limits are exceeded. However I can't get a simple async save working.
A simple (non-async) save to file works without problem:
My Controller extracts IFormFile from the upload and calls the following method without any problem
public static void Save(IFormFile image, string imagesFolder)
{
var fileName = Path.Combine(imagesFolder, image.FileName);
using (var stream = image.OpenReadStream())
using (var imgIS = Image.Load(stream, out IImageFormat format))
{
imgIS.Save(fileName);
}
}
ImageSharp is currently lacking async methods so a workaround is necessary.
The updated code below saves the uploaded file but the format is incorrect - when viewing the file I get the message "It appears we don't support this file format".
The format is extracted from the ImageSharp Load method. and used when saving to MemoryStream.
MemoryStream CopyToAsync method is used to save to FileStream to make the upload asynchronous.
public static async void Save(IFormFile image, string imagesFolder)
{
var fileName = Path.Combine(imagesFolder, image.FileName);
using (var stream = image.OpenReadStream())
using (var imgIS = Image.Load(stream, out IImageFormat format))
using (var memoryStream = new MemoryStream())
using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
{
imgIS.Save(memoryStream, format);
await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false);
fileStream.Flush();
memoryStream.Close();
fileStream.Close();
}
}
I can't work out whether the issue is with ImageSharp Save to MemoryStream, or the MemoryStream.CopyToAsync.
I'm currently getting 404 on SixLabors docs - hopefully not an indication that the project has folded.
How can I make the upload async and save to file in the correct format?
CopyToAsync copies a stream starting at its current position. You must change the current position of memoryStream back to start before copying:
// ...
memoryStream.Seek(0, SeekOrigin.Begin);
await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false);
// ...

Power App - generate PDF

I got an assignment to see if I can make power app that will generate some PDF file for end user to see.
After through research on this topic I found out that this is not an easy to achieve :)
In order to make power app generate and download/show generated pdf I made these steps:
Created power app with just one button :) to call Azure function from step 2
Created Azure function that will generate and return pdf as StreamContent
Due to power app limitations (or I just could not find the way) there was no way for me to get pdf from response inside power app.
After this, I changed my Azure function to create new blob entry but know I have problem to get URL for that new entry inside Azure function in order to return this to power app and then use inside power app Download function
My Azure function code is below
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, Stream outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
stream.CopyTo(outputBlob);
// result.Content = new StreamContent(stream);
// result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
// result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(pdfFile);
// result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// result.Content.Headers.ContentLength = stream.Length;
return result;
}
I left old code (the one that streams pdf back under comments just as reference of what I tried)
Is there any way to get download URL for newly generated blob entry inside Azure function?
Is there any better way to make power app generate and download/show generated PDF?
P.S. I tried to use PDFViewer control inside power app, but this control is completely useless cause U can not set Document value via function
EDIT: Response from #mathewc helped me a lot to finally wrap this up. All details are below.
New Azure function that works as expected
#r "Microsoft.WindowsAzure.Storage"
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
using Microsoft.WindowsAzure.Storage.Blob;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, CloudBlockBlob outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
outputBlob.UploadFromStream(stream);
return req.CreateResponse(HttpStatusCode.OK, outputBlob.Uri);
}
REMARKS:
Wee need to add "WindowsAzure.Storage" : "7.2.1" inside project.json. This package MUST be the same version as one with same name that is in %USERPROFILE%\AppData\Local\Azure.Functions.Cli
If you change your blob output binding type from Stream to CloudBlockBlob you will have access to CloudBlockBlob.Uri which is the blob path you require (documentation here). You can then return that Uri back to your Power App. You can use CloudBlockBlob.UploadFromStreamAsync to upload your PDF Stream to the blob.

Attaching an Image to Work item in Visual Studio Team Services (was Visual Studio Online)

I'm sending an attachment through the Visual Studio Team Services API and it all look like its fine, until I look at the attachment on the work item.
The attachment should be a picture, but it a little black box with a white cross.
Has anyone had this issue and does anyone know what I've done wrong?
I get the image and convert it to a 64 Base string
FileInfo info = new FileInfo(attachment.Path);
byte[] bytes = File.ReadAllBytes(info.FullName);
String file = Convert.ToBase64String(bytes);
Then I send it to the API. This returns a message saying its been successful.
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(getConnectionDetails())));
using (System.Net.Http.HttpResponseMessage response = client.PostAsync(SetURL(url),
new StringContent(binaryString,Encoding.UTF8,"application/json")).Result)
{
response.EnsureSuccessStatusCode();
responseString = await response.Content.ReadAsStringAsync();
}
}
I think its something small, that I'm missing!
This is the link to the document, I have used.
API document
Try it this way:
...
string uri = "https://xxxxxx.visualstudio.com/_apis/wit/attachments?fileName=test.jpg&api-version=1.0";
string filepath = "C:\\images\\test.jpg";
FileStream files = new FileStream(filepath,FileMode.Open);
StreamContent streamcontent = new StreamContent(files);
...
HttpResponseMessage response = hc.PostAsync(uri, streamcontent).Result;
...

BitmapEncoder FlushAsync() never returns

I've scoured the web for this and not found a solution yet. I have a DispatchTimer in my Universal phone app. On each tick, I want to capture a portion of the screen and save it to JPEG. My code seems very straightforward, and there are no crashes -- it simply never returns from the FlushAsync(). It seems like it must be a deadlock scenario, but I haven't been able to find where the conflict is yet:
using (var ms = new MemoryStream())
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(ctrl);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
using (var ras = ms.AsRandomAccessStream())
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras, propertySet);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint) renderTargetBitmap.PixelWidth,
(uint) renderTargetBitmap.PixelHeight,
logicalDpi, logicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
return ms.ToArray();
}
Any help would be great! I've been at this for hours, trying different ways to get it working with no luck.
I figured it out! Turns out you can't just use MemoryStream.AsRandomAccessStream() as your encoder destination. Turns out you should just use the InMemoryRandomAccessStream, then afterwards get the bytes:
byte[] bytes = new byte[ras.Size];
await ras.AsStream().ReadAsync(bytes, 0, bytes.Length);
return bytes;
Not sure why MemoryStream caused the problem it did, but this is a pretty easy fix! I hope this helps someone else.

Winrt StreamWriter & StorageFile does not completely Overwrite File

Quick search here yielded nothing. So, I have started using some rather roundabout ways to use StreamWriter in my WinRT Application. Reading works well, writing works differently. What' I'm seeing is that when I select my file to write, if I choose a new file then no problem. The file is created as I expect. If I choose to overwrite a file, then the file is overwritten to a point, but the point where the stream stops writing, if the original file was large, then the old contents exist past where my new stream writes.
The code is as such:
public async void WriteFile(StorageFile selectedFileToSave)
{
// At this point, selectedFileToSave is from the Save File picker so can be a enw or existing file
StreamWriter writeStream;
Encoding enc = new UTF8Encoding();
Stream dotNetStream;
dotNetStream = await selectedFileToSave.OpenStreamForWriteAsync();
StreamWriter writeStream = new StreamWriter(dotNetStream, enc);
// Do writing here
// Close
writeStream.Write(Environment.NewLine);
await writeStream.FlushAsync();
await dotNetStream.FlushAsync();
}
Can anyone offer clues on what I could be missing? There are lots of functions missing in WinRT, so not really following ways to get around this
Alternatively you can set length of the stream to 0 with SetLength method before using StreamWriter:
var stream = await file.OpenStreamForWriteAsync();
stream.SetLength(0);
using (var writer = new StreamWriter(stream))
{
writer.Write(text);
}
Why not just use the helper methods in FileIO class? You could call:
FileIO.WriteTextAsync(selectedFileToSave, newTextContents);
If you really need a StreamWriter, first truncate the file by calling
FileIO.WriteBytesAsync(selectedFileToSave, new byte[0]);
And then continue with your existing code.