This demo uses the PDF Document API to merge different documents into a single PDF. Click Merge files and download to merge uploaded files and obtain the resulting PDF.
@using DevExtreme.AspNet.Mvc
@using (Html.BeginForm("PdfMergeAndDownload", "SplitMerge", FormMethod.Post)) {
<div class="upload-proceed-no-margins">
<div class="upload-proceed-item">
@(Html.DevExtreme().FileUploader()
.ID("file-uploader")
.Name("myFile")
.Multiple(true)
.ShowFileList(true)
.Accept(".pdf")
.AllowedFileExtensions(new List<string> { ".pdf" })
.MaxFileSize(4194304)
.LabelText("Maximum file size 4Mb.")
.UploadMode(FileUploadMode.UseButtons)
.OnUploaded("enableButton")
.UploadUrl(Url.Action("DocumentUpload", "SplitMerge"))
)
</div>
<div class="upload-proceed-item">
@(Html.DevExtreme().Button()
.ID("downloadButton")
.Text("Merge files and download")
.Disabled(true)
.Type(ButtonType.Default)
.StylingMode(ButtonStylingMode.Contained)
.UseSubmitBehavior(true)
.OnClick("reset")
)
</div>
</div>
<script>
function enableButton() {
$("#downloadButton").dxButton("instance").option("disabled", false);
}
function reset() {
$("#file-uploader").dxFileUploader("instance").reset();
$("#downloadButton").dxButton("instance").option("disabled", true);
}
</script>
}
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace AspNetCoreDemos.OfficeFileAPI {
public partial class SplitMergeController : OfficeDemoController {
IMergeDemoService service;
public SplitMergeController(ILogger<SplitMergeController> logger, IWebHostEnvironment hostingEnvironment, IMergeDemoService service)
: base(logger, hostingEnvironment) {
this.service = service;
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using DevExpress.Pdf;
namespace AspNetCoreDemos.OfficeFileAPI {
public class PdfModelBase : IDisposable {
readonly PdfDocumentProcessor processor;
MemoryStream stream;
List<PdfPageModel> items = new List<PdfPageModel>();
public MemoryStream Stream { get { return stream; } }
protected PdfDocumentProcessor Processor { get { return processor; } }
protected PdfDocument Document { get { return processor.Document; } }
public List<PdfPageModel> Items { get { return items; } }
public string DocumentUrl { get; set; }
public int PageIndex { get; set; }
internal virtual string SessionKey { get; }
public PdfPreviewModel PreviewModel { get; internal set; }
public PdfModelBase() {
processor = new PdfDocumentProcessor();
PreviewModel = new PdfPreviewModel();
}
protected void CreateEmptyDocument() {
stream = new MemoryStream();
Processor.CreateEmptyDocument(stream);
Document.Creator = "PDF Document Processor Demo";
Document.Producer = "Developer Express Inc., " + AssemblyInfo.Version;
Document.Author = "DevExpress Inc.";
}
public virtual void LoadDocument(byte[] data) {
using(MemoryStream stream = new MemoryStream(data))
LoadDocument(stream);
}
protected void LoadDocument(Stream stream) {
processor.LoadDocument(stream, true);
for(int pageNumber = 1; pageNumber <= processor.Document.Pages.Count; pageNumber++)
Items.Add(new PdfPageModel(processor, pageNumber));
}
public void Dispose() {
if(processor != null)
processor.Dispose();
GC.SuppressFinalize(this);
}
}
}
using System.Collections.Generic;
using System.IO;
using DevExpress.Pdf;
namespace AspNetCoreDemos.OfficeFileAPI {
public static class PdfPageMergingModel {
public static Stream GetMergedDocument(IEnumerable<string> fileNames) {
MemoryStream stream = new MemoryStream();
using(PdfDocumentProcessor processor = new PdfDocumentProcessor()) {
processor.CreateEmptyDocument(stream);
foreach(string fileName in fileNames)
processor.AppendDocument(fileName);
processor.Document.Creator = "PDF Document Processor Demo";
processor.Document.Producer = "Developer Express Inc., " + AssemblyInfo.Version;
return stream;
}
}
}
}
using System;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace AspNetCoreDemos.OfficeFileAPI {
public partial class SplitMergeController {
static object lockObject = new object();
const string mergeSessionKey = "PdfMergeFiles";
const string directorySessionKey = "PdfMergeFilesDirectory";
public IActionResult PdfPageMerging() {
EnsureSessionKey();
return View();
}
[HttpPost]
public IActionResult DocumentUpload(IFormFile myFile) {
var path = EnsureUploadedDirectory();
var uploadedFilePath = Path.Combine(path, $"{ Guid.NewGuid() }.pdf");
using(var fileStream = System.IO.File.Create(uploadedFilePath))
myFile.CopyTo(fileStream);
return new OkResult();
}
string EnsureUploadedDirectory() {
lock(lockObject) {
var key = EnsureSessionKey();
var dirPath = Path.Combine(service.UploadPath, key);
if(!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
return dirPath;
}
}
string EnsureSessionKey() {
var key = HttpContext.Session.GetString(directorySessionKey);
if(string.IsNullOrEmpty(key)) {
key = Guid.NewGuid().ToString();
HttpContext.Session.SetString(directorySessionKey, key);
}
return key;
}
public IActionResult PdfMergeAndDownload() {
var path = EnsureUploadedDirectory();
var filePaths = Directory.GetFiles(path, "*.pdf");
try {
if(filePaths.Length > 0) {
var stream = PdfPageMergingModel.GetMergedDocument(filePaths);
return CreateFileStreamResult(stream, "application/pdf", "pdf", "Result");
}
return new NoContentResult();
} catch(Exception ex) {
Logger.LogError(ex, null);
return new NoContentResult();
} finally {
Directory.Delete(path, true);
}
}
}
public interface IMergeDemoService {
string UploadPath { get; }
}
public class PdfMergeDemoService : IMergeDemoService {
static TimeSpan delay = new TimeSpan(0, 5, 0);
static void ThreadProc(object obj) {
string uploadsDirectory = (string)obj;
while(true) {
try {
if(Directory.Exists(uploadsDirectory)) {
DateTimeOffset expirationTime = DateTimeOffset.Now.Subtract(delay);
foreach(var directory in Directory.GetDirectories(uploadsDirectory)) {
if(expirationTime > Directory.GetLastAccessTime(directory)) {
try {
Directory.Delete(directory, true);
} catch {
}
}
}
}
} catch {
}
Thread.Sleep(delay);
}
}
public PdfMergeDemoService(IWebHostEnvironment environment) {
Environment = environment ?? throw new ArgumentNullException(nameof(environment));
Thread thread = new Thread(ThreadProc);
thread.IsBackground = true;
thread.Start(UploadPath);
}
IWebHostEnvironment Environment { get; }
public string UploadPath => Path.Combine(Environment.WebRootPath, "uploads");
}
}