我正在寻找一种方法来将对象序列化为 JSON 以 POST 到 API。我继续收到此错误:
Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'System.IO.FileStream'.'
我明白错误的意思,但我不明白我需要实现什么来解决它。在JSON之前是否需要转换成其他东西?
这是我的代码:
型号:
[Serializable]
public class Document
{
public string Number { get; set; }
public string Revision { get; set; }
public string FileName { get; set; }
public Stream File { get; set; }
}
构建请求:
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...
}
帖子:
public void Post(Document document)
{
var json = JsonConvert.SerializeObject(document);
// rest of code in method...
}
最佳答案
发布后我看到 Lasse 已经在评论中回答了这个问题,因此这个答案将作为实现这个的替代方法
这是一个实现自定义 JsonConverter
的示例,它将 File
属性与 Base64 字符串相互转换,以便它可以通过网络传输。
一些要点:
- 您需要在拥有大型 PDF 文件的情况下测试此代码
- 如果发现任何边缘情况,您必须重构此代码以处理某些边缘情况
- 我写这篇文章纯粹是为了回答你“能不能做到”的问题,我没有考虑任何异常、边缘情况甚至网络延迟,具体取决于 Base64 字符串的大小——你会遇到问题和限制,具体取决于关于 HTTP 请求的内容大小。
- API 需要知道如何处理此请求,从而将 Base 64 文本作为流读取。
开始,我创建了一个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);
}
}
您可以在 Document
类中修饰适当的成员以使用此自定义 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; }
}
您的模型现在已准备好开始序列化和反序列化,为了简单起见,我更新了一些代码以使用 string
代替 txtFile
的实际文件句柄.
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);
}
}
我再次重申,我编写这段代码并不是为了生产就绪,这取决于您,这只是为了引导您朝着正确的方向前进。
关于c# - 如何在C#中使用流序列化对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57187206/