Reputation: 511
I'm looking for a way to serialize an object with a stream to JSON to POST to an API. I continue to receive this error:
Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'System.IO.FileStream'.'
I understand what the error is saying but I don't understand what I need to implement to resolve it. Does it need to be converted to something else before JSON?
Here is my code:
Model:
[Serializable]
public class Document
{
public string Number { get; set; }
public string Revision { get; set; }
public string FileName { get; set; }
public Stream File { get; set; }
}
Building request:
public Document BuildRequest(string pdfFile, string txtFile)
{
Document document = new Document();
try
{
string data = File.ReadAllText(txtFile);
string[] array = data.Split('|');
FileStream fs = new FileStream(pdfFile, FileMode.Open);
document.Number = array[0];
document.Revision = array[1];
document.FileName = file;
document.File = fs;
}
// rest of code...
}
Post:
public void Post(Document document)
{
var json = JsonConvert.SerializeObject(document);
// rest of code in method...
}
Upvotes: 3
Views: 13918
Reputation: 2681
After posting this I saw that this was answered already by Lasse in the comments, therefore this answer will serve as an alternative to achieving this
Here is an example which implements a custom JsonConverter
that converts the File
property to and from a Base64 string so it can be transferred over the network.
Some important points:
Starting off, I created a StreamStringConverter
/// <summary>
/// Handles the (de)serialization of <see cref="Stream"/>.
/// </summary>
/// <remarks>
/// The <see cref="Stream"/> will be written as a Base64 encoded string, on the inverse it will be converted from a Base64 string to a <see cref="MemoryStream"/>.
/// </remarks>
public class StreamStringConverter : JsonConverter
{
private static Type AllowedType = typeof(Stream);
public override bool CanConvert(Type objectType)
=> objectType == AllowedType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var objectContents = (string)reader.Value;
var base64Decoded = Convert.FromBase64String(objectContents);
var memoryStream = new MemoryStream(base64Decoded);
return memoryStream;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var valueStream = (FileStream)value;
var fileBytes = new byte[valueStream.Length];
valueStream.Read(fileBytes, 0, (int)valueStream.Length);
var bytesAsString = Convert.ToBase64String(fileBytes);
writer.WriteValue(bytesAsString);
}
}
You can decorate the appropriate members in your Document
class to use this custom StreamStringConverter
public class Document
{
public string Number { get; set; }
public string Revision { get; set; }
public string FileName { get; set; }
// Specify a custom JsonConverter for our StreamJsonConverter
[JsonConverter(typeof(StreamStringConverter))]
public Stream File { get; set; }
}
Your model is now ready to begin serializing and deserializing, I have updated some of the code to use string
in place of an actual file handle for txtFile
, for simplicity.
static void Main(string[] args)
{
Document document = new Document();
const string file = "file";
const string txtFileContents = "1|1.0";
const string pdfFile = "myPdfFile.pdf";
try
{
string[] array = txtFileContents.Split('|');
FileStream fs = new FileStream(pdfFile, FileMode.Open);
document.Number = array[0];
document.Revision = array[1];
document.FileName = file;
document.File = fs;
}
catch (Exception exception)
{
}
// Serialize the Document object
// File, in the JSON contents, will be a Base64 encoded string
var serializedContents = JsonConvert.SerializeObject(document);
// Deserialize the contents
// File will be a Stream
var deserializedContents = JsonConvert.DeserializeObject<Document>(serializedContents);
// For demo purposes, this will write the Document.File object back to a new PDF file for comparison
using (var fileStream = File.Create("myDeserializedPdfFile.pdf"))
{
var fileAsMemoryStream = (MemoryStream)deserializedContents.File;
fileAsMemoryStream.WriteTo(fileStream);
}
}
Again I reiterate that I have not written this code to be production ready, that's up to you, this is simply to guide you in the right direction.
Upvotes: 4
Reputation: 11
Like the good fellows Lasse and Colin said in the comments: You can't write a filestream into Json. If you want to send the file into json you'll need to change it to some type of string or byte array.
Upvotes: 0