1. 程式人生 > >Asp.net MVC Razor檢視模版動態渲染PDF,Razor模版生成靜態Html

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="RazorEngine" Version="3.9.3" />
  <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