0

I managed to obtain from Microsoft MVC the bytearray of a file, its name and mimetype. I get that data from an Ajax call made with jQuery and get in console the following data:

data: {
  stream: [68, 82, 0, 0, 4, 57, 0, 0, 7, 179, 8, 6, 0, 0,…],
  filename: "testFile.png",
  mime: "image/png"
}

I get that data by an MVC controller method which returns a byte[] for the stream and two strings for filename and mime.

I need to make this stream js side a file for the user to download. I saw many approaches involving the Blob object, but still I can't get a correct file. I get a larger file, for example, for a png image but the downloaded version cannot be open as it is not valid. Here is my try to achieve the goal:

[...]
$.ajax({
  url: myUrlToControllerMethod, 
  type: 'POST', 
  data: { fileid: myFileId},
  success: function (res) {
    var a = document.createElement('a');
    var blob = new Blob(res.data.stream, { type: res.data.mime });
    console.warn(blob)
    const url = URL.createObjectURL(blob);
    console.info(url)
    a.href = url;
    a.download = res.data.filename;
    document.body.append(a);
    a.click();
    window.URL.revokeObjectURL(url);
  },
[...]

Where am I wrong?

EDIT: I add the controller method:

public JsonResult DlFileAsync(int fileid)
{
  var ute = GetUtente();
  DlModel result = FileUtils.DlFileAsync(fileid);
  result.mime = MimeMapping.GetMimeMapping(result.nomefile);
  var jsonResult =  Json(new GenericResponse(true, result), JsonRequestBehavior.AllowGet);
  jsonResult.MaxJsonLength = int.MaxValue;
  return jsonResult;
}

where: the last three lines (jsonResult thing) are a workaround to an MVC bug as learnt here.

GenericResponse is a generic data excange class as follows:

public class GenericResponse
{
    public bool result { get; set; }
    public object data { get; set; }
}

DlModel is a class for file information exchange as follows:

public class DlModel
{
    public byte[] stream { get; set; }
    public string filename{ get; set; }
    public string mime { get; set; }
}

And FileUtils.DlFileAsync is as follows:

public static DlModel DlFileAsync(int fileid)
  var dbFileEntry = getFromDb(fileid);
  var ret = new DlModel() {
    filename = dbFileEntry.FileName,
    stream = dbFileEntry.VarBinaryStream
  };
  return ret;
}

Here dbFileEntry is the db record, which has nvarchar(30) type for FileName and varbinary(MAX) for VarBinaryStream. The corresponding entity class in MVC is as follows:

public partial class FileStream : EntityGeneric   
{
  public int Id { get; set; }
  public string FileName { get; set; }
  public byte[] VarBinaryStream { get; set; }
}

I think that's almost all.

Nillus
  • 1,131
  • 1
  • 14
  • 32
  • It looks like `data.stream` should be `data.data.stream` based on your object, and the usage of references to other properties. Isn't this also already an array? You don't need to pass it as `Blob([data.data.stream], { type: data.data.mime})`, but as `Blob(data.data.stream, { type: data.data.mime})`. – Nathan Miller Feb 13 '20 at 21:06
  • It is a typo, every data.data is copy-paste error, I will edit and fix that later. I also tried without wrapping again data.stream in an array, but there is minimal change in the resulting file: with the array I get the sequence: 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0, [...] while without I get 13780787113102610000137372688200 [...] the same without commas. This is obviously not a png, I am doing some conversion terribly wrongly! – Nillus Feb 13 '20 at 21:13
  • Post the controller method that returns the data please. – Nathan Miller Feb 13 '20 at 21:26
  • I add that in the db the file is correctly stored, and if recovered in different ways it is valid. – Nillus Feb 13 '20 at 22:18

0 Answers0