简体   繁体   中英

sending string from C# to client and converting into Uint8Array type byte array and then into blob to open excel file. Corgi Involved

So here in C# code i am sending corgi to client which has corgiBabies. Using ClosedXml here.

 var wbCorgiBabiesTemplate = new XLWorkbook();
                var wsCoriBabiesAmendementTemplate = wbCorgiBabiesTemplate.Worksheets.Add(" Work Sheet Corgi baby Template");
                wsCoriBabiesAmendementTemplate.Cell("A1").Value = "Corgi Parent";
                wsCoriBabiesAmendementTemplate.Cell("B1").Value = "Corgi Child";

                wsCoriBabiesAmendementTemplate.Cell("A2").Value = "Petunia";
                wsCoriBabiesAmendementTemplate.Cell("B2").Value = "Khaleesi";

                using (var ms = new MemoryStream())
                {
                    wbCorgiBabiesTemplate.SaveAs(ms);
                   byte[]  Corgibabies = ms.ToArray();
                }
       corgi.Corgibabies = System.Text.Encoding.UTF8.GetString(Corgibabies);
            
         return corgi;

After that in Client i want to open corgibabies in excel sheet but the conversion here is wrong somewhere i think that excel sheet doesn't open correctly.

var fileName = 'CorgiBabies.xlsx';

     dataAccessService.get('corgi')
            .then(function(response) {
                let utf8Encode = new TextEncoder();
                var strBytes = utf8Encode.encode(response.corgiBabies);
            
                    var a = document.createElement("a");
                    document.body.appendChild(a);
                    a.style = "display: none";
                    
                    var file = new Blob([strBytes], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
                    var fileURL = window.URL.createObjectURL(file);
                    a.href = fileURL;
                    a.download = fileName;
                    a.click();
                
            })

Below what excel sheet gives me error in image

在此处输入图像描述

Assuming you're on.Net Core+ (otherwise you can find the System.Buffers Nuget package for.Net standard or framework), on server side try

using System.Buffers; 
using System.Buffers.Text;

and insert

var outputBuffer = new Span<byte>();
var status = Base64.EncodeToUtf8(Corgibabies, outputBuffer, out var consumed, out var written);
// sanity check
// if (status != OperationStatus.Done) throw new Exception();`

// do the above just before replacing
// System.Text.Encoding.UTF8.GetString(Corgibabies);

// with
System.Text.Encoding.UTF8.GetString(outputBuffer);

Now I'm pretty certain that will ensure that the server responds with what the client should expect but I'm not set up to test the Javascript side of things (yet). In the meantime let me know if this helps you make progress.

PS1: the error in your original code was the implicit assumption that Corgibabies is an array containing the bytes of a UTF8 encoded string. It actually contains the raw bytes of what would normally be an.xlsx file on disk. What is needed is to make that into text (Base64 encoding) and ensure that text is UTF8. Obviously in the Javascript you need to do the reverse - UTF8 Base64 to binary, save to disk, open in Excel...

Instead of returning string as the Content, you can make it work with File .

        public ActionResult Get()
        {
            var wbCorgiBabiesTemplate = new XLWorkbook();
            var wsCoriBabiesAmendementTemplate = wbCorgiBabiesTemplate.Worksheets.Add(" Work Sheet Corgi baby Template");
            wsCoriBabiesAmendementTemplate.Cell("A1").Value = "Corgi Parent";
            wsCoriBabiesAmendementTemplate.Cell("B1").Value = "Corgi Child";

            wsCoriBabiesAmendementTemplate.Cell("A2").Value = "Petunia";
            wsCoriBabiesAmendementTemplate.Cell("B2").Value = "Khaleesi";
            wbCorgiBabiesTemplate.SaveAs("new.xlsx");
            var ms = new MemoryStream();
           wbCorgiBabiesTemplate.SaveAs(ms);

            ms.Position = 0;
            var fileName = "CorgiBabies.xlsx";
            return File(ms, "application/octet-stream", fileName);
        }

Api call:

<a href="https://localhost:7135/api/downloadExcel"></a>

or

fetch('https://localhost:7135/api/downloadExcel')
  .then(resp => resp.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    // the filename you want
    a.download = 'CorgiBabies.xlsx';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
  })
  .catch(() => alert('oh no!'));

Ref: git

ClosedXML has several extensions that will help you acheive what you need:

You can install the appropriate extension for your project, to help give you a fast access to download the workbook. You can also save the file on disk, and pass the file link (path) to JavaScript, and continue your work on the file from JavaScript.

if you need to know how you would let the user download the file from ASP.NET, then you can do this:

Simple workbook:

C#: ASP.NET MVC

[HttpGet]
public ActionResult Download(string fileName)
{
    // create workbook 
    var workbook = new XLWorkbook();
    var sheet = workbook.Worksheets.Add("Worksheet 1");
    sheet.Cell("A1").Value = "A1";
    sheet.Cell("B1").Value = "B1";
    sheet.Cell("A2").Value = "A2";
    sheet.Cell("B2").Value = "B2";
    
    // get workbook bytes 
    byte[] workbookBytes;
    
    using (var memoryStream = new MemoryStream())
    {
        workbook.SaveAs(memoryStream);
        workbookBytes = memoryStream.ToArray();
    }

    return File(workbookBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
}

C#: ASP.NET Web Forms

public void Export(HttpResponse response, string fileName)
{
    // create workbook 
    var workbook = new XLWorkbook();
    var sheet = workbook.Worksheets.Add("Worksheet 1");
    sheet.Cell("A1").Value = "A1";
    sheet.Cell("B1").Value = "B1";
    sheet.Cell("A2").Value = "A2";
    sheet.Cell("B2").Value = "B2";

    HttpResponse httpResponse = response;
    httpResponse.Clear();
    httpResponse.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    httpResponse.AddHeader("content-disposition", $"attachment;filename=\"{fileName}.xlsx\"");

    using (var memoryStream = new MemoryStream())
    {
        workbook.SaveAs(memoryStream);
        memoryStream.WriteTo(httpResponse.OutputStream);
    }

    httpResponse.End();
}

the above examples will directly download the file into the client device. However, if you want to pass the workbook bytes to the JavaScript, you will need to convert it to base64 string and pass it to the JavaScript like so:

var base64String = Convert.ToBase64String(workbookBytes);

Then from JavaScript decode it to Uint8Array :

/*
    JavaScript
*/
// get base64 string array and decoded it
var data = atob(serverSideResult);

var array = new Array(data.length);

for (var i = 0; i < data.length; i++) {
    array[i] = data.charCodeAt(i);
}

// final result
var dataUint8Array = new Uint8Array(array);

now you can work with dataUint8Array as normal Uint8Array .

if you want to pass it back to the server-side, you can convert the array to base64 string, and pass it to the server-side like so:

/*
    JavaScript
*/
let binaryString = ''

for (var i = 0; i < dataUint8Array.byteLength; i++) {
    binaryString += String.fromCharCode(dataUint8Array[i]);
}
//pass base64Result to the server-side (C#)
var base64Result = window.btoa(binaryString);

then from C# you just need to convert it back to array from base64 string like so:

var bytes = Convert.FromBase64String(dataReceivedFromJavaScript);

where bytes would be byte[] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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