Example T1166641
Visible to All Users

Reporting for ASP.NET Core - Use the Web Document Viewer to Sign an Exported PDF Document

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:

Signature Options

The selected signature is used to digitally sign the exported PDF document. The XRPdfSignature control adds a visual signature:

Signed PDF Document

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

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

SignPdfDocumentExample/Services/CustomPdfSignatureOptionsProviderAsync.cs
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); } } }
SignPdfDocumentExample/Services/CustomViewerOperationLogger.cs
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."); } } } }
SignPdfDocumentExample/Startup.cs
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?}"); }); } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.