使用 C# 在登入驗證後將 HTML 轉換為 PDF
若要在 C# 環境中透過登入驗證將 HTML 轉換為 PDF,請使用 IronPDF 的 ChromeHttpLoginCredentials 進行網路驗證,或在轉換前使用 HttpClient 下載 HTML 檔案。 此方法能有效處理網路驗證與 HTML 表單登入兩種情境。
快速入門:使用 IronPDF 將 HTML 轉換為 PDF(需登入)
利用 IronPDF 的 API,將登入表單後方的 HTML 頁面轉換為 PDF 檔案。 本指南示範了 ChromeHttpLoginCredentials 用於驗證及檢索受保護的內容。 請透過簡明扼要的程式碼範例,同時處理網路驗證與 HTML 表單登入機制。
-
using NuGet 套件管理員安裝 https://www.nuget.org/packages/IronPdf
PM > Install-Package IronPdf -
請複製並執行此程式碼片段。
new ChromePdfRenderer { LoginCredentials = new ChromeHttpLoginCredentials("username","password") } .RenderUrlAsPdf("https://example.com/protected") .SaveAs("secure.pdf"); -
部署至您的生產環境進行測試
立即透過免費試用,在您的專案中開始使用 IronPDF
簡化工作流程(5 個步驟)
- 下載 C# IronPDF 函式庫
- 下載 HTML 檔案以避免登入
- 使用 LoginCredentials 屬性透過網路驗證登入
- 使用 HTML 表單進行驗證
- MVC 登入驗證的解決方案
處理登入驗證的最佳實務有哪些?
IronPDF 透過 ChromeHttpLoginCredentials API 支援 TLS 網路驗證(使用者名稱與密碼)。 有關各種登入情境的完整指引,請參閱 TLS 網站與系統登入教學。
建議使用 System.Net.WebClient 或 HttpClient 來下載 HTML 及相關資源。 此方法支援標題、登入及其他相關需求。 IronPDF 會將 HTML 下載至記憶體或磁碟後,再轉換為 PDF 格式。 使用 HtmlAgilityPack 提取樣式表和圖片等資源,然後使用 System.Net.WebClient 進行下載。
// Download HTML content from a URL with authentication
string html;
using (WebClient client = new WebClient())
{
// Add authentication headers if needed
client.Headers.Add("Authorization", "Bearer " + accessToken);
// Download the HTML string
html = client.DownloadString("http://www.example.com/protected-content");
}
// Load the HTML into an HtmlDocument for parsing
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
// Extract all image sources for downloading
foreach(HtmlNode img in doc.DocumentNode.SelectNodes("//img"))
{
string imgSrc = img.GetAttributeValue("src", null);
Console.WriteLine($"Found image: {imgSrc}");
// Download each image asset
if (!string.IsNullOrEmpty(imgSrc))
{
string fileName = Path.GetFileName(imgSrc);
client.DownloadFile(imgSrc, fileName);
}
}
// Convert the downloaded HTML to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("authenticated-content.pdf");
// Download HTML content from a URL with authentication
string html;
using (WebClient client = new WebClient())
{
// Add authentication headers if needed
client.Headers.Add("Authorization", "Bearer " + accessToken);
// Download the HTML string
html = client.DownloadString("http://www.example.com/protected-content");
}
// Load the HTML into an HtmlDocument for parsing
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
// Extract all image sources for downloading
foreach(HtmlNode img in doc.DocumentNode.SelectNodes("//img"))
{
string imgSrc = img.GetAttributeValue("src", null);
Console.WriteLine($"Found image: {imgSrc}");
// Download each image asset
if (!string.IsNullOrEmpty(imgSrc))
{
string fileName = Path.GetFileName(imgSrc);
client.DownloadFile(imgSrc, fileName);
}
}
// Convert the downloaded HTML to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("authenticated-content.pdf");
Imports System.Net
Imports HtmlAgilityPack
Imports IronPdf
' Download HTML content from a URL with authentication
Dim html As String
Using client As New WebClient()
' Add authentication headers if needed
client.Headers.Add("Authorization", "Bearer " & accessToken)
' Download the HTML string
html = client.DownloadString("http://www.example.com/protected-content")
End Using
' Load the HTML into an HtmlDocument for parsing
Dim doc As New HtmlDocument()
doc.LoadHtml(html)
' Extract all image sources for downloading
For Each img As HtmlNode In doc.DocumentNode.SelectNodes("//img")
Dim imgSrc As String = img.GetAttributeValue("src", Nothing)
Console.WriteLine($"Found image: {imgSrc}")
' Download each image asset
If Not String.IsNullOrEmpty(imgSrc) Then
Dim fileName As String = Path.GetFileName(imgSrc)
Using client As New WebClient()
client.DownloadFile(imgSrc, fileName)
End Using
End If
Next
' Convert the downloaded HTML to PDF
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("authenticated-content.pdf")
System.Uri 建構函式,將相對網址轉換為絕對網址。 若要將 HTML 文件中的所有相對路徑轉換為絕對路徑,請使用 HtmlAgilityPack 在頁首加入 <base> 標籤。 範例。 有關處理 URL 和資源的更多資訊,請參閱《基礎 URL 與資源編碼指南》。}}為什麼我應該先下載 HTML 內容?
在轉換前先下載 HTML 內容有以下幾項優勢:
- 完全控制:在轉換前修改 HTML、修復失效連結,或插入驗證憑證
- 資產管理:下載並快取外部資源,例如圖片、CSS 及 JavaScript 檔案
- 驗證靈活性:支援任何 .NET 驗證機制,包括 OAuth、JWT 憑證或自訂標頭
- 效能:將頻繁存取的內容快取以減輕伺服器負載
- 除錯:檢查實際轉換的 HTML 內容以排除問題
若涉及包含 Cookie 和會話的複雜驗證情境,請參閱《Cookie 指南》,該指南說明了 PDF 轉換過程中的驗證狀態管理。
如何處理圖片和樣式表等資源?
在轉換需驗證的網頁時,外部資源通常也需要相同的驗證。 以下是採用 HttpClient 的全面翻譯方案:
public async Task<string> DownloadAuthenticatedHtmlWithAssets(string url, string authToken)
{
using (var client = new HttpClient())
{
// Set authentication header
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);
// Download the main HTML
string html = await client.GetStringAsync(url);
// Parse HTML to find assets
var doc = new HtmlDocument();
doc.LoadHtml(html);
// Create a base URI for resolving relative paths
var baseUri = new Uri(url);
// Download CSS files
var cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']");
if (cssLinks != null)
{
foreach (var link in cssLinks)
{
string href = link.GetAttributeValue("href", "");
if (!string.IsNullOrEmpty(href))
{
var cssUri = new Uri(baseUri, href);
string cssContent = await client.GetStringAsync(cssUri);
// Embed CSS directly in the HTML
var styleNode = doc.CreateElement("style");
styleNode.InnerHtml = cssContent;
doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode);
// Remove the external link
link.Remove();
}
}
}
// Return the modified HTML with embedded assets
return doc.DocumentNode.OuterHtml;
}
}
public async Task<string> DownloadAuthenticatedHtmlWithAssets(string url, string authToken)
{
using (var client = new HttpClient())
{
// Set authentication header
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);
// Download the main HTML
string html = await client.GetStringAsync(url);
// Parse HTML to find assets
var doc = new HtmlDocument();
doc.LoadHtml(html);
// Create a base URI for resolving relative paths
var baseUri = new Uri(url);
// Download CSS files
var cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']");
if (cssLinks != null)
{
foreach (var link in cssLinks)
{
string href = link.GetAttributeValue("href", "");
if (!string.IsNullOrEmpty(href))
{
var cssUri = new Uri(baseUri, href);
string cssContent = await client.GetStringAsync(cssUri);
// Embed CSS directly in the HTML
var styleNode = doc.CreateElement("style");
styleNode.InnerHtml = cssContent;
doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode);
// Remove the external link
link.Remove();
}
}
}
// Return the modified HTML with embedded assets
return doc.DocumentNode.OuterHtml;
}
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports HtmlAgilityPack
Public Class HtmlDownloader
Public Async Function DownloadAuthenticatedHtmlWithAssets(url As String, authToken As String) As Task(Of String)
Using client As New HttpClient()
' Set authentication header
client.DefaultRequestHeaders.Authorization = New System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken)
' Download the main HTML
Dim html As String = Await client.GetStringAsync(url)
' Parse HTML to find assets
Dim doc As New HtmlDocument()
doc.LoadHtml(html)
' Create a base URI for resolving relative paths
Dim baseUri As New Uri(url)
' Download CSS files
Dim cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']")
If cssLinks IsNot Nothing Then
For Each link In cssLinks
Dim href As String = link.GetAttributeValue("href", "")
If Not String.IsNullOrEmpty(href) Then
Dim cssUri As New Uri(baseUri, href)
Dim cssContent As String = Await client.GetStringAsync(cssUri)
' Embed CSS directly in the HTML
Dim styleNode = doc.CreateElement("style")
styleNode.InnerHtml = cssContent
doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode)
' Remove the external link
link.Remove()
End If
Next
End If
' Return the modified HTML with embedded assets
Return doc.DocumentNode.OuterHtml
End Using
End Function
End Class
有哪些工具有助於 HTML 解析?
HtmlAgilityPack 是 .NET 平台上最受歡迎的 HTML 解析函式庫,但也有其他替代方案:
- HtmlAgilityPack:最適合用於一般的 HTML 解析與處理
- AngleSharp:支援 CSS 選擇器的現代化、符合標準的 HTML 解析器
- CsQuery:專為熟悉 jQuery 的 C# 開發人員設計的 jQuery 風格語法
- 正規表達式:適用於簡單的資料擷取任務(不建議用於複雜的 HTML)
ChromeHttpLoginCredentials
如何使用網路驗證登入?
大多數 ASP.NET 應用程式皆支援網路驗證,其可靠性較 HTML 表單提交更高。 IronPDF 透過 ChromeHttpLoginCredentials 類別,內建支援基本、摘要及 NTLM 驗證機制。 如需進一步自訂標頭,請參閱《HTTP 請求標頭指南》。
:path=/static-assets/pdf/content-code-examples/how-to/logins-username-password.cs
using IronPdf;
using System;
ChromePdfRenderer renderer = new ChromePdfRenderer
{
// setting login credentials to bypass basic authentication
LoginCredentials = new ChromeHttpLoginCredentials()
{
NetworkUsername = "testUser",
NetworkPassword = "testPassword"
}
};
var uri = new Uri("http://localhost:51169/Invoice");
// Render web URL to PDF
PdfDocument pdf = renderer.RenderUrlAsPdf(uri);
// Export PDF
pdf.SaveAs("UrlToPdfExample.Pdf");
Imports IronPdf
Imports System
Private renderer As New ChromePdfRenderer With {
.LoginCredentials = New ChromeHttpLoginCredentials() With {
.NetworkUsername = "testUser",
.NetworkPassword = "testPassword"
}
}
Private uri = New Uri("http://localhost:51169/Invoice")
' Render web URL to PDF
Private pdf As PdfDocument = renderer.RenderUrlAsPdf(uri)
' Export PDF
pdf.SaveAs("UrlToPdfExample.Pdf")
為何網路驗證比表單提交更可靠?
相較於 HTML 表單提交,網路驗證具備以下幾項優勢:
- 標準化通訊協定:採用符合 RFC 標準的 HTTP 驗證標頭
- 瀏覽器整合:Chrome 渲染引擎可無縫處理驗證流程
- 會話管理:自動處理驗證挑戰與會話持久化
- 安全性:憑證透過標頭而非表單資料進行安全傳輸
- 相容性:可與大多數Enterprise級驗證系統配合使用 (
Active Directory,LDAP)
進行網路驗證需要哪些憑證?
不同的驗證類型需要不同的憑證:
// Basic Authentication (most common)
var basicAuth = new ChromeHttpLoginCredentials
{
NetworkUsername = "user@domain.com",
NetworkPassword = "password123",
AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
};
// NTLM/Windows Authentication
var ntlmAuth = new ChromeHttpLoginCredentials
{
NetworkUsername = "DOMAIN\\username", // Include domain
NetworkPassword = "password123",
AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
};
// Custom authentication headers
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key");
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " + jwtToken);
// Basic Authentication (most common)
var basicAuth = new ChromeHttpLoginCredentials
{
NetworkUsername = "user@domain.com",
NetworkPassword = "password123",
AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
};
// NTLM/Windows Authentication
var ntlmAuth = new ChromeHttpLoginCredentials
{
NetworkUsername = "DOMAIN\\username", // Include domain
NetworkPassword = "password123",
AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
};
// Custom authentication headers
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key");
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " + jwtToken);
Imports System.Collections.Generic
' Basic Authentication (most common)
Dim basicAuth As New ChromeHttpLoginCredentials With {
.NetworkUsername = "user@domain.com",
.NetworkPassword = "password123",
.AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
}
' NTLM/Windows Authentication
Dim ntlmAuth As New ChromeHttpLoginCredentials With {
.NetworkUsername = "DOMAIN\username", ' Include domain
.NetworkPassword = "password123",
.AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
}
' Custom authentication headers
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key")
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " & jwtToken)
如何排除驗證失敗的問題?
常見的驗證問題與解決方案:
- 401 未授權:請檢查憑證及驗證類型
- 403 禁止存取:使用者已通過驗證但缺乏權限
- 超時錯誤:針對認證系統速度緩慢的情況,請增加
Timeout - 憑證錯誤:請正確設定 TLS/SSL 設定
啟用除錯功能以診斷問題:
// Enable detailed logging
IronPdf.Logging.Logger.EnableDebugging = true;
IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
// Test authentication
try
{
var pdf = renderer.RenderUrlAsPdf("https://secure.example.com");
pdf.SaveAs("authenticated.pdf");
}
catch (Exception ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
// Check IronPdf.log for detailed error information
}
// Enable detailed logging
IronPdf.Logging.Logger.EnableDebugging = true;
IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
// Test authentication
try
{
var pdf = renderer.RenderUrlAsPdf("https://secure.example.com");
pdf.SaveAs("authenticated.pdf");
}
catch (Exception ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
// Check IronPdf.log for detailed error information
}
Imports IronPdf
Imports System
' Enable detailed logging
Logging.Logger.EnableDebugging = True
Logging.Logger.LogFilePath = "IronPdf.log"
Logging.Logger.LoggingMode = Logging.Logger.LoggingModes.All
' Test authentication
Try
Dim pdf = renderer.RenderUrlAsPdf("https://secure.example.com")
pdf.SaveAs("authenticated.pdf")
Catch ex As Exception
Console.WriteLine($"Authentication failed: {ex.Message}")
' Check IronPdf.log for detailed error information
End Try
如何使用 HTML 表單登入?
若要透過向 HTML 表單傳送資料來登入,請使用 ChromeHttpLoginCredentials 類別。 請參閱 IronPDF 的 ChromeHttpLoginCredentials API。
請注意以下要點:
- 將登入資料傳送至 HTML 表單中 ACTION 屬性所指定的 URL。 請將此內容設定為
LoginFormUrl的HttpLoginCredentials屬性。 這可能與您欲渲染為 PDF 的網址不同。 - 傳送代表 HTML 表單中每個輸入欄位和文字輸入區的資料。 名稱屬性定義了每個變數名稱(而非 ID)。
- 部分網站會主動防範機器人登入。
// Configure form-based login
var formLogin = new ChromeHttpLoginCredentials
{
LoginFormUrl = "https://example.com/login",
LoginFormData = new Dictionary<string, string>
{
{"username", "user@example.com"},
{"password", "securePassword123"},
{"rememberMe", "true"},
{"csrf_token", "abc123"} // Include any hidden fields
}
};
var renderer = new ChromePdfRenderer
{
LoginCredentials = formLogin,
RenderingOptions = new ChromePdfRenderOptions
{
RenderDelay = 3000, // Allow time for login redirect
EnableJavaScript = true
}
};
// The actual page you want to convert (after login)
var pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard");
pdf.SaveAs("dashboard.pdf");
// Configure form-based login
var formLogin = new ChromeHttpLoginCredentials
{
LoginFormUrl = "https://example.com/login",
LoginFormData = new Dictionary<string, string>
{
{"username", "user@example.com"},
{"password", "securePassword123"},
{"rememberMe", "true"},
{"csrf_token", "abc123"} // Include any hidden fields
}
};
var renderer = new ChromePdfRenderer
{
LoginCredentials = formLogin,
RenderingOptions = new ChromePdfRenderOptions
{
RenderDelay = 3000, // Allow time for login redirect
EnableJavaScript = true
}
};
// The actual page you want to convert (after login)
var pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard");
pdf.SaveAs("dashboard.pdf");
Imports System.Collections.Generic
' Configure form-based login
Dim formLogin As New ChromeHttpLoginCredentials With {
.LoginFormUrl = "https://example.com/login",
.LoginFormData = New Dictionary(Of String, String) From {
{"username", "user@example.com"},
{"password", "securePassword123"},
{"rememberMe", "true"},
{"csrf_token", "abc123"} ' Include any hidden fields
}
}
Dim renderer As New ChromePdfRenderer With {
.LoginCredentials = formLogin,
.RenderingOptions = New ChromePdfRenderOptions With {
.RenderDelay = 3000, ' Allow time for login redirect
.EnableJavaScript = True
}
}
' The actual page you want to convert (after login)
Dim pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard")
pdf.SaveAs("dashboard.pdf")
我需要擷取哪些表單資料?
若要透過 HTML 表單成功驗證,請擷取所有表單輸入內容:
// Use this helper method to extract form fields
public Dictionary<string, string> ExtractFormFields(string loginPageHtml)
{
var formData = new Dictionary<string, string>();
var doc = new HtmlDocument();
doc.LoadHtml(loginPageHtml);
// Find all input fields
var inputs = doc.DocumentNode.SelectNodes("//input");
if (inputs != null)
{
foreach (var input in inputs)
{
string name = input.GetAttributeValue("name", "");
string value = input.GetAttributeValue("value", "");
string type = input.GetAttributeValue("type", "text");
if (!string.IsNullOrEmpty(name))
{
// Handle different input types
switch (type.ToLower())
{
case "checkbox":
if (input.Attributes["checked"] != null)
formData[name] = "on";
break;
case "radio":
if (input.Attributes["checked"] != null)
formData[name] = value;
break;
default:
formData[name] = value;
break;
}
}
}
}
// Don't forget select elements
var selects = doc.DocumentNode.SelectNodes("//select");
if (selects != null)
{
foreach (var select in selects)
{
string name = select.GetAttributeValue("name", "");
var selected = select.SelectSingleNode(".//option[@selected]");
if (selected != null && !string.IsNullOrEmpty(name))
{
formData[name] = selected.GetAttributeValue("value", "");
}
}
}
return formData;
}
// Use this helper method to extract form fields
public Dictionary<string, string> ExtractFormFields(string loginPageHtml)
{
var formData = new Dictionary<string, string>();
var doc = new HtmlDocument();
doc.LoadHtml(loginPageHtml);
// Find all input fields
var inputs = doc.DocumentNode.SelectNodes("//input");
if (inputs != null)
{
foreach (var input in inputs)
{
string name = input.GetAttributeValue("name", "");
string value = input.GetAttributeValue("value", "");
string type = input.GetAttributeValue("type", "text");
if (!string.IsNullOrEmpty(name))
{
// Handle different input types
switch (type.ToLower())
{
case "checkbox":
if (input.Attributes["checked"] != null)
formData[name] = "on";
break;
case "radio":
if (input.Attributes["checked"] != null)
formData[name] = value;
break;
default:
formData[name] = value;
break;
}
}
}
}
// Don't forget select elements
var selects = doc.DocumentNode.SelectNodes("//select");
if (selects != null)
{
foreach (var select in selects)
{
string name = select.GetAttributeValue("name", "");
var selected = select.SelectSingleNode(".//option[@selected]");
if (selected != null && !string.IsNullOrEmpty(name))
{
formData[name] = selected.GetAttributeValue("value", "");
}
}
}
return formData;
}
Imports HtmlAgilityPack
Public Function ExtractFormFields(loginPageHtml As String) As Dictionary(Of String, String)
Dim formData As New Dictionary(Of String, String)()
Dim doc As New HtmlDocument()
doc.LoadHtml(loginPageHtml)
' Find all input fields
Dim inputs = doc.DocumentNode.SelectNodes("//input")
If inputs IsNot Nothing Then
For Each input In inputs
Dim name As String = input.GetAttributeValue("name", "")
Dim value As String = input.GetAttributeValue("value", "")
Dim type As String = input.GetAttributeValue("type", "text")
If Not String.IsNullOrEmpty(name) Then
' Handle different input types
Select Case type.ToLower()
Case "checkbox"
If input.Attributes("checked") IsNot Nothing Then
formData(name) = "on"
End If
Case "radio"
If input.Attributes("checked") IsNot Nothing Then
formData(name) = value
End If
Case Else
formData(name) = value
End Select
End If
Next
End If
' Don't forget select elements
Dim selects = doc.DocumentNode.SelectNodes("//select")
If selects IsNot Nothing Then
For Each selectNode In selects
Dim name As String = selectNode.GetAttributeValue("name", "")
Dim selected = selectNode.SelectSingleNode(".//option[@selected]")
If selected IsNot Nothing AndAlso Not String.IsNullOrEmpty(name) Then
formData(name) = selected.GetAttributeValue("value", "")
End If
Next
End If
Return formData
End Function
如何找到正確的表單提交網址?
表單的 action URL 對於成功驗證至關重要:
public string ExtractFormAction(string loginPageUrl, string loginPageHtml)
{
var doc = new HtmlDocument();
doc.LoadHtml(loginPageHtml);
// Find the login form
var form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]");
if (form == null)
{
// Try finding any form with password field
form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]");
}
if (form != null)
{
string action = form.GetAttributeValue("action", "");
// Resolve relative URLs
if (!string.IsNullOrEmpty(action))
{
var baseUri = new Uri(loginPageUrl);
var actionUri = new Uri(baseUri, action);
return actionUri.ToString();
}
}
// Default to the login page URL if no action found
return loginPageUrl;
}
public string ExtractFormAction(string loginPageUrl, string loginPageHtml)
{
var doc = new HtmlDocument();
doc.LoadHtml(loginPageHtml);
// Find the login form
var form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]");
if (form == null)
{
// Try finding any form with password field
form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]");
}
if (form != null)
{
string action = form.GetAttributeValue("action", "");
// Resolve relative URLs
if (!string.IsNullOrEmpty(action))
{
var baseUri = new Uri(loginPageUrl);
var actionUri = new Uri(baseUri, action);
return actionUri.ToString();
}
}
// Default to the login page URL if no action found
return loginPageUrl;
}
Imports System
Public Function ExtractFormAction(loginPageUrl As String, loginPageHtml As String) As String
Dim doc As New HtmlDocument()
doc.LoadHtml(loginPageHtml)
' Find the login form
Dim form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]")
If form Is Nothing Then
' Try finding any form with password field
form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]")
End If
If form IsNot Nothing Then
Dim action As String = form.GetAttributeValue("action", "")
' Resolve relative URLs
If Not String.IsNullOrEmpty(action) Then
Dim baseUri As New Uri(loginPageUrl)
Dim actionUri As New Uri(baseUri, action)
Return actionUri.ToString()
End If
End If
' Default to the login page URL if no action found
Return loginPageUrl
End Function
基於表單的驗證有哪些常見問題?
- CSRF 令牌:許多表單包含會過期的防偽造令牌
- JavaScript 驗證:某些表單需要執行 JavaScript
- 多步驟驗證:需分頁填寫的表單
- CAPTCHA 防護:人機驗證挑戰
- 會話超時:快速過期的登入會話
ViewBag
TempData
Html
如需完整的 HTML 轉 PDF 轉換指南(包含複雜的驗證情境),請參閱 HTML 轉 PDF 教學指南。
如何處理 MVC 驗證?
以下解決方案可透過程式化方式將 .NET MVC 檢視渲染為字串,在忠實呈現檢視的同時,避開 MVC 登入機制。 此方法在 MVC Core 或 MVC Framework 中將 CSHTML 轉換為 PDF 時效果良好。
// Converts an MVC partial view to a string
public static string RenderPartialViewToString(this Controller controller, string viewPath, object model = null)
{
try
{
// Set the model
var context = controller.Co/ntrollerContext;
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
// Find the partial view
var viewResult = ViewEngines.Engines.FindPartialView(context, viewPath);
if (viewResult.View == null)
{
throw new Exception($"Partial view {viewPath} could not be found.");
}
// Create a view context
var viewContext = new ViewContext(context, viewResult.View, context.Co/ntroller.ViewData, context.Co/ntroller.TempData, sw);
// Render the view
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(context, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
catch (Exception ex)
{
// Return error message if there is an exception
return ex.Message;
}
}
// Usage in an MVC Controller
public ActionResult GeneratePdf()
{
// Render authenticated view to string
var model = new InvoiceViewModel { /* populate model */ };
string html = this.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model);
// Convert to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Return PDF file
return File(pdf.BinaryData, "application/pdf", "invoice.pdf");
}
// Converts an MVC partial view to a string
public static string RenderPartialViewToString(this Controller controller, string viewPath, object model = null)
{
try
{
// Set the model
var context = controller.Co/ntrollerContext;
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
// Find the partial view
var viewResult = ViewEngines.Engines.FindPartialView(context, viewPath);
if (viewResult.View == null)
{
throw new Exception($"Partial view {viewPath} could not be found.");
}
// Create a view context
var viewContext = new ViewContext(context, viewResult.View, context.Co/ntroller.ViewData, context.Co/ntroller.TempData, sw);
// Render the view
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(context, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
catch (Exception ex)
{
// Return error message if there is an exception
return ex.Message;
}
}
// Usage in an MVC Controller
public ActionResult GeneratePdf()
{
// Render authenticated view to string
var model = new InvoiceViewModel { /* populate model */ };
string html = this.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model);
// Convert to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Return PDF file
return File(pdf.BinaryData, "application/pdf", "invoice.pdf");
}
Imports System
Imports System.IO
Imports System.Web.Mvc
Imports IronPdf
' Converts an MVC partial view to a string
Public Module ControllerExtensions
<System.Runtime.CompilerServices.Extension>
Public Function RenderPartialViewToString(controller As Controller, viewPath As String, Optional model As Object = Nothing) As String
Try
' Set the model
Dim context = controller.ControllerContext
controller.ViewData.Model = model
Using sw As New StringWriter()
' Find the partial view
Dim viewResult = ViewEngines.Engines.FindPartialView(context, viewPath)
If viewResult.View Is Nothing Then
Throw New Exception($"Partial view {viewPath} could not be found.")
End If
' Create a view context
Dim viewContext As New ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw)
' Render the view
viewResult.View.Render(viewContext, sw)
viewResult.ViewEngine.ReleaseView(context, viewResult.View)
Return sw.GetStringBuilder().ToString()
End Using
Catch ex As Exception
' Return error message if there is an exception
Return ex.Message
End Try
End Function
End Module
' Usage in an MVC Controller
Public Class InvoiceController
Inherits Controller
Public Function GeneratePdf() As ActionResult
' Render authenticated view to string
Dim model As New InvoiceViewModel() ' populate model
Dim html As String = Me.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model)
' Convert to PDF
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
' Return PDF file
Return File(pdf.BinaryData, "application/pdf", "invoice.pdf")
End Function
End Class
為何要將檢視渲染為字串,而非直接轉換?
將 MVC 檢視渲染為字串具有以下幾項關鍵優勢:
- 驗證上下文:視圖在已驗證使用者的上下文中渲染
- 完整的 MVC 處理流程:所有 MVC 功能皆可正常運作,包括
UrlHelper及ViewBag輔助函式 - 版面配置支援:母版頁與版面配置能正確呈現
- 模型綁定:複雜的檢視模型能無縫運作
- 動作篩選器:安全性與記錄篩選器會正常執行
此 MVC 解決方案有哪些優勢?
MVC 字串渲染方法提供:
- 安全性:無需公開內部 URL 或繞過驗證機制
- 效能:避免產生額外的 HTTP 請求
- 一致性:輸出內容須與使用者在瀏覽器中所見完全一致
- 靈活性:在 PDF 轉換前修改 HTML
- 測試:輕鬆進行 HTML 生成單元測試
如何將模型傳遞至渲染視圖?
以下是一個包含複雜模型的完整範例:
public class InvoiceController : Controller
{
private readonly IInvoiceService _invoiceService;
public async Task<ActionResult> DownloadInvoicePdf(int invoiceId)
{
// Load data within authenticated context
var invoice = await _invoiceService.GetInvoiceAsync(invoiceId);
if (invoice == null || invoice.UserId != User.Identity.GetUserId())
{
return HttpNotFound();
}
// Create view model
var viewModel = new InvoiceDetailsViewModel
{
Invoice = invoice,
Company = await _invoiceService.GetCompanyDetailsAsync(),
LineItems = await _invoiceService.GetLineItemsAsync(invoiceId),
TaxDetails = await _invoiceService.GetTaxDetailsAsync(invoiceId)
};
// Render to HTML string
string html = this.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel);
// Add custom styling for PDF
html = $@"
<html>
<head>
<style>
body {{font-family: Arial, sans-serif;}}
.invoice-header {{background-color: #f0f0f0; padding: 20px;}}
.line-items {{width: 100%; border-collapse: collapse;}}
.line-items th, .line-items td {{border: 1px solid #ddd; padding: 8px;}}
</style>
</head>
<body>
{html}
</body>
</html>";
// Convert to PDF with options
var renderer = new ChromePdfRenderer
{
RenderingOptions = new ChromePdfRenderOptions
{
MarginTop = 20,
MarginBottom = 20,
MarginLeft = 10,
MarginRight = 10,
PrintHtmlBackgrounds = true
}
};
var pdf = renderer.RenderHtmlAsPdf(html);
// Add metadata
pdf.MetaData.Author = "Invoice System";
pdf.MetaData.Title = $"Invoice #{invoice.Number}";
pdf.MetaData.CreationDate = DateTime.Now;
return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf");
}
}
public class InvoiceController : Controller
{
private readonly IInvoiceService _invoiceService;
public async Task<ActionResult> DownloadInvoicePdf(int invoiceId)
{
// Load data within authenticated context
var invoice = await _invoiceService.GetInvoiceAsync(invoiceId);
if (invoice == null || invoice.UserId != User.Identity.GetUserId())
{
return HttpNotFound();
}
// Create view model
var viewModel = new InvoiceDetailsViewModel
{
Invoice = invoice,
Company = await _invoiceService.GetCompanyDetailsAsync(),
LineItems = await _invoiceService.GetLineItemsAsync(invoiceId),
TaxDetails = await _invoiceService.GetTaxDetailsAsync(invoiceId)
};
// Render to HTML string
string html = this.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel);
// Add custom styling for PDF
html = $@"
<html>
<head>
<style>
body {{font-family: Arial, sans-serif;}}
.invoice-header {{background-color: #f0f0f0; padding: 20px;}}
.line-items {{width: 100%; border-collapse: collapse;}}
.line-items th, .line-items td {{border: 1px solid #ddd; padding: 8px;}}
</style>
</head>
<body>
{html}
</body>
</html>";
// Convert to PDF with options
var renderer = new ChromePdfRenderer
{
RenderingOptions = new ChromePdfRenderOptions
{
MarginTop = 20,
MarginBottom = 20,
MarginLeft = 10,
MarginRight = 10,
PrintHtmlBackgrounds = true
}
};
var pdf = renderer.RenderHtmlAsPdf(html);
// Add metadata
pdf.MetaData.Author = "Invoice System";
pdf.MetaData.Title = $"Invoice #{invoice.Number}";
pdf.MetaData.CreationDate = DateTime.Now;
return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf");
}
}
Imports System.Threading.Tasks
Imports System.Web.Mvc
Public Class InvoiceController
Inherits Controller
Private ReadOnly _invoiceService As IInvoiceService
Public Async Function DownloadInvoicePdf(invoiceId As Integer) As Task(Of ActionResult)
' Load data within authenticated context
Dim invoice = Await _invoiceService.GetInvoiceAsync(invoiceId)
If invoice Is Nothing OrElse invoice.UserId <> User.Identity.GetUserId() Then
Return HttpNotFound()
End If
' Create view model
Dim viewModel As New InvoiceDetailsViewModel With {
.Invoice = invoice,
.Company = Await _invoiceService.GetCompanyDetailsAsync(),
.LineItems = Await _invoiceService.GetLineItemsAsync(invoiceId),
.TaxDetails = Await _invoiceService.GetTaxDetailsAsync(invoiceId)
}
' Render to HTML string
Dim html As String = Me.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel)
' Add custom styling for PDF
html = $"
<html>
<head>
<style>
body {{font-family: Arial, sans-serif;}}
.invoice-header {{background-color: #f0f0f0; padding: 20px;}}
.line-items {{width: 100%; border-collapse: collapse;}}
.line-items th, .line-items td {{border: 1px solid #ddd; padding: 8px;}}
</style>
</head>
<body>
{html}
</body>
</html>"
' Convert to PDF with options
Dim renderer As New ChromePdfRenderer With {
.RenderingOptions = New ChromePdfRenderOptions With {
.MarginTop = 20,
.MarginBottom = 20,
.MarginLeft = 10,
.MarginRight = 10,
.PrintHtmlBackgrounds = True
}
}
Dim pdf = renderer.RenderHtmlAsPdf(html)
' Add metadata
pdf.MetaData.Author = "Invoice System"
pdf.MetaData.Title = $"Invoice #{invoice.Number}"
pdf.MetaData.CreationDate = DateTime.Now
Return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf")
End Function
End Class
在實施任何驗證解決方案之前,請確保您已正確安裝 IronPDF 並設定好授權金鑰。
準備好探索更多可能性了嗎? 請造訪我們的教學頁面:轉換 PDF。
RenderDelay
常見問題
當內容位於登入表單後方時,該如何將 HTML 轉換為 PDF?
IronPDF 提供多種方法,可在登入驗證環境下將 HTML 轉換為 PDF。您可以使用 ChromeHttpLoginCredentials API 進行 TLS 網路驗證,或透過 System.Net.WebClient 或 HttpClient 搭配適當的驗證標頭下載 HTML 內容,再使用 IronPDF 將其轉換為 PDF。
什麼是 ChromeHttpLoginCredentials,該如何使用它?
ChromeHttpLoginCredentials 是 IronPDF 用於處理網路驗證的 API。您可以透過在 ChromePdfRenderer 上設定 LoginCredentials 屬性並填入您的使用者名稱和密碼來使用此功能,讓 IronPDF 在將受密碼保護的 URL 渲染為 PDF 時自動進行驗證。
我能否處理基於 HTML 表單的登入功能以進行 PDF 轉換?
是的,IronPDF 支援基於 HTML 表單的登入功能。建議的做法是使用 System.Net.WebClient 或 HttpClient 來處理登入流程,下載經過驗證的 HTML 內容,然後使用 IronPDF 的 RenderHtmlAsPdf 方法將下載的 HTML 轉換為 PDF。
如何從已驗證的網頁下載 HTML 資源(例如圖片和樣式表)?
您可以使用 HtmlAgilityPack 解析下載的 HTML 並提取圖片和樣式表等資源網址。接著使用 System.Net.WebClient 透過相同的驗證標頭下載每個資源,最後使用 IronPDF 將完整的 HTML 套件轉換為 PDF。
處理驗證憑證或標頭的最佳做法是什麼?
當使用 IronPDF 並搭配驗證憑證時,請透過 HttpClient 或 WebClient 並附上驗證標頭(例如 Bearer 憑證)來下載 HTML 內容。將驗證過的 HTML 內容載入記憶體或儲存至磁碟後,即可使用 IronPDF 的 ChromePdfRenderer 將其轉換為 PDF。
是否有 MVC 登入驗證的替代方案?
是的,IronPDF 針對 MVC 登入驗證情境提供了解決方案。建議的做法是:先使用標準的 .NET HTTP 客戶端進行驗證並下載 HTML 內容,然後將已驗證的 HTML 直接傳遞給 IronPDF 的渲染引擎,而非讓 IronPDF 直接處理驗證程序。

