Error converting value from string to stream

I want to serialize a custom object:

public class MyCustomObject
{
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public List<HttpPostedFileBase> Files { get; set; }

    public MyCustomObject()
    {
        Files = new List<HttpPostedFileBase>();
    }
}

In json. For this, I use a custom converter:

public class HttpPostedFileConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stream = (Stream)value;
        using (var sr = new BinaryReader(stream))
        {
            var buffer = sr.ReadBytes((int)stream.Length);
            writer.WriteValue(Convert.ToBase64String(buffer));
        }
    }

I use JsonSerializerSettings for serialization so that json.net knows which type implements (for HttpPostedFileBase).

        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new HttpPostedFileConverter());
        settings.TypeNameHandling = TypeNameHandling.Objects;

The object serializes correctly, but I have this error for serialization:

JsonSerializationException Error converting value "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDA

and this is the value of my serialized object:

{
  "$type": "ConsoleApplication1.MyCustomObject, ConsoleApplication1",
  "Name": "Test2",
  "Date": "2016-11-03T12:35:14.6020154+01:00",
  "Files": [
    {
      "$type": "System.Web.HttpPostedFileWrapper, System.Web",
      "ContentLength": 1024,
      "FileName": "Pannigale.jpg",
      "ContentType": "image/jpg",
      "InputStream": "/9j/4AAQ...KKAP//Z"
    }
  ]
}

What is wrong with deserialization?

EDIT I tested the class for testing ... and now it works:

public class TestHttpFile : HttpPostedFileBase
{
    string fullFileName = @"C:\Pictures\SBK-1299-Panigale-S_2015_Studio_R_B01_1920x1080.mediagallery_output_image_[1920x1080].jpg";
    public override int ContentLength
    {
        get
        {
            return 1024;
        }
    }

    public override string FileName
    {
        get
        {
            return "Pannigale.jpg";
        }
    }

    public override string ContentType
    {
        get
        {
            return "image/jpg";
        }
    }

    public override Stream InputStream
    {
        get
        {
            return File.OpenRead(fullFileName);
        }
    }
}

In serialization, I noticed this difference:

 "$type": "ConsoleApplication1.TestHttpFile, ConsoleApplication1",

instead

 "$type": "System.Web.HttpPostedFileWrapper, System.Web",

But finally, I donโ€™t want to create a wrapper or anything else ... and I donโ€™t understand why it works with this type, and not with HttpPostedFileWrapper.

+4
3

: , , HttpPostedFileWrapper HttpPostedFile, .

, HttpPostedFileConverter :

public class StreamConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Stream).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var bytes = serializer.Deserialize<byte[]>(reader);
        return new MemoryStream(bytes);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stream = (Stream)value;
        var bytes = stream.ReadAllBytesAndReposition();
        serializer.Serialize(writer, bytes);
    }
}

public static class StreamExtensions
{
    public static byte[] ReadAllBytesAndReposition(this Stream stream)
    {
        const int bufferSize = 4096;
        using (var ms = new MemoryStream())
        {
            byte[] buffer = new byte[bufferSize];
            int count;
            var position = stream.CanSeek ? stream.Position : (long?)null;
            while ((count = stream.Read(buffer, 0, buffer.Length)) != 0)
                ms.Write(buffer, 0, count);
            if (position != null)
            {
                // Restore position
                stream.Position = position.Value;
            }
            return ms.ToArray();
        }
    }
}

JSON, , MyCustomObject, , TypeNameHandling = TypeNameHandling.Auto . , System.Web.HttpPostedFileWrapper , HttpPostedFile. :

public class HttpPostedFileWrapper : HttpPostedFileBase {

    private HttpPostedFile _file;

    public HttpPostedFileWrapper(HttpPostedFile httpPostedFile) {
        if (httpPostedFile == null) {
            throw new ArgumentNullException("httpPostedFile");
        }
        _file = httpPostedFile;
    }

, Json.NET , JSON HttpPostedFile, null , ArgumentNullException.

: HttpPostedFile. , , Microsoft , HttpPostedFile. , custom JsonConverter HttpPostedFileWrapper, HttpPostedFile . Json.NET, , .

, ?

1. HttpPostedFilesBase

HttpPostedFilesBase, , HttpPostedFilesBase JsonConverter. MemoryHttpPostedFile :

public sealed class MemoryHttpPostedFile : HttpPostedFileBase
{
    readonly string contentType;
    readonly string fileName;
    readonly MemoryStream inputStream;

    public MemoryHttpPostedFile(string contentType, string fileName, [JsonConverter(typeof(StreamConverter))] MemoryStream inputStream)
    {
        if (inputStream == null)
            throw new ArgumentNullException("inputStream");
        this.contentType = contentType;
        this.fileName = fileName;
        this.inputStream = inputStream;
    }

    public override int ContentLength { get { return (int)inputStream.Length; } }

    public override string ContentType { get { return contentType; } }

    public override string FileName { get { return fileName; } }

    [JsonConverter(typeof(StreamConverter))]
    public override Stream InputStream { get { return inputStream; } }

    //TODO: implement SaveAs()
    public override void SaveAs(string filename)
    {
        // Implement based on HttpPostedFile.SaveAs()
        // https://referencesource.microsoft.com/#System.Web/HttpPostedFile.cs,678e7f8bc95c149f
        throw new NotImplementedException();
    }
}

public class HttpPostedFileBaseConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(HttpPostedFileBase).IsAssignableFrom(objectType)
            && !typeof(MemoryHttpPostedFile).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var postedFile = (HttpPostedFileBase)value;

        // Save position
        var wrapper = new MemoryHttpPostedFile(postedFile.ContentType, postedFile.FileName, new MemoryStream(postedFile.InputStream.ReadAllBytesAndReposition()));

        serializer.Serialize(writer, wrapper);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var wrapper = serializer.Deserialize<MemoryHttpPostedFile>(reader);
        return wrapper;
    }
}

HttpPostedFilesBase MemoryHttpPostedFile, TypeNameHandling.Auto. . StreamConverter StreamExtensions .

:

var settings = new JsonSerializerSettings
{
    Converters = new JsonConverter[] { new HttpPostedFileBaseConverter() },
    Formatting = Formatting.Indented,
};

2. HttpPostedFileWrapper

"" HttpPostedFile paracycle, :

public class HttpPostedFileBaseConverter : JsonConverter
{
    class HttpPostedFileSurrogate
    {
        public string ContentType { get; set; }

        public string FileName { get; set; }

        public byte[] InputStream { get; set; }
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(HttpPostedFileBase).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var wrapper = (HttpPostedFileWrapper)value;

        // Save position
        var surrogate = new HttpPostedFileSurrogate
        {
            ContentType = wrapper.ContentType,
            FileName = wrapper.FileName,
            InputStream = wrapper.InputStream.ReadAllBytesAndReposition(),
        };

        serializer.Serialize(writer, surrogate);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var surrogate = serializer.Deserialize<HttpPostedFileSurrogate>(reader);
        var file = HttpPostedFileExtensions.ConstructHttpPostedFile(surrogate.InputStream, surrogate.FileName, surrogate.ContentType);
        return new HttpPostedFileWrapper(file);
    }
}

public static class HttpPostedFileExtensions
{
    public static HttpPostedFile ConstructHttpPostedFile(byte[] data, string filename, string contentType)
    {
        // Adapted from /questions/471134/how-to-instantiate-a-httppostedfile5515134#5515134
        // Get the System.Web assembly reference (they seem to be in different assemblies in different versions of .Net
        var assemblies = new[] { typeof(HttpPostedFile).Assembly, typeof(HttpPostedFileBase).Assembly };

        // Get the types of the two internal types we need
        Type typeHttpRawUploadedContent = assemblies.Select(a => a.GetType("System.Web.HttpRawUploadedContent")).Where(t => t != null).First();
        Type typeHttpInputStream = assemblies.Select(a => a.GetType("System.Web.HttpInputStream")).Where(t => t != null).First();

        // Prepare the signatures of the constructors we want.
        Type[] uploadedParams = { typeof(int), typeof(int) };
        Type[] streamParams = { typeHttpRawUploadedContent, typeof(int), typeof(int) };
        Type[] parameters = { typeof(string), typeof(string), typeHttpInputStream };

        // Create an HttpRawUploadedContent instance
        object uploadedContent = typeHttpRawUploadedContent
          .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, uploadedParams, null)
          .Invoke(new object[] { data.Length, data.Length });

        // Call the AddBytes method
        typeHttpRawUploadedContent
          .GetMethod("AddBytes", BindingFlags.NonPublic | BindingFlags.Instance)
          .Invoke(uploadedContent, new object[] { data, 0, data.Length });

        // This is necessary if you will be using the returned content (ie to Save)
        typeHttpRawUploadedContent
          .GetMethod("DoneAddingBytes", BindingFlags.NonPublic | BindingFlags.Instance)
          .Invoke(uploadedContent, null);

        // Create an HttpInputStream instance
        object stream = (Stream)typeHttpInputStream
          .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, streamParams, null)
          .Invoke(new object[] { uploadedContent, 0, data.Length });

        // Create an HttpPostedFile instance
        HttpPostedFile postedFile = (HttpPostedFile)typeof(HttpPostedFile)
          .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, parameters, null)
          .Invoke(new object[] { filename, contentType, stream });

        return postedFile;
    }
}

. StreamExtensions . HttpPostedFileBaseConverter โ€‹โ€‹ JsonSerializerSettings.Converters, .

( , , Microsoft HttpPostedFile, .)

+3

.

... json. ...

HttpPostedFileConverter, , , , Stream Base64 string. - :

public class StreamConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Stream).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return new MemoryStream(Convert.FromBase64String((string)reader.Value));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stream = (Stream)value;
        using (var sr = new BinaryReader(stream))
        {
            var buffer = sr.ReadBytes((int)stream.Length);
            writer.WriteValue(Convert.ToBase64String(buffer));
        }
    }
}

/ InputStream, :

settings.Converters.Add(new StreamConverter());

, . .

Deserializing HttpPostedFileBase

, , - ... , , HttpPostedFileWrapper

, HttpPostedFileWrapper, , . , :

public HttpPostedFileWrapper(
    HttpPostedFile httpPostedFile
)

, HttpPostedFile. HttpPostedFile .

, , , , HttpPostedFileBase.

:

public class CustomHttpPostedFile : HttpPostedFileBase
{
    [JsonProperty("ContentLength")]
    private int contentLength;
    [JsonProperty("FileName")]
    private string fileName;
    [JsonProperty("ContentType")]
    private string contentType;
    [JsonProperty("InputStream")]
    private Stream inputStream;
    [JsonIgnore]
    public override int ContentLength { get { return contentLength; } }
    [JsonIgnore]
    public override string FileName { get { return fileName; } }
    [JsonIgnore]
    public override string ContentType { get { return contentType; } }
    [JsonIgnore]
    public override Stream InputStream { get { return inputStream; } }
    public override void SaveAs(string filename)
    {
        using (var output = File.Create(fileName))
            InputStream.CopyTo(output);
    }
}

. HttpPostedFileWrapper, CustomCreationConverter, Json.NET Deserialize with CustomCreationConverter :

public class HttpPostedFileBaseConverter : CustomCreationConverter<HttpPostedFileBase>
{
    public override HttpPostedFileBase Create(Type objectType)
    {
        return new CustomHttpPostedFile();
    }
}

:

settings.Converters.Add(new StreamConverter());
settings.Converters.Add(new HttpPostedFileBaseConverter());

.

, , , , ( ). , , - .

+3

HttpPostedFileBase - , HttpPostedFile - . ASP.Net, HttpPostedFile. , , , , .

var file = (HttpPostedFile) Request.Files[0];

, HttpPostedFile HttpPostedFileBase, , , , mime, . , .. HttpPostedFile, ?

Edit

, json HttpPostedFile, . , HttpPostedFileBase, .

JsonConverter, :

public class StreamConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stream = (Stream)value;
        using (var sr = new BinaryReader(stream))
        {
            var buffer = sr.ReadBytes((int)stream.Length);
            writer.WriteValue(Convert.ToBase64String(buffer));
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var str = reader.ReadAsString();
        var stream = new MemoryStream();
        using (var sr = new BinaryWriter(stream))
        {
            sr.Write(Convert.FromBase64String(str));
        }
        return stream;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Stream).IsAssignableFrom(objectType);
    }
}
+2
source

Source: https://habr.com/ru/post/1659712/


All Articles