c# - 如何在C#中使用流序列化对象

标签 c# json

我正在寻找一种方法来将对象序列化为 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 字符串相互转换,以便它可以通过网络传输。

一些要点:

  1. 您需要在拥有大型 PDF 文件的情况下测试此代码
  2. 如果发现任何边缘情况,您必须重构此代码以处理某些边缘情况
  3. 我写这篇文章纯粹是为了回答你“能不能做到”的问题,我没有考虑任何异常、边缘情况甚至网络延迟,具体取决于 Base64 字符串的大小——你会遇到问题和限制,具体取决于关于 HTTP 请求的内容大小。
  4. 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/

相关文章:

C# 线程停放 CPU 的?

C# 自定义事件处理程序

c# - 使用可为 null 的 DateTime

android - 将数据放入 Android 4.4 错误位置中的 JSON 对象

python - 如何使用 json google translate api?

iOS编程,获取JSON数据

c# - LibGit2Sharp异常: repository path not owned by current user

C# NHibernate 子字符串方法未找到

json - 用于对视频进行评分的 youtube 数据 API

Android + JSON 防止反编译?