简体   繁体   English

为什么使用 NPOI 将 DataTable 导出到 Excel 导致 ERR_CONNECTION_RESET

[英]Why exporting DataTable to Excel using NPOI cause to ERR_CONNECTION_RESET

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 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.我可以看到 memoryStream 有数据,但在“返回响应”上它没有返回给客户端,而是再次调用 function。 This is my code:这是我的代码:

HTML: 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: 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.) DAL:(生成 excel 的最终 function。)

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]这是我在 chrome 调试器中看到的:[Network][1]

In Timing I see "Stallen": [Stallen][2]在 Timing 我看到“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 @ Observab @ 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 (匿名) @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(匿名)@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 @Observab le.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:17 le.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。订阅@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(匿名)@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 (匿名) @ core .js:17 441 (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 441(匿名)@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,谢谢,

I solved the problem.我解决了这个问题。 I change the code:我更改代码:

API CONTROLLER: 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 DAL:周围使用仅用于编写 stream

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

                return stream;
            }

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

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