views:

512

answers:

4

I want to push a file to the browser from a website using a webservice. I'm currently reading the file into a base64 byte array, and returning that from the webservice. This webservice is called from a website, and i'm stuck on how to push this as the original file to the browser. Ideally I would like to read the byte array into a memory stream, and then just write it to the Response stream if possible so the end user just downloads the file.

+1  A: 

It's possible, you'll need to make sure you explicitly set the ContentType of the HttpResponse, for example:

Response.ContentType = "image/jpeg";
Response.OutputStream.Write(buffer, 0, buffer.Length);

If you want to control the file name, you'll have to add a Content-Disposition header. Google can help you find the right way to sort that out.

nullptr
+1, although you left out Content-Disposition, which is most important for file downloads. Edit: And then you added it. So ignore this. :)
Randolpho
+2  A: 

First, rather than send a base64 byte array, have your web service simply return a byte array for your file. Response.OutputStream.Write() will automatically base64 encode your bytes, so you might as well have them un-encoded in your memory stream.

Second, you'll need more than just the bytes. You'll need meta-data associated with the file. For the snippet below, I've placed all of that metadata into a separate class (local instance named "file"). Then, just use this snippet, once you have the data you need:

Response.Clear();
Response.ClearHeaders();
Response.ContentType = file.ContentType;
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + file.FileName + "\"");
Response.AddHeader("Content-Length", file.FileSize.ToString());
Response.OutputStream.Write(file.Bytes, 0, file.Bytes.Length);
Response.Flush();
Response.End();
Randolpho
Careful with Response.End() http://stackoverflow.com/questions/1087777/is-response-end-considered-harmful
Todd Smith
@Todd Smith: Thanks for the pointer. I was aware of the issue, but you're correct that others might not; it could be a serious gotcha. In the case of a file download, however, there is no further processing you want to or should do, and thus `Response.End()` *is* likely to be the correct call. It certainly is in my case.
Randolpho
Should i use Response.Close() instead of Repsonse.End() then?
what about using Response.TransmitFile from the web service - any reason not to do that?
Response.TransmitFile would work perfectly if the file existed as an unencrypted file on the file system of the server, as TransmitFile only needs a path to the file. Very frequently the file does not exist as a file mappable by TransmitFile. Sometimes it's stored in the database. Sometimes (hopefully always in enterprise situations, but that is, alas, not always the case) it's encrypted during storage and must be decrypted by the server before transmission.
Randolpho
A: 

It really depends on the interface to your webservice. Ie SOAP, REST, ASPX.

One thing you can try is to change the content-type in your Response to "Application/octet-stream". Or something similar to tell the receiver the MIME type.

If your using WCF rest you can use Stream as a return type on the web service.

Mark Milbourne
A: 

Its usually a bad idea to embed a file in a web service. You just add overhead and complexity with no real benefit.

Instead you should provide a IHttpHandler to handle the file upload. Most web servers also provide helper API's to simplify this, e.g. in ASP.NET you can access the uploaded file with:

HttpContext.Request.Files[0]

There are plenty of javascript file upload scripts that simplify this on the client: http://www.phpletter.com/Demo/AjaxFileUpload-Demo/

mythz
i am actually trying to download files to the client, not upload to the server