如何通过Angular从基于iTextSharp的C# API下载PDF文件
修复C# API并实现Angular获取PDF的方案
一、C# API代码的问题修复
存在的核心问题:
- PDF生成路径错误:直接在当前目录创建文件,后续却去
wwwroot/docs查找,必然找不到目标文件 - 服务器端调用
Process.Start:这会在服务器本地打开PDF,客户端完全无法感知,毫无实际意义 - 资源未正确释放:
FileStream未使用using语句自动释放,可能导致文件占用或泄漏 - 异步方法未落地:方法标记为
async但无任何异步操作,要么移除async,要么改用异步IO - 未利用
doacaoId参数:当前代码未根据捐赠ID获取数据填充PDF内容,逻辑不完整 - 返回值错误:返回
CustomResponse无法让客户端接收到PDF文件,需返回文件流类型
修复后的API代码:
[AllowAnonymous] [HttpGet("comprovante-pdf/{doacaoId:guid}")] public IActionResult GerarComprovantePdf(Guid doacaoId) { // 1. 先根据doacaoId查询数据库获取捐赠数据(示例省略,需自行补充业务逻辑) // var doacao = await _doacaoRepository.GetByIdAsync(doacaoId); // if (doacao == null) return NotFound("捐赠记录不存在"); var pxPorMm = 72 / 25.2F; var pdf = new Document(PageSize.A4.Rotate(), 15 * pxPorMm, 15 * pxPorMm, 15 * pxPorMm, 20 * pxPorMm); // 直接在wwwroot/docs目录创建文件,确保路径正确 var fileName = $"comprovante_vaquinha_animal.{DateTime.Now:dd.MM.yyyy.HH.mm}.pdf"; var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/docs", fileName); // 使用using自动释放FileStream资源 using var arquivo = new FileStream(filePath, FileMode.Create); var writer = PdfWriter.GetInstance(pdf, arquivo); pdf.Open(); // 添加标题 var fonteTitulo = new Font(fonteBase, 28, Font.NORMAL, BaseColor.Black); var titulo = new Paragraph("Comprovante de Doação", fonteTitulo); titulo.Alignment = Element.ALIGN_LEFT; titulo.SpacingAfter = 10; pdf.Add(titulo); // 添加表格(填充实际捐赠数据) var tabela = new PdfPTable(4); float[] largurasColunas = { 0.5f, 1.5f, 1.0f, 1.2f }; tabela.SetWidths(largurasColunas); tabela.DefaultCell.BorderWidth = 0; tabela.WidthPercentage = 100; // 示例:插入捐赠数据行(替换为实际业务数据) tabela.AddCell("ID"); tabela.AddCell(doacaoId.ToString()); tabela.AddCell("Data"); tabela.AddCell(DateTime.Now.ToString("dd/MM/yyyy")); pdf.Add(tabela); pdf.Close(); // 返回PDF文件流给客户端,指定文件名触发浏览器下载 var fileBytes = System.IO.File.ReadAllBytes(filePath); return File(fileBytes, "application/pdf", fileName); }
二、Angular端获取并下载PDF的实现
1. 封装API调用服务
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class DoacaoService { private apiBaseUrl = '你的API基础地址'; // 替换为实际API地址 constructor(private http: HttpClient) {} gerarComprovantePdf(doacaoId: string) { const headers = new HttpHeaders({ 'Accept': 'application/pdf' }); return this.http.get(`${this.apiBaseUrl}/comprovante-pdf/${doacaoId}`, { headers, responseType: 'blob' // 指定返回类型为二进制Blob }); } }
2. 组件中触发下载逻辑
import { Component } from '@angular/core'; import { DoacaoService } from './doacao.service'; @Component({ selector: 'app-doacao', templateUrl: './doacao.component.html' }) export class DoacaoComponent { constructor(private doacaoService: DoacaoService) {} baixarComprovante(doacaoId: string) { this.doacaoService.gerarComprovantePdf(doacaoId).subscribe(blob => { // 创建Blob临时URL const url = window.URL.createObjectURL(blob); // 创建隐藏a标签触发下载 const downloadLink = document.createElement('a'); downloadLink.href = url; downloadLink.download = `comprovante_vaquinha_animal.pdf`; // 自定义下载文件名 document.body.appendChild(downloadLink); downloadLink.click(); // 释放资源并清理DOM元素 window.URL.revokeObjectURL(url); document.body.removeChild(downloadLink); }, error => { console.error('生成PDF失败:', error); alert('无法生成捐赠证明,请稍后重试'); }); } }
3. 模板添加触发按钮
<button (click)="baixarComprovante('你的捐赠ID')">下载捐赠证明</button>
内容的提问来源于stack exchange,提问作者ThiagoWerneck
相关产品推荐
相关产品推荐

