0

I develop a web API with ASP.NET C# and angular 8. I try to export some data from Oracle into Excel file on the server-side (using NPOI) and download it in client-side. I can see that the memoryStream have the data but on the "return response" it doesnt returned to the client and instead of it the function is called again. This is my code:

HTML:

 <button
            class="col-sm-2 button-style button-text"
            style="color: white; background-color: #19D893;height: 100%;"
            (click)="exportPriceList()">
        Export
        </button>

type script:

public exportPriceList(): void {

      let fileName='filename'; 
      const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

      console.log('before promise');

      const promise = new Promise((resolve, reject) => {                                 
        this.export().subscribe(
          success => {
            console.log('start success');
      
            const blob = new Blob ([success], {type: fileType});
      
            console.log('window.navigator ', window.navigator  );
            console.log('window.navigator.msSaveOrOpenBlob ', window.navigator.msSaveOrOpenBlob  );
      
            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
              
      
              window.navigator.msSaveOrOpenBlob(blob, );
            } else {
                const a = document.createElement('a');
                a.href = URL.createObjectURL(blob);
                a.download = fileName ;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
            }
        },
        err => {
            alert(err);
        });
       
     });

      promise.then((res) => {
        console.log('promise!!!! ', res );
      });
      promise.catch((err) => {
      });
    }

public export()
  {
    console.log('start export to excel');

    const fileName = 'filename1'; 
    const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

    const url =  this.apiService.baseUrl + 'api/PriceList/Export?token=' + this.auth.authDetails.getValue().token +
        '&priceListType=' + this.selectedPriceListType.Key + '&fileType=' + fileType + '&bank=' + this.selectedBank.Key;

    return this.http.get(url, {responseType:  'arraybuffer'});// this.http.get(url, {responseType:  'blob'});
  }

API Controller:

[HttpGet]
    [Route("api/PriceList/Export")]
    public HttpResponseMessage Export([FromUri]string token, [FromUri]int priceListType,[FromUri]string fileType, [FromUri]int? bank=null)
    {
        try
        {
            var stream = dal.ExportPriceListServer(priceListType, bank);

            var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);

            response.Content = new StreamContent(stream);
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName= "PriceList_" + bank + "_" + DateTime.Now.ToString("yyyyMMdd") + ".xlsx" 
            };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(fileType);

            return response;
        }
        catch (Exception ex)
        {
            exc.throwException(EventLogEntryType.Error, ex.ToString());
            throw;
        }
    }

DAL: (The final function which generate the excel.)

public MemoryStream ExportToExcel(DataTable dt)
    {
        try
        {
            using (var stream = new MemoryStream())
            {
                // Declare XSSFWorkbook object for create sheet  
                var workbook = new XSSFWorkbook();
                var sheet = workbook.CreateSheet("sheet 1");

                int rowIndex = 0;
                var headerRow = sheet.CreateRow(1);

                //Below loop is create header  
                foreach (DataColumn column in dt.Columns)
                {
                    XSSFCell xc = (XSSFCell)headerRow.CreateCell(column.Ordinal);
                    xc.SetCellValue(GetColumnTitle(column.ColumnName));
                    //xc.CellStyle = xstl;
                }

                rowIndex = 2;
                foreach (DataRow row in dt.Rows)
                {
                    XSSFRow dataRow = (XSSFRow)(sheet.CreateRow(rowIndex));

                    foreach (DataColumn column in dt.Columns)
                    {
                        XSSFCell c = (XSSFCell)dataRow.CreateCell(column.Ordinal);
                        string val = row[column].ToString();

                        int x;
                        if (Int32.TryParse(val, out x) && (!String.IsNullOrEmpty(val)))//column.IsNumeric()
                        {
                            c.SetCellValue(Int64.Parse(val));
                            c.SetCellType(CellType.Numeric);
                        }
                        else
                        {
                            c.SetCellValue(row[column].ToString());
                        }

                        // no need to auto size all the time, after 100 is ok... (it costs a lot)
                        if (rowIndex == 100)
                        {
                            sheet.AutoSizeColumn(column.Ordinal);
                        }

                    }

                    rowIndex++;
                }

                // Declare one MemoryStream variable for write file in stream  

                workbook.Write(stream, true);

                return stream;
            }
        }
        catch (Exception ex)
        {

            Console.Write(ex);
            return null;
        }
    }

This is what I see in chrome debugger: [Network][1]

In Timing I see "Stallen": [Stallen][2]

rates.component.ts:100 before promise
zone.js:2969 GET .....     **net::ERR_CONNECTION_RESET**
scheduleTask @ zone.js:2969
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:407
onScheduleTask @ zone.js:297
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:401
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:232
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:255
scheduleMacroTaskWithCurrentZone @ zone.js:1114
(anonymous) @ zone.js:3001
proto.<computed> @ zone.js:1394
(anonymous) @ http.js:1630
push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe

@ Observable.js:43 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:29 push../node_modules/rxjs/_esm5/internal/operators/finalize.js.FinallyOperator.call @ finalize.js:13 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:24 (anonymous) @ subscribeTo.js:21 subscribeToResult @ subscribeToResult.js:11 push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._innerSub @ mergeMap.js:74 push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext @ mergeMap.js:68 push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next @ mergeMap.js:51 push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:54 (anonymous) @ scalar.js:5 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe @ Observable.js:43 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:29 push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call @ mergeMap.js:29 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:24 push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterOperator.call @ filter.js:15 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:24 push../node_modules/rxjs/_esm5/internal/operators/map.js.MapOperator.call @ map.js:18 push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe @ Observable.js:24 (anonymous) @ rates.component.ts:144 ZoneAwarePromise @ zone.js:891 push../src/app/Components/content/rates/rates.component.ts.RatesComponent.exportPriceList @ rates.component.ts:143 eval @ RatesComponent.html:100 handleEvent @ core.js:19545 callWithDebugContext @ core.js:20639 debugHandleEvent @ core.js:20342 dispatchEvent @ core.js:16994 (anonymous) @ core.js:17441 (anonymous) @ platform-browser.js:993 push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:421 onInvokeTask @ core.js:14051 push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:420 push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:188 push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:496 invokeTask @ zone.js:1540 globalZoneAwareCallback @ zone.js:1566

Do you have any solution for me?

Thanks,

Coral Adar
  • 31
  • 4

1 Answers1

0

I solved the problem. I change the code:

API CONTROLLER:

MemoryStream stream = dal.ExportPriceListServer(priceListType);

            var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);

            response.Content = new ByteArrayContent(stream.ToArray());
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = "test.xlsx"
            };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(fileType);

            return response;

DAL: surrounded with using Just for write the stream

 // Declare one MemoryStream variable for write file in stream  
            using (var stream = new MemoryStream())
            {
                workbook.Write(stream, true);

                return stream;
            }
Coral Adar
  • 31
  • 4