.NET MVC deserialize byte array from JSON Uint8Array

问题内容:

I’m using js-scrypt (https://github.com/tonyg/js-scrypt) on my client-side web application to hash and salt passwords before posting them to my server-side .NET MVC application to be hashed and salted again. This JavaScript library implements byte arrays as JavaScript Uint8Arrays. How do I get my MVC Controller to deserialize my JSON Uint8Array to a byte[]?

JavaScript Example: (AJAX.Post is a library I wrote, myUint8Array serializes properly)

AJAX.Post('www.example.com/SendByteArray', { myByteArray: myUint8Array }, Callback);

C# Example: (In my default controller)

[HttpPost]
public async Task<JsonResult> SendByteArray(byte[] myByteArray) {

}

In this example myByteArray is always null. I’ve tried a couple different approaches based on converting to strings and then back to a byte[] but I haven’t been able to get the correct value. It would be greatly preferred if I could somehow implement the code into .NET’s JSON deserializer directly so that the code above works exactly as is, because I have a few other projects where I could do some cool things if I could pass byte arrays directly between the server-side and client-side applications.

问题评论:

答案:

答案1:

I faced the same issue and after lot of R&D. I came to few conclusions.

Approach 1:
C# cannot deserialize javascript types arrays(UInt8Array, UInt16Array etc.). The data should be copied in to normal java script array from typed array and that data should be sent. At the receiving end (C# endpoint method) the parameter should be integer array instead of byte array. If byte array is placed, data received as null at the end point. Received integer array should be converted to byte array for file recovery.

Approach 2:
Another option to send typed array data instead of copying javascript typed array data into normal array is to send the typed array data as it is and at the receiving end (C# endpoint method), the method parameter should object. This object should be iterated using some linq and should be converted to byte array for file recovery.

Both are approaches discovered above are very slow according to me. When I am sending 3 files each of 5MB size, my browser (IE 10 browser) memory consumption increased exponentially while sending the data through Ajax request. I am still not able to figure out the issue. If someone is able to send byte array using Ajax please let me know.

Approach 3:
Third approach is to convert the byte array to base64 encoded string and send it. Though this increases the file size by 33% this approach is far better than above two. I am able to send 15 MB file easily and memory consumption of browser is aroung 80MB while sending this 3 files and consumption become less once the files are sent.

Important: Please deallocate memory of the variable after reading the file content. Garbage collection in IE is not that good. I faced a lot of issues with memory consumption after reading file using fileReader. Deallocate all the unused variable and byte array content of the file when they are no longer needed.

Please let me know if am wrong.

答案评论:

答案2:

For now the only method I could get to work was to base64 encode the Uint8Array, capture it as a string in C#, and then convert that string to a byte[].

JavaScript:

AJAX.Post('www.example.com/SendByteArray', { strByteArray: btoa(String.fromCharCode.apply(null, myUint8Array)) }, Callback);

C#:

[HttpPost]
public async Task<JsonResult> SendByteArray(string strByteArray) {
    byte[] myByteArray = Convert.FromBase64String(strByteArray);
}

答案评论:

答案3:

Change your controller action to accept an int[] instead of byte[], then convert to a byte array. The post value can still be a JSON array.

[HttpPost]
public async Task<JsonResult> SendByteArray(int[] myByteArray) {

     byte[] theBytes = myByteArray.Select(i => (byte)i).ToArray();

     // Or any one of a dozen other ways of converting it

}

In order to post to a byte array, you’d have to base-64 encode the bytes on the client, and pass it in as a string.

There may be an alternative, like a filter or attribute or something like that, but this is the easiest way I know of.

答案评论:

    
int[] still isn’t picking it up, it’s still null. I think the issue is that a Uint8Array doesn’t serialize into an actual JSON array, it serializes into an object with properties {0: 168, 1: 49,…} among a few other properties.
– user1084447
Jul 25 ’13 at 14:20
    
That’s interesting – didn’t realize that a Uint8Array serialized into a regular object instead of a straight-up array. Looks like if you can convert the Uint8Array into a regular array by calling myUnit8Array.subarray(), which should give you just the bytes, which you could then post into the int[] parameter. Might be worth comparing that vs. your base-64 solution, see which one provides a smaller footprint.
    
myUnit8Array.subarray() still appears to produce the same odd object {0: 168, 1: 49,…}
    
@blaster Hmm, didn’t see that before – I guess my browser console tricked me. Only thing left I can think of is to create a brand new array and push all the values into it one at a time, then serialize that new array.

答案4:

you must Use Jason.stringify To Serialize it And set Some Attribute of ajax .This is Example That I Use And It Works

            var list = [];

           //Fill list array

            var parameters = {};
            parameters = JSON.stringify({ "Your parameter": list });
            jQuery.ajax({
                url: '@Url.Action("Your Action")';,
                type: 'POST',
                contentType: 'application/json; charset=utf-8',
                dataType: "html",
                traditional: true,
                data: parameters,
                success: function (data, textStatus, jqXHR) {
                   //TODO: on success
                },
                error: function (data) {
                       //TODO: on fail
                }    
            });

    [HttpPost]
    public async Task<JsonResult> SendByteArray(IEnumerable<byte> myByteArray) {

    }

     OR Do this Way

    [HttpPost]
    public async Task<JsonResult> SendByteArray(int[] myByteArray) {
      convert to byte here
    }

答案评论:

答案5:

Building on the solution of user1084447 (serializing and deserializing to a base64 string), this works pretty good for serialization:

var serialized = fromByteArray(myUint8Array);

Where the fromeByteArray function comes from this github project. I learned about the base64-js from this documentation on mdn.

答案评论:

原文地址:

https://stackoverflow.com/questions/47752699/uint8array-input-was-not-valid

添加评论

友情链接:蝴蝶教程