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.Pdf

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章