Saving a base 64 encoded image in MongoDB GridFS - vb.net

I have a web service that takes the content of a canvas tag and saves it into a MongoDB GridFS store.
The code below works, however it requires saving the image to disk before sending it to MongoDB.
Using postBody As Stream = Request.InputStream
' Get the body of the HTTP POST (the data:image/png)
postBody.Seek(0, SeekOrigin.Begin)
Dim imageData As String = New StreamReader(postBody).ReadToEnd
Dim base64Data = Regex.Match(imageData, "data:image/(?<type>.+?),(?<data>.+)").Groups("data").Value
Dim data As Byte() = Convert.FromBase64String(base64Data)
Using stream = New MemoryStream(data, 0, data.Length)
Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(stream)
Dim directory = Server.MapPath("~/App_Data/temp/")
Dim file = String.Concat(directory, id, ".png")
img.Save(file, System.Drawing.Imaging.ImageFormat.Png)
Using fs = New FileStream(file, FileMode.Open)
db.GridFS.Upload(fs, id & ".png")
End Using
End Using
End Using
Is there a better way, perhaps without the need to persist it to disk before uploading to MongoDB?

As suggested in the comments, just use the Stream as an argument to Upload instead of writing out to file.
And also note that you do not have to convert to base64 in order to send the file via GridFS (or a plain mongo field for that matter). The input can be binary, unless of course you always want your data base64 encoded for your convenience.

Related

How to recombine document pages stored as separate Base64 strings in FileNet using VB.Net?

I have a document that is stored on FileNet. Each page of the document is stored as a separate base 64 encoded string. I need to get all of these pages into a single document again.
What I have attempted to do is to decode the Base64 string into an array. for each page of the document, I decode the Base64 string into a byte array using concatenation. I then use the File.WriteAllBytes method to create a single file. This file is a valid TIFF file and I am able to open it however only the last page appears. I have checked to make sure that the application I am using to open the document is capable of showing more than one page. I am using the Windows Photos application which will show all pages of a TIFF document.
How can I merge the pages of this document so that each page will appear correctly?
For example, the code below reads the Base64 string for each file and then combines them into a single output file. When I open bytefileout3.tiff however, I can only see the last page that was added into the document.
Dim inputPath As String = "C:\temp\file1.txt"
Dim fileStr As String = File.ReadAllText(inputPath)
Dim bytes As Byte() = Convert.FromBase64String(fileStr)
Dim inputPath2 As String = "C:\temp\file2.txt"
Dim fileStr2 As String = File.ReadAllText(inputPath2)
Dim bytes2 As Byte() = Convert.FromBase64String(fileStr2)
Dim bytes3 As Byte() = New Byte() {}
File.WriteAllBytes("c:\temp\bytefileout.tiff", bytes)
File.WriteAllBytes("c:\temp\bytefileout2.tiff", bytes2)
bytes3 = bytes2.Concat(bytes).ToArray()
File.WriteAllBytes("c:\temp\bytefileout3.tiff", bytes3)

How do you delete a file generated via webapi after returning the file as response?

I'm creating a file on the fly on a WebAPI call, and sending that file back to the client.
I think I'm misunderstanding flush/close on a FileStream:
Dim path As String = tempFolder & "\" & fileName
Dim result As New HttpResponseMessage(HttpStatusCode.OK)
Dim stream As New FileStream(path, FileMode.Open)
With result
.Content = New StreamContent(stream)
.Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment")
.Content.Headers.ContentDisposition.FileName = fileName
.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("application/octet-stream")
.Content.Headers.ContentLength = stream.Length
End With
'stream.Flush()
'stream.Close()
'Directory.Delete(tempFolder, True)
Return result
You can see where I've commented things out above.
Questions:
Does the stream flush/close itself?
How can I delete the tempFolder after returning the result?
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
Update:
I went ahead with accepted answer, and found it to be quite simple:
Dim ReturnStream As MemoryStream = New MemoryStream()
Dim WriteStream As StreamWriter = New StreamWriter(ReturnStream)
With WriteStream
.WriteLine("...")
End With
WriteStream.Flush()
WriteStream.Close()
Dim byteArray As Byte() = ReturnStream.ToArray()
ReturnStream.Flush()
ReturnStream.Close()
Then I was able to stream the content as bytearraycontent:
With result
.Content = New ByteArrayContent(byteArray)
...
End With
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
To do the same thing without writing a file to disk, you might look into the MemoryStream class. As you'd guess, it streams data from memory like the FileStream does from a file. The two main steps would be:
Take your object in memory and instead of writing it to a file, you'd serialize it into a MemoryStream using a BinaryFormatter or other method (see that topic on another StackOverflow Q here: How to convert an object to a byte array in C#).
Pass the MemoryStream to the StreamContent method, exactly the same way you're passing the FileStream now.

VB.Net Reading Resource Binary File

I have a resource in named StoreCode, I can't seem to read the file using:
Dim readBinaryFile As BinaryReader
readBinaryFile = New BinaryReader(My.Resources.StoreCode)
There is an error:
Value of type:'1-dimensional array of Byte' cannot be converted to 'System.IO.Stream'
How do I correctly read the Binary File?
Seems My.Resources.StoreCode is a byte[] for that reason you need to copy it to a MemoryStream object and then use a BinaryReader to read the stream's content.
Using ms As New MemoryStream(My.Resources.StoreCode)
Using readBinaryFile As New BinaryReader(ms)
'read operations
End Using
End Using
I hope it helps.
My.Resources.StoreCode is probably a an array of bytes. Instead, it needs to be a file stream, similar to this:
Dim readBinaryFile As BinaryReader
Dim fs As System.IO.Stream = File.Open(pathstring, FileMode.Open)
readBinaryFile = New BinaryReader(fs)

Track webpage downloading progress

I'm using this piece of code for VB.NET to download the text from a website:
Dim Str As System.IO.Stream
Dim srRead As System.IO.StreamReader
Dim req As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.example.com/file.txt")
Dim resp As System.Net.WebResponse = req.GetResponse
Str = resp.GetResponseStream
srRead = New System.IO.StreamReader(Str)
It is just a text file, and is rather small, so it downloads really quickly. But I do believe that in the future the file will become considerably large. Is there a way to track the downloading progress from the above method?
You can find the total length of your find in the ContentLength property of your WebResponse object. Once you have that, it's pretty easy to report progress based on the data you read from the GetResponseStream.

Problem When Compressing File using vb.net

I have File Like "Sample.bak" and when I compress it to be "Sample.zip" I lose the file extension inside the zip file I meann when I open the compressed file I find "Sample" without any extension.
I use this code :
Dim name As String = Path.GetFileName(filePath).Replace(".Bak", "")
Dim source() As Byte = System.IO.File.ReadAllBytes(filePath)
Dim compressed() As Byte = ConvertToByteArray(source)
System.IO.File.WriteAllBytes(destination & name & ".Bak" & ".zip", compressed)
Or using this code :
Public Sub cmdCompressFile(ByVal FileName As String)
'Stream object that reads file contents
Dim streamObj As Stream = New StreamReader(FileName).BaseStream
'Allocate space in buffer according to the length of the file read
Dim buffer(streamObj.Length) As Byte
'Fill buffer
streamObj.Read(buffer, 0, buffer.Length)
streamObj.Close()
'File Stream object used to change the extension of a file
Dim compFile As System.IO.FileStream = File.Create(Path.ChangeExtension(FileName, "zip"))
'GZip object that compress the file
Dim zipStreamObj As New GZipStream(compFile, CompressionMode.Compress)
'Write to the Stream object from the buffer
zipStreamObj.Write(buffer, 0, buffer.Length)
zipStreamObj.Close()
End Sub
please I need to compress the file without loosing file extension inside compressed file.
thanks,
GZipStream compresses a stream of bytes, it does no more than that. It does not embed file info in the stream, so you need to embed it somewhere.
The easiest way to restore the file name is to name it with the original name e.g. Sample.bak.zip.
If that doesn't work for you can use SharpZipLib (samples here) which does the embedding of the file info for you.
If you don't want to go that either of thoes you can either create your own file format and embed the file info or you can try and implement the standard gzip format