简体   繁体   中英

How to consume a asp.net core 3.1 web api returning a file with open api client side generated code for typescript(angular)

this is the issue. I have a web api method that generates a pdf using DinktoPdf and I want to return it to the angular client and show it on a pop-pup but cant seem to open it. This is the code for my api:

[HttpGet("PrintGravimetricSheetReport")]
[SwaggerOperation(OperationId = "PrintGravimetricSheetReport")]
[SwaggerResponse(200, "Ok", typeof(File))]
[SwaggerResponse(400, "Bad Request", typeof(ErrorResponse))]
public async Task<IActionResult> PrintGravimetricSheetReport()
{
   var vm  = new QuoteLineItemModel();
   var documentContent = await _templateService.RenderTemplateAsync("GravSheet", vm);
   string folderPath = _hostEnvironment.ContentRootPath + "\\GeneratedDocs\\GravSheets\\";

   if (!Directory.Exists(folderPath))
   Directory.CreateDirectory(folderPath);

   var fileName = folderPath + "GravSheet_Report.pdf".AppendTimeStamp();


   var globalSettings = new GlobalSettings
   {
      ColorMode = ColorMode.Color,
      Orientation = Orientation.Portrait,
      PaperSize = PaperKind.A4,
      Margins = new MarginSettings(){Top =10},
      DocumentTitle = "GravSheet Report",
      Out = fileName
   };

   var objectSettings = new ObjectSettings
   {
      PagesCount = true,
      HtmlContent = documentContent,
      WebSettings = { DefaultEncoding = "utf-8" },
      HeaderSettings = { FontName = "Arial", FontSize = 9, Right = "Page [page] of [toPage]", Line = true},
      FooterSettings = { FontName = "Arial", FontSize = 9, Line = true, Center = "Report Footer"}
   };

   var pdf = new HtmlToPdfDocument
   {
      GlobalSettings = globalSettings,
      Objects = {objectSettings}
   };

   var file = _converter.Convert(pdf);

   return File(file, "application/pdf");
}

as you can observe there I'm using swagger to document my api and also I use Open-Api to generate the typescript client side for the angular client. this is the autogenerated code:

import { Inject, Injectable, Optional }                      from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
         HttpResponse, HttpEvent, HttpParameterCodec }       from '@angular/common/http';
import { CustomHttpParameterCodec }                          from '../encoder';
import { Observable }                                        from 'rxjs';

import { ErrorResponse } from '../model/errorResponse';

import { BASE_PATH, COLLECTION_FORMATS }                     from '../variables';
import { Configuration }                                     from '../configuration';


@Injectable({
  providedIn: 'root'
})
export class ReportsService {

    protected basePath = 'http://localhost';
    public defaultHeaders = new HttpHeaders();
    public configuration = new Configuration();
    public encoder: HttpParameterCodec;

    constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
        if (configuration) {
            this.configuration = configuration;
        }
        if (typeof this.configuration.basePath !== 'string') {
            if (typeof basePath !== 'string') {
                basePath = this.basePath;
            }
            this.configuration.basePath = basePath;
        }
        this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
    }



    /**
     * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
     * @param reportProgress flag to report request and response progress.
     */
    public printGravimetricSheetReport(observe?: 'body', reportProgress?: boolean): Observable<object>;
    public printGravimetricSheetReport(observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<object>>;
    public printGravimetricSheetReport(observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<object>>;
    public printGravimetricSheetReport(observe: any = 'body', reportProgress: boolean = false ): Observable<any> {

        let headers = this.defaultHeaders;

        // to determine the Accept header
        const httpHeaderAccepts: string[] = [
            'text/plain',
            'application/json',
            'text/json'
        ];
        const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
        if (httpHeaderAcceptSelected !== undefined) {
            headers = headers.set('Accept', httpHeaderAcceptSelected);
        }


        return this.httpClient.get<object>(`${this.configuration.basePath}/api/Reports/PrintGravimetricSheetReport`,
            {
                withCredentials: this.configuration.withCredentials,
                headers: headers,
                observe: observe,
                reportProgress: reportProgress
            }
        );
    }

}

This is what I've tried to open the object returned by the api in the client:

printGravSheet(): void {
    this.reportService.printGravimetricSheetReport().subscribe(response => {
      const blob = new Blob([response], { type: 'application/pdf' });
      const url = window.URL.createObjectURL(response);
      const showWindow = window.open(url);
      if (!showWindow || showWindow.closed || typeof showWindow.closed === 'undefined') {
        alert('Please disable your Pop-up blocker and try again');
      }
    });
  }

And just get error messages out of it. Please can someone point out the correct way to do this. Thanks in advance.

So looking around I found that you need to delete the line on the web api:

Out = fileName

the web api final version would be as:

[HttpGet("PrintGravimetricSheetReport")]
[SwaggerOperation(OperationId = "PrintGravimetricSheetReport")]
[SwaggerResponse(200, "Ok", typeof(FileContentResult))]
[SwaggerResponse(400, "Bad Request", typeof(ErrorResponse))]
public async Task<IActionResult> PrintGravimetricSheetReport()
{
   var vm  = new QuoteLineItemModel();
   var documentContent = await _templateService.RenderTemplateAsync("GravSheet", vm);
         
   var globalSettings = new GlobalSettings
   {
      ColorMode = ColorMode.Color,
      Orientation = Orientation.Portrait,
      PaperSize = PaperKind.A4,
      Margins = new MarginSettings(){Top =10},
      DocumentTitle = "GravSheet Report",
   };

   var objectSettings = new ObjectSettings
   {
      PagesCount = true,
      HtmlContent = documentContent,
      WebSettings = { DefaultEncoding = "utf-8" },
      HeaderSettings = { FontName = "Arial", FontSize = 9, Right = "Page [page] of [toPage]", Line = true},
      FooterSettings = { FontName = "Arial", FontSize = 9, Line = true, Center = "Report Footer"}
  };

  var pdf = new HtmlToPdfDocument
  {
      GlobalSettings = globalSettings,
      Objects = {objectSettings}
  };

  var file = _converter.Convert(pdf);
  return File(file, "application/pdf");
}

and the component method in angular is:

printGravSheet(): void {
    this.reportService.printGravimetricSheetReport().subscribe((blobResponse: Blob) => {
    const fileUrl = window.URL.createObjectURL(blobResponse);
    const showWindow = window.open(fileUrl);
    if (!showWindow || showWindow.closed || typeof showWindow.closed === 'undefined') {
      alert('Please disable your Pop-up blocker and try again');
    }
  });
};

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