Base64 to StreamContent to upload image without pulling from file system - c#

I'd like to be able to change this code so that I don't have to pull from a file on a file system, but rather use a base64 value that is saved in a database. Does anyone here know enough about StreamContent to know what I need to do to accomplish this?
The file is a jpeg file.
private static StreamContent FileMultiPartBody(string fullFilePath)
{
var fileInfo = new FileInfo(fullFilePath);
var fileContent = new StreamContent(fileInfo.OpenRead());
// Manually wrap the string values in escaped quotes.
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = string.Format("\"{0}\"", fileInfo.Name),
Name = "\"signature\"",
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return fileContent;
}

StreamContent is just a wrapper of another stream (the stream returned from fileInfo.OpenRead() in your example). All you need to do is replace that stream with a stream from your database and return that. You can also replace the fileInfo.Name with a Path.GetFileName(fullFilePath) call.
private Stream GetStreamFromDatabase(string fullFilePath)
{
//TODO
}
private static StreamContent FileMultiPartBody(string fullFilePath)
{
var fileContent = new StreamContent(GetStreamFromDatabase(fullFilePath))
// Manually wrap the string values in escaped quotes.
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = string.Format("\"{0}\"", Path.GetFileName(fullFilePath)),
Name = "\"signature\"",
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return fileContent;
}
If you need help converting a base64 value from a database to a stream I would suggest asking a separate question about that.

Related

c# Sending a file with HttpResponseMessage StreamContent, but no file is sent?

I am trying to send a file on my pc to my client. I have looked around and most answers resembles this: How to return a file (FileContentResult) in ASP.NET WebAPI
So I have tried implementing it myself, but I only manage to receive the headers. I must assume I am doing something wrong somewhere, but I can't tell where. I have a little trouble telling the c# versions apart, but the target it should work on is .Net 4.8.
My code for sending the file:
[HttpGet("ftplog")]
public HttpResponseMessage Get()
{
String fileName = "FileZilla Server.log";
String path = #"C:\Users\jacqq\source\repos\testing\testing\Views\Home\FileZilla Server.log";
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
var memoeryStream = new MemoryStream();
fileStream.CopyTo(memoeryStream);
memoeryStream.Seek(0, SeekOrigin.Begin);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(memoeryStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName.ToString()
};
return result;
}
I have tried sending the FileStream instead of a MemoryStream and I have tried sending the file as ByteArrayContent, but I always only receive headers. I have checked, and the file is read correctly with data. It might be that my recieving code is wrong?
public static async Task DownloadFileTaskAsync(HttpClient client, Uri uri, string FileName)
{
var s = await client.GetStreamAsync(uri);
StreamReader reader = new StreamReader(s) ;
Console.WriteLine("Starting");
Console.WriteLine(reader.ReadToEnd());
Console.WriteLine("stopping");
}
I am new to c#, so it might be I have overlooked something. If anyone know of a different/better way to send a file, I would be keen to hear that too.
Here is what I recieve:
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},"content":{"headers":[{"key":"Content-Type","value":["application/octet-stream"]},{"key":"Content-Disposition","value":["attachment; filename=\"FileZilla Server.log\""]}]},"statusCode":100,"reasonPhrase":"Continue","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":false}
Please help, have been stuck for little too long.
[HttpGet("ftplog")]
public FileStreamResult Get()
{
string fileName = "FileZilla Server.log";
string path = #"C:\Users\jacqq\source\repos\testing\testing\Views\Home\FileZilla Server.log";
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
var memoryStream = new MemoryStream();
fileStream.SaveAs(memoryStream);
memoryStream.Position = 0;
return new FileStreamResult(memoryStream, "application/octet-stream")
{
FileDownloadName = $"{fileName}.log"
};
}

How to Read Contents of an Audio File to a string

I'm working on an app that needs to write the contents of a music file to StreamWriter which is used to create a copy of the file. My first attempt resulted in a file that couldn't be played. Comparing the two file's contents in Notepad++ showed a lot of differences between the two files, namely the copied file having a lot of box characters.
I thought this might be a problem with encoding, so I wrote a quick test that loops through all the System.Text.Encoding default values, for both reading and writing, to see what that would do. For my test mp3 file, it resulted in three versions that are playable, but distorted, while the others wouldn't play at all. I also tested this with a wav file. There were three playable files again, but different encoding combinations.
Here's my code for generating the different encoded files:
private string FolderPath => #"D:\Encoding Test";
private string FileName => "Test Song.mp3";
private string FilePath => Path.Combine(FolderPath, FileName);
public void Encode()
{
var encodings = new[] { Encoding.ASCII, Encoding.Unicode, Encoding.UTF8, Encoding.UTF7, Encoding.UTF32, Encoding.BigEndianUnicode };
foreach (var readerEncoding in encodings)
{
foreach (var writerEncoding in encodings)
{
ChangeEncoding(readerEncoding, writerEncoding);
}
}
}
private void ChangeEncoding(Encoding readerEncoding, Encoding writerEncoding)
{
var contents = ReadFile(readerEncoding);
WriteToNewFile(readerEncoding, writerEncoding, contents);
}
private string ReadFile(Encoding encoding)
{
using var fileStream = new FileStream(FilePath, FileMode.Open);
using var reader = new StreamReader(fileStream, encoding);
var contents = reader.ReadToEnd();
return contents;
}
private void WriteToNewFile(Encoding readerEncoding, Encoding writerEncoding, string contents)
{
var newName = GetNewFileName(readerEncoding, writerEncoding);
var newFilePath = Path.Combine(FolderPath, newName);
using var fileStream = new FileStream(newFilePath, FileMode.Create);
using var writer = new StreamWriter(fileStream, writerEncoding);
writer.Write(contents);
}
private string GetNewFileName(Encoding readerEncoding, Encoding writerEncoding)
{
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(FileName);
var extension = Path.GetExtension(FileName);
var newName = $"{fileNameWithoutExtension}-{readerEncoding.EncodingName} to {writerEncoding.EncodingName}{extension}";
return newName;
}
How can I read the contents of an mp3 or wav file into a StreamWriter and get it to save to a file correctly?

Changing from MemoryStream to Stream in C#

Below is the code where I am passing memory stream and reading it and doing the necessary operation afterwards. Now the requirement has changed and instead of Memory stream, I will be passing Stream and that starts giving me error. I would like to know how can I handle the below method if contents returned here is of Stream type. Now it works fine when my contents is of type MemoryStream.
public async Task<string> ReadStream(string containerName, string digestFileName, string fileName, string connectionString)
{
string data = string.Empty;
string fileExtension = Path.GetExtension(fileName);
var contents = await DownloadBlob(containerName, digestFileName, connectionString);
if (fileExtension == ".gz")
{
using (var unzipper = new GZipStream(contents, CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(unzipper, Encoding.UTF8))
{
data = reader.ReadToEnd();
}
}
}
else
{
data = Encoding.UTF8.GetString(contents.ToArray());
}
return data;
}
I'm going to assume the issue is contents.ToArray(), since Stream desn't have a ToArray() method.
In this case, you'll be better off using a StreamReader:
using (var reader = new StreamReader(contents))
{
data = reader.ReadToEnd();
}
StreamReader uses Encoding.UTF8 by default, but you can specify it explicitly if you want: new StreamReader(contents, Encoding.UTF8).
You'll note that you're already doing this a few lines above, to read from the unzipper stream.

Angular/Web API 2 returns invalid or corrupt file with StreamContent or ByteArrayContent

I'm trying to return a file in a ASP.NET Web API Controller. This file is a dynamically-generated PDF saved in a MemoryStream.
The client (browser) receives the file successfully, but when I open the file, I see that all the pages are totally blank.
The thing is that if I take the same MemoryStream and write it to a file, this disk file is displayed correctly, so I assume that the problem is related to the file transfer via Web.
My controller looks like this:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(memStream.ToArray()); //OR: new StreamContent(memStream);
return result;
}
Just to try, if I write the stream to disk, it's displayed correctly:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
using (var fs = new FileStream("C:\\Temp\\test.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
memStream.CopyTo(fs);
}
return null;
}
The differences are:
PDF saved on disk: 34KB
PDF transferred via web: 60KB (!)
If I compare both files contents, the main differences are:
File Differences
On the left is the PDF transferred via web; on the right, the PDF saved to disk.
Is there something wrong with my code?
Maybe something related to encodings?
Thanks!
Well, it turned out to be a client (browser) problem, not a server problem. I'm using AngularJS in the frontend, so when the respose was received, Angular automatically converted it to a Javascript string. In that conversion, the binary contents of the file were somehow altered...
Basically it was solved by telling Angular not to convert the response to a string:
$http.get(url, { responseType: 'arraybuffer' })
.then(function(response) {
var dataBlob = new Blob([response.data], { type: 'application/pdf'});
FileSaver.saveAs(dataBlob, 'myFile.pdf');
});
And then saving the response as a file, helped by the Angular File Saver service.
I guess you should set ContentDisposition and ContentType like this:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memStream.ToArray())
};
//this line
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "YourName.pdf"
};
//and this line
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
Try this
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
//get buffer
var buffer = memStream.GetBuffer();
//content length for header
var contentLength = buffer.Length;
var statuscode = HttpStatusCode.OK;
var response = Request.CreateResponse(statuscode);
response.Content = new StreamContent(new MemoryStream(buffer));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = contentLength;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=my_filename.pdf", out contentDisposition)) {
response.Content.Headers.ContentDisposition = contentDisposition;
}
return response;
}

How to convert base64 value from a database to a stream with C#

I have some base64 stored in a database (that are actually images) that needs to be uploaded to a third party. I would like to upload them using memory rather than saving them as an image then posting it to a server. Does anyone here know how to convert base64 to a stream?
How can I change this code:
var fileInfo = new FileInfo(fullFilePath);
var fileContent = new StreamContent(fileInfo.OpenRead());
to fill the StreamContent object with a base64 interpretation of an image file instead.
private static StreamContent FileMultiPartBody(string fullFilePath)
{
var fileInfo = new FileInfo(fullFilePath);
var fileContent = new StreamContent(fileInfo.OpenRead());
// Manually wrap the string values in escaped quotes.
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = string.Format("\"{0}\"", fileInfo.Name),
Name = "\"name\"",
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return fileContent;
}
You'll want to do something like this, once you've gotten the string from the database:
var bytes = Convert.FromBase64String(base64encodedstring);
var contents = new StreamContent(new MemoryStream(bytes));
// Whatever else needs to be done here.
Just as an alternative approach, which works well with large streams (saves the intermediate byte array):
// using System.Security.Cryptography
// and assumes the input stream is b64Stream
var stream = new CryptoStream(b64Stream, new FromBase64Transform(), CryptoStreamMode.Read);
return new StreamContent(stream);
var stream = new MemoryStream(Convert.FromBase64String(base64));

Categories