How use the Byte Array of a image? - c#

So, i am getting the byte array of a LongRaw image from Oracle...
I am using a webapi to this. After get the array, how i use it on the Client-side ?
Do Its better i convert to base64string and pass this value converting just at the client side ?
cmd.InitialLONGFetchSize = -1;
var reader = cmd.ExecuteReader();
if (reader.Read())
{
// Fetch the LONG RAW
OracleBinary imgBinary = reader.GetOracleBinary(0);
// Get the bytes from the binary obj
byte[] imgBytes = imgBinary.IsNull ? null : imgBinary.Value;
//var imgString = Uri.EscapeDataString(Convert.ToBase64String(imgBytes));
}
//CRIO A LISTA
lretorno.Load(reader, LoadOption.OverwriteChanges, "BUSCAFOTO");
reader.Close();
connection.Close();
connection.Dispose();
var teste = lretorno.Tables[0].AsEnumerable().Select(row => new FotoEnvolvido
{
FOTO = (byte[])(row["FOTO"]),
//FOTO = Convert.ToString(row["FOTO"]),
});
return teste;

You can write a Web API Controller that returns the binary data of an image. Base64 strings impose a overhead of the amount of bytes that have to be transmitted. Please avoid this.
A sample controller can look like this example:
public class WebApiController : ApiController
{
public async Task<HttpResponseMessage> Get(string id)
{
var bytes = await GetBytesFromDataLayerAsync(id);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(bytes);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("image/jpeg");
return result;
}
private async Task<byte[]> GetBytesFromDataLayerAsync(string id)
{
// put your Oracle logic here
return ...
}
}

Depending on what your doing as rboe said writing the bytes directly to the client will save some data size(approx. 37%) and computing overhead. If your not only displaying jpeg images you should also set the mime-type to the correct value... take a look at this source for a rather complete set of extension to mime-type mappings. If you do not know the mime-type you can try "application/octet-stream" as that is the general mime-type for binary data.
If your displaying your content via web browser you could just use an <img> tag something like <img src="view_image.aspx?id=5"> you can even create the dynamically with javascript/jQuery.
If you really do want the image data embedded in a json request which might be useful if you have a lot of little icons and don't want a ton of requests (with http/2 I don't think this will matter) or another reason, then yes first encode the binary data using...
string base64EncodedData = Convert.ToBase64String(bytes);
If the client is javascript you can decode using the latest browsers native functions
var decodedImageData = window.atob(base64EncodedData);
See:
mozilla.org docs
This answer
This answer
If you are however just sending it to another c# endpoint you can use...
byte[] decodedImageData = Convert.FromBase64String(base64EncodedData);
And like I mentioned in the comment to ensure it's encrypted just make the site only support https:// and if you don't have a SSL cert you can get one for free from http://startssl.com

Related

C# Binary string to Bytearray without conversion

I call an API to get a PDF file. The API returns it as a string with binary data.
Now I need to save it to a file without any conversion of the data.
How can I do this in C#?
I have been trying
string file = await service.GetDocumentsAsync(document.FileId); // Gets the filedata
byte[] byteArray = file.Select (c => (byte)c).ToArray ();
using (var stream = new FileStream($"c:\\temp\\{document.Id}.pdf", FileMode.Create))
{
stream.Write (byteArray,0,file.Length);
stream.Close ();
}
I do get the PDF, but it only has blank pages.
The beginning of the string when i look at it in the Debugger:
As suggested we had to change what the API returned. We use RestSharp and had to use Response.RawByte iso. Response.

How to assemble file from byte[] via HTTP request method C#

I want to send file as byte[] to another PC via HTTP POST method. What is the most efficient way to assemble the file from byte[] on the other side? I am using File.ReadAllBytes method to get byte[] from file.
If you are using tcp the network protocol will make sure that your stream is coming in the right order and without dropped parts. Therefore, the simplest readstream will be the most efficient. If you want to use parallel routes and play with the datagrams.
If the file is large you will have to transmit and receive it in chunks. But the IP streams can hide that from you.
For example: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.getstream?view=netframework-4.7.2
This is what worked for me. I used this method to call api method and send file as byte[]. I tried sending whole byte[] but api method wasn't able to recive it.
private static async void SendFiles(string path)
{
var bytes = File.ReadAllBytes(path);
var length = bytes.Length;
foreach (var b in bytes)
{
length--;
string sendFilesUrl = $"http://api/communication/sendF/{b}/{length}";
StringContent queryString = new StringContent(bytes.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage response = await client.PostAsync(sendFilesUrl, queryString);
string responseBody = await response.Content.ReadAsStringAsync();
}
}
My api method is
[HttpPost]
[Route("sendF/{b}/{length}")]
public HttpResponseMessage SendF([FromUri]byte[] b, [FromUri]int length)
{
if(length != 0)
{
bytes.AddRange(b);
}
else
{
File.WriteAllBytes(#"G:\test\test.exe", bytes.ToArray<byte>());
}
return CreateResponse(client);
}
This code works for me but it takes very long to pass all bytes if the file is large. Currently I'm searching for more efficient way of sending bytes. One solution that came to my mind is to send byte[] in chunks

Returning a PDF from an ASP.NET Core 2 Controller

I am trying to return a PDF file from my ASP.NET Core 2 controller.
I have this code
(mostly borrowed from this SO question):
var net = new System.Net.WebClient();
//a random pdf file link
var fileLocation = "https://syntera.io/documents/T&C.pdf";/
var data = net.DownloadData(fileLocation);
MemoryStream content = null;
try
{
content = new MemoryStream(data);
return new FileStreamResult(content, "Application/octet-stream");
}
finally
{
content?.Dispose();
}
This code above is part of a service class that my controller calls. This is the code from my controller.
public async Task<IActionResult> DownloadFile(string fileName)
{
var result = await _downloader.DownloadFileAsync(fileName);
return result;
}
But I keep getting ObjectDisposedException: Cannot access a closed Stream.
The try and finally block was an attempt to fix it , from another SO question .
The main question is A) Is this the right way to send a PDF file back to the browser and B) if it isn't, how can I change the code to send the pdf to the browser?
Ideally , I don't want to first save the file on the server and then return it to the controller. I'd rather return it while keeping everything in memory.
The finally will always get called (even after the return) so it will always dispose of the content stream before it can be sent to the client, hence the error.
Ideally , I don't want to first save the file on the server and then return it to the controller. I'd rather return it while keeping everything in memory.
Use a FileContentResult class to take the raw byte array data and return it directly.
FileContentResult: Represents an ActionResult that when executed will write a binary file to the response.
async Task<IActionResult> DownloadFileAsync(string fileName){
using(var net = new System.Net.WebClient()) {
byte[] data = await net.DownloadDataTaskAsync(fileName);
return new FileContentResult(data, "application/pdf") {
FileDownloadName = "file_name_here.pdf"
};
}
}
No need for the additional memory stream
You must specify :
Response.AppendHeader("content-disposition", "inline; filename=file.pdf");
return new FileStreamResult(stream, "application/pdf")
For the file to be opened directly in the browser.

MVC providing runtime image not save on disk to browser

My MVC app creates images at runtime that I do NOT need to save on the disk.
What's the best way to send those to the requesting browser?
Note that the images will never be the same, so there is no reason to save them on disk first.
The server will draw the random image and will return the image to the calling client. I'm trying to understand what the best format for this type of operation is (bitmap, image ...) so that the streaming back to the server is as smooth and as fast as possible.
If you are sending them in the same page where you create it, then you can modify your Response to send it directly.
//After having your bitmap created...
MemoryStream ms = new MemoryStream();
bmp.Save(ms, ImageFormat.PNG);
bmp.Dispose();
byte[] data = ms.ToArray();
Response.ContentType = "image/png";
Response.ContentLength = data.Length;
using(var str = Response.GetResponseStream())
str.Write(data, 0, data.Length);
Response.End();
If you can get the bytes of the bitmap, then it's easy to return it to the client
public ActionResult GetImage()
{
byte[] byteArray = MagicMethodToGetImageData();
return new FileContentResult(byteArray, "image/jpeg");
}
Moreover, if you want to return the image plus some data, you can encode the bytes as base64 and wrap it in a JSON like this:
public ActionResult GetImage()
{
byte[] byteArray = MagicMethodToGetImageData();
var results = new
{
Image = Convert.ToBase64String(byteArray),
OtherData = "some data"
};
return Json(results);
}
One possibility would be to use the FileContentResult class to read the file content and directly show it or offer to download. A solution could look like this:
private FileContentResult getFileContentResult(string name, bool download = true)
{
if (!string.IsNullOrEmpty(name))
{
// don't forget to set the appropriate image MIME type
var result = new FileContentResult(System.IO.File.ReadAllBytes(name), "image/png");
if (download)
{
result.FileDownloadName = Server.UrlEncode(name);
}
return result;
}
return null;
}
The use this method in some Action like this:
public ActionResult GetImage(string name)
{
return getFileContentResult(name, true);
// or use the image directly for example in a HTML img tag
// return getFileContentResult(name);
}
The class is pretty robust and fast - I have made good experience using it for exactly the same purpose.

reading a web api blob into a string that I can send as part of a json object to the server and turn back into a file

i'm trying to turn a wav file into a string I can send to the server as a part of a json object, so that on the server I can turn that string back into a file.
i have tried to use readAsBinaryString and read as text, can't get past error in reading the string into a byte array.
reader.onloadend = saveMedia;
reader.readAsText(Blob);
//reader.readAsBinaryString(Blob); also tried.
then the callback sends an ajax request with an object holding the string in "reader.result" and on the server i tried things like:
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] BinaryData = encoding.GetBytes(stringFromRequest);
the answers to this question below seem to be that this should not be done. but i really want to do it this way because of another tool I am using (breeze js). don't want to use a separate post action with a file data type.
releted:
File API - Blob to JSON
Found a way that works:
var reader = new FileReader();
reader.onloadend = afterRead;
reader.readAsBinaryString(blob);
function afterRead() {
// convert binary string to base64 for a safe transfer to the server.
entity.BinaryProp = window.btoa(reader.result);
}
on the server-side:
string BinaryString = (string)entityInfo.UnmappedValuesMap["BinaryProp"];
byte[] BinaryData = Convert.FromBase64String(BinaryString);
You can use fileReader.readAsDataURL(fileObject), this encode blob to base64, which can safely upload to server by API.
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
let thumbnail = reader.result;
console.log(thumbnail)
//send to API
};
The answer above is great, but there is a simpler way.
var reader = new FileReader();
reader.onloadend = afterRead;
reader.readAsDataURL(blob); // Use this function instead
function afterRead() {
entity.BinaryProp = reader.result; //result is already a base64 string!
}
See documentation here: FileReader.readAsDataURL()

Categories