简体   繁体   English

.NET MVC从JSON Uint8Array反序列化字节数组

[英].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. 我在客户端Web应用程序上使用js-scrypt( https://github.com/tonyg/js-scrypt )对密码进行哈希处理和加盐处理,然后再将密码发布到服务器端.NET MVC应用程序进行哈希处理和再加盐。 This JavaScript library implements byte arrays as JavaScript Uint8Arrays. 此JavaScript库将字节数组实现为JavaScript Uint8Arrays。 How do I get my MVC Controller to deserialize my JSON Uint8Array to a byte[]? 如何获得我的MVC控制器将JSON Uint8Array反序列化为一个字节[]?

JavaScript Example: (AJAX.Post is a library I wrote, myUint8Array serializes properly) JavaScript示例:(AJAX.Post是我编写的库,myUint8Array正确序列化了)

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

C# Example: (In my default controller) C#示例:(在我的默认控制器中)

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

}

In this example myByteArray is always null. 在此示例中,myByteArray始终为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. 我已经尝试了几种基于转换为字符串然后返回到byte []的方法,但是我一直无法获得正确的值。 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. 如果我能以某种方式直接将代码直接实现到.NET的JSON反序列化器中,以便上面的代码按原样工作,那将是非常可取的,因为我还有其他一些项目,如果我可以在之间直接传递字节数组,可以做一些很酷的事情服务器端和客户端应用程序。

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[]. 现在,我唯一可以使用的方法是对Uint8Array进行base64编码,在C#中将其捕获为字符串,然后将该字符串转换为byte []。

JavaScript: JavaScript:

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

C#: C#:

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

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.). 方法1:C#无法反序列化javascript类型数组(UInt8Array,UInt16Array等)。 The data should be copied in to normal java script array from typed array and that data should be sent. 数据应该从类型数组复制到普通的Java脚本数组中,并且应该发送该数据。 At the receiving end (C# endpoint method) the parameter should be integer array instead of byte array. 在接收端(C#端点方法),该参数应为整数数组而不是字节数组。 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. 方法2:发送类型化数组数据(而不是将javascript类型化数组数据复制到普通数组中)的另一种方法是按原样发送类型化数组数据,并且在接收端(C#端点方法),方法参数应为对象。 This object should be iterated using some linq and should be converted to byte array for file recovery. 该对象应使用一些linq进行迭代,并应转换为字节数组以进行文件恢复。

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. 当我发送3个文件(每个文件大小均为5MB)时,通过Ajax请求发送数据时,浏览器(IE 10浏览器)的内存消耗呈指数增长。 I am still not able to figure out the issue. 我仍然无法找出问题所在。 If someone is able to send byte array using Ajax please let me know. 如果有人能够使用Ajax发送字节数组,请告诉我。

Approach 3: Third approach is to convert the byte array to base64 encoded string and send it. 方法3:第三种方法是将字节数组转换为base64编码的字符串并将其发送。 Though this increases the file size by 33% this approach is far better than above two. 尽管这将文件大小增加了33%,但此方法远优于以上两种方法。 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. 我可以轻松发送15 MB的文件,并且在发送这3个文件的同时浏览器的内存消耗约为80 MB,一旦发送文件,消耗量就会减少。

Important: Please deallocate memory of the variable after reading the file content. 重要提示:请在读取文件内容后重新分配变量的内存。 Garbage collection in IE is not that good. IE中的垃圾收集不是很好。 I faced a lot of issues with memory consumption after reading file using fileReader. 使用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. 如果有错,请告诉我。

I used the following code for uploading large files in chunks from Angular 5 to ASP Core Web API. 我使用以下代码将大文件从Angular 5批量上载到ASP Core Web API。 On the client side - converting ArrayBuffer to Base64String: 在客户端-将ArrayBuffer转换为Base64String:

private arrayBufferToBase64String(buffer: ArrayBuffer) {
  let binaryString = ''
  var bytes = new Uint8Array(buffer);
  for (var i = 0; i < bytes.byteLength; i++) {
    binaryString += String.fromCharCode(bytes[i]);
  }

  return window.btoa(binaryString);
}

Posting the string (this is the Angular 2+ version): 发布字符串(这是Angular 2+版本):

var data = {
  data: this.arrayBufferToBase64String(arrayBuffer)
}

this.httpClient.post(url, data)

On the server (C#): 在服务器(C#)上:

var bytes = Convert.FromBase64String(part.Data);

part is a model class: part是模型类:

public class FilePartModel
{
    public string Data { get; set; }
}

Change your controller action to accept an int[] instead of byte[] , then convert to a byte array. 将您的控制器操作更改为接受int[]而不是byte[] ,然后转换为字节数组。 The post value can still be a JSON array. 帖子值仍可以是JSON数组。

[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. 为了发布到字节数组,您必须对客户端上的字节进行base-64编码,然后将其作为字符串传递。

There may be an alternative, like a filter or attribute or something like that, but this is the easiest way I know of. 可能有其他选择,例如过滤器或属性或类似的东西,但这是我所知道的最简单的方法。

you must Use Jason.stringify To Serialize it And set Some Attribute of ajax .This is Example That I Use And It Works 您必须使用Jason.stringify对其进行序列化并设置ajax的某些属性。这是我使用且有效的示例

            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
    }

Building on the solution of user1084447 (serializing and deserializing to a base64 string), this works pretty good for serialization: 建立在user1084447的解决方案(序列化和反序列化为base64字符串)的基础上,这对于序列化非常有效:

var serialized = fromByteArray(myUint8Array);

Where the fromeByteArray function comes from this github project . fromeByteArray函数来自此github项目 I learned about the base64-js from this documentation on mdn . 我从mdn上的该文档了解了base64-js。

I wasn't able to change server side's, so I needed to keep the byte[] type on server's endpoint. 我无法更改服务器端,因此需要在服务器的端点上保留byte[]类型。 In order to solve this I ended up transforming my Uint8Array to a simple array of bytes, which JSON parses as an array instead of an object. 为了解决这个问题,我最终将Uint8Array转换为一个简单的字节数组,JSON将其解析为数组而不是对象。

            const byteArray = [];
            Object.keys(contentUint8Array).forEach((key) =>{
                const byteForKey = contentUint8Array[key];
                byteArray.push(byteForKey);
            });

This way .Net endpoint was able to deserialize to a Byte array. 这样,.Net端点可以反序列化为Byte数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM