13

After achieving successful implementation of ajax POST, uploading model objects and even complex objects thanks to this nice post, the new goal is to have an implementation for even little more complicated scenario.

I have tried to implement the task in question via code examples searching google without a concrete and correct answer

The goal is to have multi purpose (multi data-type) data transfer from client side to server (without use of a form or HttpRequestBase) passing raw byte array in the most efficient way (i know that it is possible to implement a new protocol HTTP/2 or googles Protocol Buffers - Google's data interchange format

[HttpPost]
public JsonResult UploadFiles(byte[] parUploadBytearry)
{
}

preferably a model which one of it's properties is a byte[]

[HttpPost]
public [JsonResult / ActionResult] Upload(SomeClassWithByteArray parDataModel)
{
}

The ajax http Post Signature :

Log("AajaxNoPostBack preparing post-> " + targetUrl);
$.ajax({
    type: 'POST',
    url: targetUrl,
    data: mods,
    contentType: "application/json; charset=utf-8",
    dataType: "json",

    success:  function for Success..
});

I also desperately tried this workaround

public JsonResult UploadFiles(object parUploadBytearry)
{
    if (parUploadBytearry== null)
        return null;
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    var pathtosSave = System.IO.Path.Combine(Server.MapPath("~/Content/uploaded"), "Test11.png");
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
    {
        bf.Serialize(ms, parUploadFiles);
        var Barr =  ms.ToArray();
        var s = new System.Web.Utils.FileFromBar(pathtosSave, BR);
    }
}

as it did post and received data all the way to saving the data (.png) successfully to a file in system, the data was not legit.

And the last sane try before the object to byte array attempt was this msdn Code example 1

What is the correct way to pass a byte array that C# will understand?

(in case of documents raw byte[] or files like png images)

Yuval Itzchakov
  • 136,303
  • 28
  • 230
  • 296
  • In your `SomeClassWithByteArray` example, if the transfer protocol is JSON, how do you serialize the byte array? Base64? – Yuval Itzchakov Mar 13 '16 at 09:06
  • this is also an option, as i said at the beginning of the post for complex objects i have used `toDictionary` plugin, i have expected that raw data , as one of it's members , will be the most trivial to then convert in any efficient method – כרמי רפאל Mar 13 '16 at 09:17

1 Answers1

3

What is the correct way to pass a byte array

The easiest way of reading a byte[] from WebAPI without writing custom MediaTypeFormatter for "application/octet-stream" is by simply reading it from the request stream manually:

[HttpPost]
public async Task<JsonResult> UploadFiles()
{
    byte[] bytes = await Request.Content.ReadAsByteArrayAsync();
}

In another post, I described how to utilize the built in formatter for BSON (Binary JSON) which exists in WebAPI 2.1.

If you do want to go down the read and write a BinaryMediaTypeFormatter which answers "application/octet-stream", a naive implementation would look like this:

public class BinaryMediaTypeFormatter : MediaTypeFormatter
{
    private static readonly Type supportedType = typeof(byte[]);

    public BinaryMediaTypeFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
    }

    public override bool CanReadType(Type type)
    {
        return type == supportedType;
    }

    public override bool CanWriteType(Type type)
    {
        return type == supportedType;
    }

    public override async Task<object> ReadFromStreamAsync(Type type, Stream stream,
        HttpContent content, IFormatterLogger formatterLogger)
    {
        using (var memoryStream = new MemoryStream())
        {
            await stream.CopyToAsync(memoryStream);
            return memoryStream.ToArray();
        }
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream stream,
        HttpContent content, TransportContext transportContext)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        if (!type.IsSerializable)
            throw new SerializationException(
                $"Type {type} is not marked as serializable");

        var binaryFormatter = new BinaryFormatter();
        binaryFormatter.Serialize(stream, value);
        return Task.FromResult(true);
    }
}
Community
  • 1
  • 1
Yuval Itzchakov
  • 136,303
  • 28
  • 230
  • 296
  • WebAPI 2.1 or Request.Content (specifically now) is it compatible to .NET 4.03 ? in my project there's no `Request.Content` Definition – כרמי רפאל Mar 13 '16 at 09:25
  • Web API 2.1 should be, there's no constraint to the .NET version AFAIK. The use of `async-await`, with .NET 4.0.3 would require you to use the [`Microsoft.Async.Bcl`](https://www.nuget.org/packages/Microsoft.Bcl.Async/) library. – Yuval Itzchakov Mar 13 '16 at 09:27
  • _This package is not supported in Visual Studio 2010,_ i knew i will need to pack up and move one day, but not now.. i am still stuck with the familiar 2010 as in desktop app i haven't reached the top notch development technology by Microsoft , i can see in web dev the story is different. if you don't use latest ... well everything . you simply cant work (not at all but optimally ) – כרמי רפאל Mar 13 '16 at 09:31
  • Well, 2010 is a six year old IDE, you should definitely move on to newer versions which support a broader set of options. – Yuval Itzchakov Mar 13 '16 at 09:38
  • so when i will soon, move to 2013/15 what you're saying is that the raw file is simply converts to the required data format? – כרמי רפאל Mar 13 '16 at 09:55
  • *the raw file is simply converts to the required data format* Not sure what that means, but wit the raw bytes you read you can later transform them to any format you need. – Yuval Itzchakov Mar 13 '16 at 09:58
  • `ReadFromStreamAsync` is the only part of your code that does not exist in my project namespace. what did you use back then when it was not out yet, we are talking about basics `byte[]` is not new to .NET, so how other than making use of latest technology would you deal with `bytes` ... the O2 of the data types ... i find it hard to believe that the only (sane) implantation will require to go this far, or the reason is if you don't then you have to write a similar API in size / complexity by your self ? – כרמי רפאל Mar 13 '16 at 10:10
  • http://forums.asp.net/t/1925422.aspx? sending+byte+array+in+the+webapi+ here and some other posts i read about what u have suggested, i will now implement the conventional `foreach (string file in Request.Files)` based approach , and when i will have the time to move to the new api's (interested in `SignalR` and google's `protobuff `) i will then open this in full screen to implement other advanced high performance Data-transfer Protocols and Api's, thanks a lot for now yuval for your kind answer ! – כרמי רפאל Mar 13 '16 at 10:50