This example demonstrates how to sign an exported PDF document.
Add Signature Capabilities to the Document Viewer's UI
File: CustomPdfSignatureOptionsProviderAsync.cs
To pass a collection of signatures to the Web Document Viewer, implement the IPdfSignatureOptionsProviderAsync interface.
In this example, the CustomPdfSignatureOptionsProviderAsync
class implements the IPdfSignatureOptionsProviderAsync interface. The GetAvailableOptionsAsync method returns the dictionary of signature identifiers and PdfSignatureOptions objects. This dictionary defines signatures available in the Web Document Viewer.
Select a signature to sign the exported document from the Signature drop down list in the PDF Export Options section:
The selected signature is used to digitally sign the exported PDF document. The XRPdfSignature control adds a visual signature:
Customize the Exported Document
File: CustomViewerOperationLogger.cs
The example uses the PDF Document API to add a digital signature to a PDF document. Override the CustomizeExportDocumentOnFinish method to retrieve and modify the exported document.
Note:
If you use this method to sign a PDF document, the XRPdfSignature control doesn't add a visual signature representation. To confirm that the document is signed, open it in the PDF editor.
The CustomViewerOperationLogger
service inherits the WebDocumentViewerOperationLogger class. The CustomizeExportDocumentOnFinish method creates a PKCS#7 signature with a certificate and a password specified in the object constructor. PdfSignatureBuilder properties allow you to specify the signer’s name, location, contact information, and the reason for signing.
To sign the exported document, call the PdfDocumentSigner.SaveDocument method and pass the created PdfSignatureBuilder object as a parameter.
Files to Review
Documentation
- Print and Export Reports in ASP.NET Core Applications
- Export to PDF (Reporting)
- Sign PDF Documents (PDF Document API)
More Examples
- PDF Document API - Apply Multiple Signatures
- PDF Document API - Add a Visual Signature to a PDF Document
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using DevExpress.XtraPrinting;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Hosting;
namespace SignPdfDocumentExample.Services {
public class CustomPdfSignatureOptionsProviderAsync : IPdfSignatureOptionsProviderAsync {
readonly Dictionary<string, PdfSignatureOptions> signatures = new Dictionary<string, PdfSignatureOptions>();
public CustomPdfSignatureOptionsProviderAsync(IWebHostEnvironment webHostEnvironment) {
var signatureDictionaryPath = Path.Join(webHostEnvironment.ContentRootPath, "Signatures");
signatures.Add(Guid.NewGuid().ToString(), new PdfSignatureOptions() {
Certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(Path.Combine(signatureDictionaryPath, "certificate.pfx"), "123"),
ContactInfo = "Jane Cooper",
});
signatures.Add(Guid.NewGuid().ToString(), new PdfSignatureOptions() {
Certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(Path.Combine(signatureDictionaryPath, "certificate.pfx"), "123"),
ContactInfo = "John Smith",
Location = "Australia",
Reason = "I Agree",
ImageSource = DevExpress.XtraPrinting.Drawing.ImageSource.FromFile(Path.Combine(signatureDictionaryPath, "John_Smith.png"))
});
}
public Task<Dictionary<string, PdfSignatureOptions>> GetAvailableOptionsAsync() {
return Task.FromResult(signatures);
}
}
}
C#using System.IO;
using DevExpress.Office.DigitalSignatures;
using DevExpress.Pdf;
using DevExpress.XtraReports.Web.ClientControls;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace SignPdfDocumentExample.Services {
public class CustomViewerOperationLogger : WebDocumentViewerOperationLogger {
readonly ILogger<CustomViewerOperationLogger> logger;
readonly IWebHostEnvironment webHostEnvironment;
public CustomViewerOperationLogger(ILogger<CustomViewerOperationLogger> logger, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment) {
this.logger = logger;
this.webHostEnvironment = webHostEnvironment;
}
public override void CustomizeExportDocumentOnFinish(string documentId, string exportOperationId, ExportedDocument exportedDocument) {
if(exportedDocument.ContentType == "application/pdf") {
string certificateFile = Path.Join(webHostEnvironment.ContentRootPath, "Signatures", "certificate.pfx");
using(PdfDocumentSigner documentSigner = new PdfDocumentSigner(new MemoryStream(exportedDocument.Bytes))) {
var signer = new Pkcs7Signer(certificateFile, "123", HashAlgorithmType.SHA256);
PdfSignatureBuilder signature = new PdfSignatureBuilder(signer);
signature.ContactInfo = "John Smith";
signature.Reason = "I Agree";
MemoryStream stream = new MemoryStream();
documentSigner.SaveDocument(stream, signature);
exportedDocument.Bytes = stream.ToArray();
}
logger.LogInformation($"Exported document {documentId} signed with \"certificate.pfx\" signature certificate.");
}
}
}
}
C#using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;
using DevExpress.XtraReports.Services;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SignPdfDocumentExample.Services;
namespace SignPdfDocumentExample {
public class Startup {
public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services.AddDevExpressControls();
services.AddScoped<IReportProvider, CustomReportProvider>();
services.AddScoped<WebDocumentViewerOperationLogger, CustomViewerOperationLogger>();
services.AddSingleton<IPdfSignatureOptionsProviderAsync, CustomPdfSignatureOptionsProviderAsync>();
services
.AddMvc()
.AddNewtonsoftJson();
services.ConfigureReportingServices(configurator => {
configurator.ConfigureWebDocumentViewer(viewerConfigurator => {
viewerConfigurator.UseCachedReportSourceBuilder();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) {
app.UseDevExpressControls();
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
if(env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
} else {
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}