在ASP.NET Core中将html导出为pdf

时间:2016-09-07 08:19:01

标签: asp.net-core pdf-generation

我想将一段html导出为pdf文件,但我没有任何兼容的nuget包。

当我尝试安装任何人时:" X与netcoreapp1.0不兼容(.NETCoreApp,Version = v1.0)。"

有没有人知道使用asp.net核心导出到pdf的任何方法?

7 个答案:

答案 0 :(得分:22)

如果您在.net core 2.0中,也可以使用jsreport .net sdk,而无需更复杂的节点服务。这包括将您现有的剃刀视图转换为pdf的过滤器。来自docs

1。 安装核心jsreport.Binaryjsreport.Localjsreport.AspNetCore

2。 在您[HttpGet("{id}")] public ApiResponse GetApi([FromRoute] int id, int pageIndex = 0, int pageSize = int.MaxValue) { if (id == 0) return new ApiResponse(StatusCodes.Status400BadRequest, error: "id must be provided"); var result = someMethod(id, pageIndex, pageSize); return new ApiResponse(StatusCodes.Status200OK, result, "success"); } 中将其配置为以下

public class ApiResponse
{

    public ApiResponse(int statusCode, object result = null, string success = "", string error = "")
    {
        Error = error;
        Success = success;
        StatusCode = statusCode;
        Result = result;      
    }

    public string Error { get; set; }
    public string Success { get; set; }
    public int StatusCode { get; set; }
    public Object Result { get; set; }
}

3。 然后,您需要将Startup.cs属性添加到特定操作,并指定要使用的转换。在这种情况下,html到pdf转换。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();              
    services.AddJsReport(new LocalReporting()
        .UseBinary(JsReportBinary.GetBinary())
        .AsUtility()
        .Create());
}

您可以在MiddlewareFilter上获得大量页眉,页脚或页面布局的其他选项。请注意,您也可以通过html生成excel文件。请参阅documentation

中的详细信息

PS:我是jsreport的作者。

答案 1 :(得分:20)

从我原来的答案复制Export to pdf using ASP.NET 5

从.NET Core中的html生成pdf(没有任何.NET框架依赖项)的一种方法是在.NET Core应用程序中使用Node.js。 以下示例说明如何在干净的ASP.NET Core Web Application项目(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的更多说明,请查看here

现在在调用此Node.js脚本的Mvc控制器中创建一个操作

[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')pdf.js的base64编码字符串在Node.js和.NET Core之间交换数据并使用 在操作中var result = await nodeServices.InvokeAsync<byte[]>("./pdf");然后解码base64编码的字符串。

<小时/> 的替代

大多数pdf生成器解决方案仍然依赖于.NET 4.5 / 4.6框架。但是,如果您不喜欢使用Node.js,似乎有一些付费替代方案可用:

  • NReco.PdfGenerator.LT
  • EVO HTML to PDF Converter Client for .NET Core
  • 用于.NET Core的Winnovative HTML to PDF Converter Client

我没有尝试过任何这些。

我希望我们很快会在这方面看到一些开源进展。

答案 2 :(得分:4)

您可以查看DinkToPdf库。它是.NET Core的wkhtmltopdf库的包装器。

同步转换器

在多线程应用程序和Web服务器中使用此转换器。转换任务将保存到阻塞集合并在单个线程上执行。

var 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 }
        }
    }
};

答案 3 :(得分:3)

我遇到了同样的问题!我想从HTML字符串生成PDF文件。然后我遇到了PhantomJs这是一个命令行实用程序,用于将html文件转换为pdf。我在C#for .NET CORE上用它编写了一个跨平台的包装器,它在Linux上运行得很好!虽然截至目前它只适用于64位Linux,因为这是目前.NET Core支持的唯一平台。 该项目可以找到here

PhantomJs.NetCore.PdfGenerator gen = new PhantomJs.NetCore.PdfGenerator("/path/to/pantomjsfolder");
string outputFilePath = gen.GeneratePdf("<h1>Hello</h1>","/folder/to/write/file/in");

答案 4 :(得分:2)

这是一个适用于ASP.NET Core 2.0的解决方案,允许从<{1}} 生成动态PDF文件,直接将它们发送给用户和/或在发送之前保存它们。

要补充Jan Blaha answer there,为了获得更大的灵活性,您可能需要使用以下代码:

cshtml

使用类将cshtml文件呈现为字符串,您可以使用following service(可以作为范围服务注入):

/// 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);
}

然后总结一下,在您的控制器中,假设剃刀cshtml视图模板为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; } } ,您可以使用以下内容。

注意:发布时可能需要复制/Views/Home/PDFTemplate.cshtml文件(即使编译了视图)。

cshtml

答案 5 :(得分:0)

另一个好的解决方案是OpenHtmlToPdf

答案 6 :(得分:-2)

以防万一有人使用.NET CORE> 2.0(仅WINDOWS)

这是一个免费且易于使用的库: https://code.msdn.microsoft.com/Convert-from-HTML-to-PDF-d63582e8

public IActionResult OnPost() 
{ 
    // instantiate a html to pdf converter object 
    HtmlToPdf converter = new HtmlToPdf(); 

    // create a new pdf document converting an url 
    PdfDocument doc = converter.ConvertUrl(TxtUrl); 

    // save pdf document 
    byte[] pdf = doc.Save(); 

    // close pdf document 
    doc.Close(); 

    // return resulted pdf document 
    FileResult fileResult = new FileContentResult(pdf, "application/pdf"); 
    fileResult.FileDownloadName = "Document.pdf"; 
    return fileResult; 
}