我想将一段html导出为pdf文件,但我没有任何兼容的nuget包。
当我尝试安装任何人时:" X与netcoreapp1.0不兼容(.NETCoreApp,Version = v1.0)。"
有没有人知道使用asp.net核心导出到pdf的任何方法?
答案 0 :(得分:22)
如果您在.net core 2.0中,也可以使用jsreport .net sdk,而无需更复杂的节点服务。这包括将您现有的剃刀视图转换为pdf的过滤器。来自docs:
1。 安装核心jsreport.Binary,jsreport.Local和jsreport.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,似乎有一些付费替代方案可用:
我没有尝试过任何这些。
我希望我们很快会在这方面看到一些开源进展。
答案 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;
}