Asp.net MVC Razor檢視模版動態渲染PDF,Razor模版生成靜態Html
1.前言
上一篇文章我開源了輪子,Asp.net Core 3.1 Razor檢視模版動態渲染PDF,然後,很多小夥伴有很多私信找我了。那麼我下面就簡單的給大家說一下,關於小夥伴問的這些問題。
- 我專案的電子簽章部分程式碼可否開源?
答:我專案電子簽章也是使用第三方的電子簽章,電子簽章並不是自己實現的,專案裡面的電子簽章程式碼無非也是對接第三方的介面。這部分程式碼開源出去也沒有什麼意義。我們是使用數字廣東的方案,如果您也是使用該數字簽章,可以私下溝通我看看能不能幫助您。
- 電子簽章實現難不難,怎麼實現自己的電子簽章?
答:電子簽章要實現,估計不是太難,按照我的理解,當然我沒有具體深入研究(如果這裡我有妄自菲薄的意思,請諒解,畢竟我能力有限,只是按照我的理解來分析),我個人覺得電子簽章應該就是利用數字證書給PDF簽名,然後加密保護文件,然後校驗文件的真偽,就要考慮怎麼驗證這個文件沒有被刪改,是當初我們簽章的這個文件,而且這個簽名不能被偽造。個人覺得不是很複雜,但是,電子簽章的法律有效性卻不是這麼簡單的。按照國家法律規定,利用的簽名平臺應該有資質的,國家認可的第三方簽章平臺,也就是說,私人自己製作的簽章,打起官司來,很難得到法律支援。
- 專案為什麼CSS樣式不起效?
答:你是否使用了外鏈的CSS樣式,因為渲染Razor檢視是在後臺渲染,無法找到外鏈的檔案路徑,就使用不了外鏈的CSS樣式,內嵌和內聯CSS樣式都沒啥問題的。
- 用word或者excel模版他不香嗎?為什麼要搞個這個東西?
答:無非是多一個方案,具體你使用什麼完全是你自己說了算,你覺得其他方案好就用,你覺得本方案能幫助你就用,不好就不用,我又不收你半毛線,還是想說的是,你其他的方案,能有用CSS那麼容易做出來漂亮的表單效果嗎?
- 圖片支援嗎?
答:圖片要轉Base64編碼,不支援外連線圖片。
- 前端預覽PDF用什麼外掛?
答:我目前不用外掛,新一代瀏覽器都支援PDF直接預覽,直接就能渲染成PDF呈現,當然你也可以自己整合PDF.JS.我大概看了下,整合也很方便。我之所以不整合,是考慮到我的專案有可能使用IE低版本的情況,PDF.JS可能不支援。所以乾脆直接把PDF流推送給瀏覽器,瀏覽器要是能預覽,就直接呈現,不能預覽就下載。
- 專案支援net Framework嗎?為啥報錯?
答:這個問題問的有點多,所以本文後續就以這個再說一下本輪子在net45下的使用。還是那句話,有不對的,歡迎您指正,覺得對你有用的就用,無用的就直接忽視,我又不收你半毛線。
- 可以用本專案生成靜態Html嗎?容易被搜尋引擎抓取。
答:可以,後面演示
2.依賴專案
<PackageReference Include="TuesPechkin" Version="2.1.1" />
<PackageReference Include="TuesPechkin.Wkhtmltox.Win32" Version="0.12.2.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.3" />
<PackageReference Include="Nito.AsyncEx" Version="4.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<Reference Include="Nito.AsyncEx.Concurrent" Version="4.0.1" />
<Reference Include="Nito.AsyncEx.Enlightenment" Version="4.0.1" />
3.核心程式碼
TuesPechkin外掛,首先說一下這個TuesPechkin外掛,他其實是利用TuesPechkin.Wkhtmltox程序來轉換的。這個外掛使用還是要小心的,使用不當可能有執行緒安全問題,會使得當前工作程序掛起。在IIS下面使用也要注意使用32位的外掛。具體使用請看作者的說明:https://github.com/tuespetre/TuesPechkin/blob/develop/README.md
外掛初始化程式碼:
private static readonly IConverter PdfConverter = new ThreadSafeConverter(new RemotingToolset<PdfToolset>( new Win32EmbeddedDeployment( new TempFolderDeployment())));
切記IIS和多執行緒一定要靜態單例。使用
Win32EmbeddedDeployment
ThreadSafeConverter
這兩個類。其他的可能讓你程序掛起的成為可能。
還要用到遠端工具集的PDF工具集。
Razor 轉Html程式碼,主要有兩種方式:
第一種使用RazorEngine來轉換:這個主要是傳遞Razor模版進去,轉換。
protected string RunCompileRazorTemplate(object model,string razorTemplateStr) { if(string.IsNullOrWhiteSpace(razorTemplateStr)) throw new ArgumentException("Razor模版不能為空"); var htmlString= Engine.Razor.RunCompile(razorTemplateStr, razorTemplateStr.GetHashCode().ToString(), null, model); return htmlString; }
第二種使用ViewEngine。這個主要是自動查詢Asp.net MVC裡面的View下面的Razor,目前我們專案就是使用這個。
var viewName = context.RouteData.Values["action"].ToString(); var result = ViewEngines.Engines.FindView(context, viewName, null); IExportPdfByHtmlTemplate exportPdfByHtmlTemplate = new PdfByHtmlTemplateExporter (); #endif if (result.View == null) throw new ArgumentException($"名稱為:{viewName}的檢視不存在,請檢查!"); context.HttpContext.Response.ContentType = "application/pdf"; //context.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=test.pdf"); var html = ""; using (var stringWriter = new StringWriter()) { #if !NET45 var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = Value }; var viewContext = new ViewContext(context, result.View, viewDictionary, new TempDataDictionary(context.HttpContext, tempDataProvider), stringWriter, new HtmlHelperOptions()); await result.View.RenderAsync(viewContext); #else var viewDictionary = new ViewDataDictionary(new ModelStateDictionary()) { Model = Value }; var viewContext = new ViewContext(context, result.View, viewDictionary, context.Controller.TempData, stringWriter); result.View.Render(viewContext, stringWriter); result.ViewEngine.ReleaseView(context, result.View); #endif html = stringWriter.ToString(); }
推送PDF流給客戶端,預覽PDF主要程式碼
context.HttpContext.Response.ContentType = "application/pdf"; context.HttpContext.Response.AddHeader("Content-Length", buff.Length.ToString()); context.HttpContext.Response.AddHeader("Content-Disposition", "filename=電子簽章PDF-"+DateTime.Now.ToString()+".pdf"); context.HttpContext.Response.BinaryWrite(buff); context.HttpContext.Response.Flush(); context.HttpContext.Response.Close(); context.HttpContext.Response.End();
這裡要注意三個地方,不然一定會踩坑。
Content-Length要設定,不然谷歌瀏覽器可能無法下載預覽的PDF。
Content-Disposition不能要attachment,否則可能直接下載不是預覽。
ContentType 要設定"application/pdf"
Razor轉靜態Html
還有一部分人問我怎麼利用本外掛Razor模版動態生成靜態Html,這樣容易被百度爬蟲錄取。
其實這部分核心程式碼就是幾句程式碼,非常簡單。本專案直接用下面介面即可生成html字元轉,自行儲存就可以了。
public interface IHtmlByRazorTemplateExporter { Task<string> ExportHtmlByRazorTemplateAsync<T>(T data, string htmlTemplate) where T : class; string ExportHtmlByRazorTemplate<T>(T data, string htmlTemplate) where T : class; }
核心:
protected string RunCompileRazorTemplate(object model,string razorTemplateStr) { if(string.IsNullOrWhiteSpace(razorTemplateStr)) throw new ArgumentException("Razor模版不能為空"); var htmlString= Engine.Razor.RunCompile(razorTemplateStr, razorTemplateStr.GetHashCode().ToString(), null, model); return htmlString; }
4.使用方式
- 目前本專案已經打包成nuget,並上傳,使用可以直接專案右鍵->管理NuGet程式包,查詢,然後下載安裝。
- 也可以使用命令安裝。install-package JESAI.HtmlTemplate.Pdf.net45
- 或者直接fork本倉庫自己打包,並根據自己情況修改使用。
自定打包可以修改專案目標框架。專案右鍵->屬性->應用程式,目標框架,修改
如發現不能修改,可以,專案->右鍵->編輯專案檔案
然後編譯,就可以使用了。
具體使用
方式一:
方式二:
Razor檢視模版程式碼:
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <table border="1" style="width:800px;height:500px;"> <tr> <td>姓名</td> <td>@Model.Name</td> <td>性別</td> <td>@Model.Sex</td> </tr> <tr> <td>年齡</td> <td>@Model.Age</td> <td>班級</td> <td>@Model.Class</td> </tr> <tr> <td>住址</td> <td>@Model.Address</td> <td>電話</td> <td>@Model.Tel</td> </tr> <tr> <td clospan="2">住址</td> <td>@Model.Des</td> </tr> </table> </body> </html>
5.執行效果
6.專案程式碼
程式碼託管:https://gitee.com/Jesai/JESAI.HtmlTemplate