我想将一段html导出为pdf文件,但我找不到任何兼容的NuGet包。
当我尝试安装任何一个时:"X与netcoreapp1.0(.NETCoreApp,Version=v1.0)不兼容。"
有人知道使用asp.net core导出pdf的方法吗?
我想将一段html导出为pdf文件,但我找不到任何兼容的NuGet包。
当我尝试安装任何一个时:"X与netcoreapp1.0(.NETCoreApp,Version=v1.0)不兼容。"
有人知道使用asp.net core导出pdf的方法吗?
如果你在 .net core 2.0 中,也不需要更复杂的 node 服务,可以使用 jsreport .net sdk。其中包括将现有的 razor 视图转换为 pdf 的筛选器等功能。从文档中了解更多信息:
1. 安装Nuget包jsreport.Binary,jsreport.Local和jsreport.AspNetCore
2.
在你的Startup.cs
中进行以下配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddJsReport(new LocalReporting()
.UseBinary(JsReportBinary.GetBinary())
.AsUtility()
.Create());
}
3. 然后您需要将MiddlewareFilter
属性添加到特定的操作中,并指定您想要使用哪种转换。在这种情况下,是从HTML转换为PDF。
[MiddlewareFilter(typeof(JsReportPipeline))]
public IActionResult Invoice()
{
HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf);
return View();
}
您可以在JsReportFeature()
上找到许多其他标题、页脚或页面布局选项。请注意,您也可以通过HTML生成Excel文件。有关更多信息,请参阅文档。
PS:我是jsreport的作者。
以下内容是我原来的回答,转载自这里Export to pdf using ASP.NET 5:
.NET Core中一种生成PDF文档的方法(不依赖于任何.NET框架)是在.NET Core应用程序中使用Node.js。 下面的示例展示了如何在干净的ASP.NET Core Web应用程序项目(Web API模板)中实现HTML到PDF转换器。
安装NuGet包Microsoft.AspNetCore.NodeServices
在Startup.cs文件中添加services.AddNodeServices()
这一行代码
public void ConfigureServices(IServiceCollection services)
{
// ... all your existing configuration is here ...
// Enable Node Services
services.AddNodeServices();
}
现在安装所需的 Node.js 包:
从命令行切换到 .NET Core 项目的根目录,并运行以下命令。
npm init
并按照说明创建package.json文件
npm install jsreport-core --save
npm install jsreport-jsrender --save
npm install jsreport-phantom-pdf --save
在项目根目录下创建一个名为pdf.js
的文件。module.exports = function (callback) {
var jsreport = require('jsreport-core')();
jsreport.init().then(function () {
return jsreport.render({
template: {
content: '<h1>Hello {{:foo}}</h1>',
engine: 'jsrender',
recipe: 'phantom-pdf'
},
data: {
foo: "world"
}
}).then(function (resp) {
callback(/* error */ null, resp.content.toJSON().data);
});
}).catch(function (e) {
callback(/* error */ e, null);
})
};
点击这里以获取有关jsreport-core
的更多解释。
现在在Mvc控制器中创建一个调用此Node.js脚本的操作。
[HttpGet]
public async Task<IActionResult> MyAction([FromServices] INodeServices nodeServices)
{
var result = await nodeServices.InvokeAsync<byte[]>("./pdf");
HttpContext.Response.ContentType = "application/pdf";
string filename = @"report.pdf";
HttpContext.Response.Headers.Add("x-filename", filename);
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
HttpContext.Response.Body.Write(result, 0, result.Length);
return new ContentResult();
}
当然,您可以对从nodeServices返回的byte []
执行任何操作,在本示例中,我只是从控制器动作中输出它,以便在浏览器中查看。
您还可以通过使用resp.content.toString('base64')
将数据在Node.js和.NET Core之间交换为base64编码字符串,使用pdf.js
,并在操作中使用var result = await nodeServices.InvokeAsync< byte [] >(“./ pdf”);
,然后解码base64编码的字符串。
大多数pdf生成器解决方案仍依赖于.NET 4.5/4.6框架。但是,如果您不想使用Node.js,则似乎有一些付费替代方案可用:
虽然我没有尝试过任何一个。
我希望我们能很快在这个领域看到一些开源进展。
module.exports = function (callback, html) {
,并在模板中设置 content: html
,然后在您的操作中执行 var result = await nodeServices.InvokeAsync<byte[]>("./pdf", razorRenderedHtmlString);
。但是,如果您未提前内联CSS,可能会遇到困难。 - Sjolundvar converter = new SynchronizedConverter(new PdfTools());
定义要转换的文档
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4Plus,
},
Objects = {
new ObjectSettings() {
PagesCount = true,
HtmlContent = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In consectetur mauris eget ultrices iaculis. Ut odio viverra, molestie lectus nec, venenatis turpis.",
WebSettings = { DefaultEncoding = "utf-8" },
HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true, Spacing = 2.812 }
}
}
};
PhantomJs.NetCore.PdfGenerator gen = new PhantomJs.NetCore.PdfGenerator("/path/to/pantomjsfolder");
string outputFilePath = gen.GeneratePdf("<h1>Hello</h1>","/folder/to/write/file/in");
在服务器端完成
如果HTML在服务器上,则可以尝试使用以下软件包。
软件包Puppeteer Sharp,请查看教程
软件包Playwright Dotnet,请查看教程
在客户端完成(如果跨平台方案不起作用,这也会有所帮助)
最后一种选择是使用浏览器打印PDF,请查看教程
其他要点
不要随意选择互联网上的软件包,因为可能存在安全问题、隐私等问题,而是检查是否有像Microsoft、Google等大公司提供的免费开源软件包,一旦选择了软件包,如有需要,请与安全团队进行验证,或者检查评论和下载量。还要检查其许可页面,看看是免费还是付费。
如果Linux
容器有问题,请在容器外部创建一个API来将HTML
转换为PDF
,然后尝试在容器应用程序中调用您的新API,或者尝试gotenberg,它们有容器和SDK版本。
还根据需求和性能权衡,决定在服务器端还是客户端完成。
cshtml
生成动态PDF文件,直接发送给用户和/或在发送之前保存。为了增加灵活性,可以使用以下代码来补充Jan Blaha的答案。/// Generate a PDF from a html string
async Task<(string ContentType, MemoryStream GeneratedFileStream)> GeneratePDFAsync(string htmlContent)
{
IJsReportFeature feature = new JsReportFeature(HttpContext);
feature.Recipe(Recipe.PhantomPdf);
if (!feature.Enabled) return (null, null);
feature.RenderRequest.Template.Content = htmlContent;
var report = await _RenderService.RenderAsync(feature.RenderRequest);
var contentType = report.Meta.ContentType;
MemoryStream ms = new MemoryStream();
report.Content.CopyTo(ms);
return (contentType, ms);
}
public class ViewToStringRendererService: ViewExecutor
{
private ITempDataProvider _tempDataProvider;
private IServiceProvider _serviceProvider;
public ViewToStringRendererService(
IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource,
IModelMetadataProvider modelMetadataProvider,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
: base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource, modelMetadataProvider)
{
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
var context = GetActionContext();
if (context == null) throw new ArgumentNullException(nameof(context));
var result = new ViewResult()
{
ViewData = new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
TempData = new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
ViewName = viewName,
};
var viewEngineResult = FindView(context, result);
viewEngineResult.EnsureSuccessful(originalLocations: null);
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
context,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return output.ToString();
}
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
/// <summary>
/// Attempts to find the <see cref="IView"/> associated with <paramref name="viewResult"/>.
/// </summary>
/// <param name="actionContext">The <see cref="ActionContext"/> associated with the current request.</param>
/// <param name="viewResult">The <see cref="ViewResult"/>.</param>
/// <returns>A <see cref="ViewEngineResult"/>.</returns>
ViewEngineResult FindView(ActionContext actionContext, ViewResult viewResult)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
if (viewResult == null)
{
throw new ArgumentNullException(nameof(viewResult));
}
var viewEngine = viewResult.ViewEngine ?? ViewEngine;
var viewName = viewResult.ViewName ?? GetActionName(actionContext);
var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
var originalResult = result;
if (!result.Success)
{
result = viewEngine.FindView(actionContext, viewName, isMainPage: true);
}
if (!result.Success)
{
if (originalResult.SearchedLocations.Any())
{
if (result.SearchedLocations.Any())
{
// Return a new ViewEngineResult listing all searched locations.
var locations = new List<string>(originalResult.SearchedLocations);
locations.AddRange(result.SearchedLocations);
result = ViewEngineResult.NotFound(viewName, locations);
}
else
{
// GetView() searched locations but FindView() did not. Use first ViewEngineResult.
result = originalResult;
}
}
}
if(!result.Success)
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", viewName));
return result;
}
private const string ActionNameKey = "action";
private static string GetActionName(ActionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
{
return null;
}
var actionDescriptor = context.ActionDescriptor;
string normalizedValue = null;
if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
!string.IsNullOrEmpty(value))
{
normalizedValue = value;
}
var stringRouteValue = routeValue?.ToString();
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
{
return normalizedValue;
}
return stringRouteValue;
}
}
最后,在您的控制器中,假设razor cshtml视图模板为/Views/Home/PDFTemplate.cshtml
,您可以使用以下内容。
注意:即使视图已编译,cshtml
文件在发布时可能仍需要复制。
var htmlContent = await _ViewToStringRendererService.RenderViewToStringAsync("Home/PDFTemplate", viewModel);
(var contentType, var generatedFile) = await GeneratePDFAsync(htmlContent);
Response.Headers["Content-Disposition"] = $"attachment; filename=\"{System.Net.WebUtility.UrlEncode(fileName)}\"";
// You may save your file here
using (var fileStream = new FileStream(Path.Combine(folder, fileName), FileMode.Create))
{
await generatedFile.CopyToAsync(fileStream);
}
// You may need this for re-use of the stream
generatedFile.Seek(0, SeekOrigin.Begin);
return File(generatedFile.ToArray(), "application/pdf", fileName);
_RenderService
? - rjps12_RenderService
是下面的 ViewToStringRendererService
。在启动时,它应该被注入为作用域或瞬态。 - JeanHtmlToPdf htmlToPdf = new HtmlToPdf();
htmlToPdf.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
// put css in pdf
htmlToPdf.Options.MarginLeft = 15;
htmlToPdf.Options.MarginRight = 15;
---------------------------
string url = "<html><head></head><body>Hello World</body></html>"
PdfDocument pdfDocument = htmlToPdf.ConvertHtmlString(url);
byte[] pdf = pdfDocument.Save();
//convert to memory stream
Stream stream = new MemoryStream(pdf);
pdfDocument.Close();
//if want to transfer stream to file
File(stream, "application/pdf", Guid.NewGuid().ToString() + ".pdf");
如果要将HTML导出为PDF,您可以使用iTextSharp库,甚至可以将HTML放在部分视图中,并将该视图导出为PDF。最近,我在一个需要导出PDF的项目中尝试了这种方法,我参考了如何在Asp.Net Core中将视图导出为PDF。所以您可以尝试一下。