You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET中SQL存储PDF后邮件发送背景图丢失问题排查

PDF存入SQL Server后邮件发送丢失背景图的解决方法

问题场景

开发Web应用时,将jsPDF生成的PDF文件存入SQL Server的varbinary(MAX)字段,后续取出并通过邮件发送。当前代码可正常发送PDF,但打开后背景图丢失;直接使用IFormFile发送PDF时背景图显示正常,问题出在PDF与二进制格式的转换过程。

错误原因

  1. 上传阶段:使用StreamReader读取二进制PDF文件为字符串,再通过UTF8编码转换为字节数组。PDF是二进制文件,包含非UTF8兼容的字节,文本流读取会损坏原始二进制数据,导致背景图等内容丢失。
  2. 读取阶段:将数据库取出的字节数组转为UTF8字符串,再转回字节数组,二次破坏了二进制数据。

修正后的代码

前端AJAX提交代码(无需修改)

if(email) {
   var file = doc.output('blob');
   var fd = new FormData();
   fd.append('pdfFile',file);
   fd.append('jobNo',$('#jobNoInput').val());
   $.ajax({
       url: "/Jobs/SendInvoiceEmailToQueue",
       data: fd,
       dataType: 'text',
       processData: false,
       contentType: false,
       type: 'POST',
       success: function(data) {
           var data2 = JSON.parse(data);
           if(data2 == "SUCCESS")
           {
               quickToast('Invoice added to Email Queue for Job No: ' + $('#jobNoInput').val(), 'success', 'Added to Email Queue');
           }
       }
   });
} else {
   doc.save('Invoice.pdf');
}

后端上传PDF至数据库代码(修正版)

public IActionResult SendInvoiceEmailToQueue(string jobNo)
{
    IFormFile pdfFile = Request.Form.Files[0];
    
    // 直接读取PDF文件流为字节数组,避免文本转换
    byte[] pdfBytes;
    using (var ms = new MemoryStream())
    {
        pdfFile.CopyTo(ms);
        pdfBytes = ms.ToArray();
    }

    connectionString();
    using (var con = new SqlConnection(_connectionString)) // 假设connectionString()返回连接字符串
    {
        con.Open();
        var query = "INSERT INTO dbo.email_queue([JOBNO],[PDF],[EMAILADDRESS],[DATE],[TIME]) VALUES(@jobNo, @pdf, 'address', GETDATE(), CURRENT_TIMESTAMP)";
        using (var cmd = new SqlCommand(query, con))
        {
            // 字段为varbinary(MAX),使用SqlDbType.VarBinary而非Image
            var picparameter = new SqlParameter("@pdf", SqlDbType.VarBinary, -1)
            {
                Value = pdfBytes
            };
            var jobNoparameter = new SqlParameter("@jobNo", SqlDbType.Int)
            {
                Value = Int32.Parse(jobNo)
            };
            cmd.Parameters.Add(picparameter);
            cmd.Parameters.Add(jobNoparameter);
            cmd.ExecuteNonQuery();
        }
    }

    return new JsonResult("SUCCESS");
}

后端读取PDF并发送邮件代码(修正版)

public IActionResult SendInvoiceEmail(string queueNo)
{
    connectionString();
    using (var con = new SqlConnection(_connectionString))
    {
        con.Open();
        // 使用参数化查询避免SQL注入
        var query = "SELECT PDF FROM dbo.recovery_email_queue WHERE EmailQueueRecNo = @queueNo";
        using (var cmd = new SqlCommand(query, con))
        {
            cmd.Parameters.AddWithValue("@queueNo", queueNo);
            using (var dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    // 直接取出二进制字节数组,无需UTF8转换
                    var pdfBytes = (byte[])dr["PDF"];
                    var stream = new MemoryStream(pdfBytes);

                    // 直接创建Attachment,无需包装成IFormFile
                    var attachment = new Attachment(stream, "invoice.pdf", "application/pdf");

                    using (MailMessage mail = new MailMessage())
                    {
                        mail.From = new MailAddress("fromAdd");
                        mail.To.Add("add");
                        mail.Subject = "Test Sending Invoice";
                        mail.Body = "<h1>This is body</h1>";
                        mail.IsBodyHtml = true;

                        mail.Attachments.Add(attachment);
                        using (SmtpClient smtp = new SmtpClient("smtp-mail.outlook.com", 587))
                        {
                            smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
                            smtp.UseDefaultCredentials = false;
                            smtp.Credentials = new System.Net.NetworkCredential(
                                ConfigurationManager.AppSettings["emailUser"].ToString(), 
                                ConfigurationManager.AppSettings["emailPass"].ToString()
                            );
                            smtp.EnableSsl = true;
                            smtp.Send(mail);
                        }
                    }
                }
            }
        }
    }

    return new JsonResult("SUCCESS");
}

额外注意事项

  • 数据库字段类型为varbinary(MAX),对应SqlDbType应使用SqlDbType.VarBinary(设置长度为-1表示MAX),而非已废弃的SqlDbType.Image。
  • 所有数据库连接、命令、流对象都应使用using语句,确保资源自动释放,避免内存泄漏。
  • 读取数据库时使用参数化查询,避免SQL注入风险。

内容的提问来源于stack exchange,提问作者TryingAgain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 20:42:12