I am writing test cases for an API.
In the API, I am getting the memory stream in the body of HttpRequest. In the below snippet, req is an instance of HttpRequest
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
So, while mocking I have this code:
Data data = new Data()
{
width = 400,
height = 600,
text = "text",
barcodeformat = ZXing.BarcodeFormat.CODE_128.ToString()
};
byte[] inputData = null;
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, data);
inputData = ms.ToArray();
}
var mockHttp = new Mock<HttpRequest>();
mockHttp.Setup(x => x.Body).Returns(new MemoryStream(inputData));
But in the API code, I am getting the value in data as empty string.
Please help me to understand where I am going wrong.
JsonConvert expects json, but you don't have json here.
Related
I'm having some issues in converting an image from an Base63 string to image memoryStream on a WebApi. The result looks like this:
I have tried several ways ala this:
var imageBytes = Convert.FromBase64String(pagedResult.Data);
var ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
var image = await Image.LoadAsync(ms, cancellationToken);
var stream = new MemoryStream();
await image.SaveAsync(stream, new JpegEncoder(), cancellationToken);
stream.Position = 0;
ms.Position = 0;
return (stream, pagedResult.Mimetype);
Or something as simple like this:
var sapDoc = Convert.FromBase64String(pagedResult.Data);
return (new MemoryStream(sapDoc), pagedResult.Mimetype);
The controller looks like this:
[HttpGet("document")]
public async Task<ActionResult<Stream>> GetImage([FromQuery] long documentNumber, string documentId)
{
var query = new GetDocument.Query
{
DocumentId = documentId,
DocumentNumber = documentNumber
};
var (image, imageFormat) = await _mediator.Send(query);
return File(image, imageFormat);
Any idea what's going on?
I have verified the base64 string. If i take the output and use forexample this: https://codebeautify.org/base64-to-image-converter i can see the image.
I found the issue. I was the mimType that from SAP was set to JPG instead of JPEG. An simple mimType.Replace("jpg", "jpeg") fixed the issue :)
Here is a way to do it:
var data = Encoding.UTF8.GetBytes(pagedResult.Data);
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
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;
}
I am looking for a way to serialize Avro to a byte array in Avro C# library. There is a link to do for Avro Java library as described in following link from Avro documentation:
https://cwiki.apache.org/confluence/display/AVRO/FAQ#FAQ-Serializingtoabytearray
Code copied from above link:
ByteArrayOutputStream out = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
DatumWriter<User> writer = new SpecificDatumWriter<User>(User.getClassSchema());
writer.write(user, encoder);
encoder.flush();
out.close();
byte[] serializedBytes = out.toByteArray();
But I have not found a way to do in Avro c# library. I am basically looking for c# equivalent of above code.
You can use these methods to convert to and from an object to a byte array or vice-versa. Code extracted from https://stackoverflow.com/a/18205093/6138713
// Convert an object to a byte array
private byte[] ObjectToByteArray(Object obj)
{
if(obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
// Convert a byte array to an Object
private Object ByteArrayToObject(byte[] arrBytes)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object) binForm.Deserialize(memStream);
return obj;
}
Maybe something as follows, I used the following code to write to a Kineses Stream
public async Task RecordAsync(ISpecificRecord record, string partitionKey)
{
using (var ms = new MemoryStream())
{
var encoder = new BinaryEncoder(ms);
var writer = new SpecificDefaultWriter(record.Schema);
writer.Write(record, encoder);
// AWS Kineses
var putRecordRequest = new PutRecordRequest
{
StreamName = _streamName,
Data = ms,
PartitionKey = partitionKey
};
await _kinesis.PutRecordAsync(putRecordRequest);
}
}
or
public byte[] Serialize(ISpecificRecord record)
{
using (var ms = new MemoryStream())
{
var encoder = new BinaryEncoder(ms);
var writer = new SpecificDefaultWriter(record.Schema);
writer.Write(record, encoder);
return ms.ToArray();
}
}
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));
I'm generating ics files ( iCalendar or RFC 2445 or however you call them) using a library that serializes the ical contents into a MemoryStream, or actually any type of stream.
Here's my chunk of code:
public ActionResult iCal(int id) {
MyApp.Event kiEvt = evR.Get(id);
// Create a new iCalendar
iCalendar iCal = new iCalendar();
// Create the event, and add it to the iCalendar
DDay.iCal.Components.Event evt = iCal.Create<DDay.iCal.Components.Event>();
// Set information about the event
evt.Start = kiEvt.event_date;
evt.End = evt.Start.AddHours(kiEvt.event_duration); // This also sets the duration
evt.Description = kiEvt.description;
evt.Location = kiEvt.place;
evt.Summary = kiEvt.title;
// Serialize (save) the iCalendar
iCalendarSerializer serializer = new iCalendarSerializer(iCal);
System.IO.MemoryStream fs = new System.IO.MemoryStream();
serializer.Serialize(fs, System.Text.Encoding.UTF8);
return File(fs, "text/calendar", "MyApp.wyd."+kiEvt.id+".ics");
}
My problem is that fs contains some content, but the controller returns empty file - with proper mimetype and filename. I'm most probably missing something with the stream handling but can't figure out what.
Can anybody help me out here? Thanks in advance.
Just a guess: Do you need to Seek back to the start of the stream before you return it?
fs.Seek(0, 0);
iCalendar iCal = new iCalendar();
foreach (CalendarItem item in _db.CalendarItems.Where(r => r.Start > DateTime.Now && r.Active == true && r.CalendarID == ID).ToList())
{
Event evt = new Event();
evt.Start = new iCalDateTime(item.Start);
evt.End = new iCalDateTime(item.End);
evt.Summary = "Some title";
evt.IsAllDay = false;
evt.Duration = (item.End - item.Start).Duration();
iCal.Events.Add(evt);
}
// Create a serialization context and serializer factory.
// These will be used to build the serializer for our object.
ISerializationContext ctx = new SerializationContext();
ISerializerFactory factory = new DDay.iCal.Serialization.iCalendar.SerializerFactory();
// Get a serializer for our object
IStringSerializer serializer = factory.Build(iCal.GetType(), ctx) as IStringSerializer;
if (serializer == null) return Content("");
string output = serializer.SerializeToString(iCal);
var contentType = "text/calendar";
var bytes = Encoding.UTF8.GetBytes(output);
var result = new FileContentResult(bytes, contentType);
result.FileDownloadName = "FileName.ics";
return result;