How to send canvas image large size from silverlight to WCF service - wcf

I have a large size byte[] formed from silverlight Canvas using following code
var img = new WriteableBitmap(cnvControlHolder, null);
var outStream = new MemoryStream();
EncodeJpeg(img, outStream);
Now I want to send this to WCF service to form image from this byte array & save it as an image on server side so that I can consume it in SSRS. My problem is as the byte[] is big I get the classic Method not found from WCF service.
I read in few links that WCF streaming would be one option, but could not find any sample on the net. My service method is like this:
public bool Upload(Stream image)
{
FileStream fileStream = null;
BinaryWriter writer = null;
var filePath = HttpContext.Current.Server.MapPath(".") + #"\" +
ConfigurationManager.AppSettings["PictureUploadDirectory"] + #"\Diagram.jpeg";// +image.ImageName;
if (image!=null)
{
//return ByteArrayToFile(filePath, image.Imagestream);
fileStream = File.Open(filePath, FileMode.Create);
writer = new BinaryWriter(fileStream);
writer.Write("Diagram.jpeg");
}
return false;
}
and client call is this :
var img = new WriteableBitmap(canvas1, null);
var outStream = new MemoryStream();
EncodeJpeg(img, outStream); //custom library to compress into jpeg
var client = new Service1Client();
client.UploadCompleted += new EventHandler<UploadCompletedEventArgs>(client_UploadCompleted);
client.UploadAsync(outStream.ToArray());
Can somebody suggest some sample or any other solution to fix my issue.

I recently implemented a very similar solution in Silverlight. The solution involves:
Dividing the large byte[] into n chunks of size that can be sent via a web service call
Making a web call to the service, registering a file upload request for n chunks, and requesting a guid from the service.
Making n web calls to the service and uploading each chunk, supplying the guid and the ordinal of the chunk (the chunks may arrive out of sequence).
Once the server receives all n chunks, it combines the chunks and writes the data into a file.
I hope this can help to get you started.

Related

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.

Windows Azure UploadFromStream No Longer Works After Porting to MVC4 - Pointers?

Updated my MVC3/.Net 4.5/Azure solution to MVC4.
My code for uploading an image to blob storage appears to fail each time in the upgraded MVC4 solution. However, when I run my MVC3 solution works fine. Code that does the uploading, in a DLL, has not changed.
I’ve uploaded the same image file in the MVC3 and MVC4 solution. I’ve inspected in the stream and it appears to be fine. In both instance I am running the code locally on my machine and my connections point to blob storage in cloud.
Any pointers for debugging? Any known issues that I may not be aware of when upgrading to MVC4?
Here is my upload code:
public string AddImage(string pathName, string fileName, Stream image)
{
var client = _storageAccount.CreateCloudBlobClient();
client.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(5));
var container = client.GetContainerReference(AzureStorageNames.ImagesBlobContainerName);
image.Seek(0, SeekOrigin.Begin);
var blob = container.GetBlobReference(Path.Combine(pathName, fileName));
blob.Properties.ContentType = "image/jpeg";
blob.UploadFromStream(image);
return blob.Uri.ToString();
}
I managed to fix it. For some reason reading the stream directly from the HttpPostFileBase wasn't working. Simply copy it into a new memorystream solved it.
My code
public string StoreImage(string album, HttpPostedFileBase image)
{
var blobStorage = storageAccount.CreateCloudBlobClient();
var container = blobStorage.GetContainerReference("containerName");
if (container.CreateIfNotExist())
{
// configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
}
string uniqueBlobName = string.Format("{0}{1}", Guid.NewGuid().ToString(), Path.GetExtension(image.FileName)).ToLowerInvariant();
CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = image.ContentType;
image.InputStream.Position = 0;
using (var imageStream = new MemoryStream())
{
image.InputStream.CopyTo(imageStream);
imageStream.Position = 0;
blob.UploadFromStream(imageStream);
}
return blob.Uri.ToString();
}

How do stream a file from WCF that didn't originate from a filesystem. (sharepoint content database)

I'm trying to return a stream in WCF 3.5 using a REST-Style URL instead of SOAP. The idea is to read a file from SharePoint 2010, then pass it back to the client. (We have reasons for doing it this way instead of using SharePoint services, but I digress.) It appears as though the only way to send the file is by writing it to the filesystem using one FileStream, then using File.OpenRead to return the stream back to the client. Using a MemoryStream doesn't seem to work. IE prompts for the file save, but the file comes down as like 2KB and then can't be read of course because it's not all there. Any ideas?
SPListItemCollection lookupFld2 = docLibrary.GetItems(spQuery2);
if (lookupFld2.Count > 0)
{
WebOperationContext.Current.OutgoingResponse.ContentType =
"application/octet-stream";
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Content-Disposition","attachment; filename=" + lookupFld2[0].File.Name);
MemoryStream memoryStream =
(MemoryStream)lookupFld2[0].File.OpenBinaryStream();
memoryStream.Position = 0;
return memoryStream;
}
Technically, OpenBinaryStream only returns a general Stream instance NOT a MemoryStream (http://msdn.microsoft.com/en-us/library/ms470901.aspx). If you want a MemoryStream you need to create a new one and copy the contents from the BinaryStream into the MemoryStream then reset the position and return it.

Restful WCF Service - returning byte[]?

I'm working with a RESTful WCF service. One of the service methods returns byte[] (which contains a file).
On the client side, I have some code that uses the WebRequest class to invoke that particular service method. Using the WebRequest, I'm getting the response stream like:
Stream stream = webReq.GetResponse().GetResponseStream();
From this stream, I am then reconstructing a byte[] and then outputting the File locally. The problem is that the reconstructed file on the client-side doesn't resemble the file that was returned from the service side (I get a corrupt PDF file that is much larger in size than the one sent from the service side). Just before the service method returns the byte[], I outputted that byte[] to disk on the service side and it created the file fine... This points to something going wrong between that method returning the byte[] and my client side reconstructing the byte[] from a Stream on the client side... to reconstruct the byte[] from the Stream, I'm using the following method which someone posted in the past on stackoverflow:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Any ideas what could be going wrong?
I guess that the response from the server contains some envelope in addition to the raw bytes. Like a XML envelope or something. Which would of course suppose that the bytes are base64 encoded string in the response because you cannot store binary data into XML. It would also explain why you are getting a bigger buffer on the client than the actual PDF that the server has sent.
This will of course depend on what binding your WCF service uses and how is it configured. When you dump the contents of the MemoryStream you are reading on the client what exactly do you see? This should give you further hints on how the actual PDF file is encoded in the HTTP response body.

Returning Azure BLOB from WCF service as a Stream - Do we need to close it?

I have a simple WCF service that exposes a REST endpoint, and fetches files from a BLOB container. The service returns the file as a stream. i stumbled this post about closing the stream after the response has been made :
http://devdump.wordpress.com/2008/12/07/disposing-return-values/
This is my code:
public class FileService
{
[OperationContract]
[WebGet(UriTemplate = "{*url}")]
public Stream ServeHttpRequest(string url)
{
var fileDir = Path.GetDirectoryName(url);
var fileName = Path.GetFileName(url);
var blobName = Path.Combine(fileDir, fileName);
return getBlob(blobName);
}
private Stream getBlob(string blobName)
{
var account = CloudStorageAccount.FromConfigurationSetting("ConnectingString");
var client = account.CreateCloudBlobClient();
var container = client.GetContainerReference("data");
var blob = container.GetBlobReference(blobName);
MemoryStream ms = new MemoryStream();
blob.DownloadToStream(ms);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
So I have two question :
Should I follow the pattern mentioned in the post ?
If I change my return type to Byte[], what are Cons/Pros ?
( My client is Silverlight 4.0, just in case it has any effect )
I'd consider changing your return type to byte[]. It's tidier.
Stream implements IDisposable, so in theory the consumer of your method will need to call your code in a using block:
using (var receivedStream = new FileService().ServeHttpRequest(someUrl))
{
// do something with the stream
}
If your client definitely needs access to something that Stream provides, then by all means go ahead and return that, but by returning a byte[] you keep control of any unmanaged resources that are hidden under the covers.
OperationBehaviorAttribute.AutoDisposeParameters is set to TRUE by default which calls dispose on all the inputs/outputs that are disposable. So everything just works.
This link :
http://devdump.wordpress.com/2008/12/07/disposing-return-values/
explains how to manually control the process.