How can I help you?
Getting Started with Server-Backed ASP.NET Core PDF Viewer
28 Feb 202624 minutes to read
The ASP.NET Core PDF Viewer control is a server-backed solution for viewing, printing, and interacting with PDF files in web applications. Unlike the standalone PDF Viewer that performs client-side rendering, the server-backed variant processes and renders PDFs on the server, providing enhanced performance and security for enterprise applications. The control delivers a rich viewing experience with core interactions such as zooming, scrolling, text search, text selection, and text copying. Built-in support for thumbnails, bookmarks, hyperlinks, and tables of contents enables seamless navigation within and across PDF documents. Users can also annotate documents and fill form fields directly within the viewer.
Prerequisites
Before starting the setup, ensure the following requirements are met:
- System Requirements: Review the system requirements for ASP.NET Core controls
- License: For production applications, a valid Syncfusion license key must be registered as described in the ASP.NET Core licensing documentation
Integrate PDF Viewer into an ASP.NET Core application
Step 1: Create a new ASP.NET Core project
- Start Visual Studio and select Create a new project.
- In the Create a new project dialog, select ASP.NET Core Web App.
- In the Configure your new project dialog, enter the project name and select Next.
- In the Additional information dialog, select .NET 6.0 (Long-term Support) or a later LTS version (such as .NET 8.0), and then select Create.
ASP.NET Core PDF Viewer NuGet package installation
Step 2: Install required NuGet packages
To add Syncfusion ASP.NET Core controls to the application, use the NuGet package manager. Open the Package Manager Console or use the NuGet Package Manager UI in Visual Studio and install the Syncfusion.EJ2.AspNet.Core package.
Install-Package Syncfusion.EJ2.AspNet.Core -Version 32.2.3Add Syncfusion® ASP.NET Core Tag Helper
Step 3: Import the Tag Helper
Open ~/Pages/_ViewImports.cshtml and add the Syncfusion EJ2 Tag Helper import. This makes all Syncfusion tag helpers available throughout the application.
@addTagHelper *, Syncfusion.EJ2Add style sheet
Step 4: Add component styles
Reference the Syncfusion theme using the CDN inside the <head> of ~/Pages/Shared/_Layout.cshtml. This stylesheet provides styling for all Syncfusion components including the PDF Viewer.
<head>
...
<!-- Syncfusion ASP.NET Core controls styles -->
<link rel="stylesheet" href="https://cdn.syncfusion.com/ej2/32.2.3/fluent.css" />
</head>NOTE
See the Themes topic for different ways to reference styles in an ASP.NET Core application, including CDN, NPM package, and CRG.
Add script reference
Step 5: Add component scripts
Add the Syncfusion JavaScript library using the CDN inside the <head> of ~/Pages/Shared/_Layout.cshtml. This script provides the core functionality for all Syncfusion components.
<head>
...
<!-- Syncfusion ASP.NET Core controls scripts -->
<script src="https://cdn.syncfusion.com/ej2/32.2.3/dist/ej2.min.js"></script>
</head>Register Syncfusion® Script Manager
Step 6: Register the script manager
Open ~/Pages/Shared/_Layout.cshtml and register the script manager at the end of the <body> tag. The script manager initializes Syncfusion components and manages their lifecycle.
<body>
....
....
<!-- Syncfusion ASP.NET Core Script Manager -->
<ejs-scripts></ejs-scripts>
</body>NOTE
Add the script manager
<ejs-script>at the end of the<body>.
Add ASP.NET Core PDF Viewer control
Step 7: Add the PDF Viewer component
Add the Syncfusion® ASP.NET Core PDF Viewer tag helper in ~/Pages/Index.cshtml. The serviceUrl property is essential for server-backed mode, as it specifies the server endpoint that handles all PDF processing operations.
@page "{handler?}"
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<ejs-pdfviewer id="pdfviewer" style="height:600px" serviceUrl="/Index" documentPath="https://cdn.syncfusion.com/content/pdf/pdf-succinctly.pdf">
</ejs-pdfviewer>
</div>Step 8: Implement server-side handlers
Add the following code to Index.cshtml.cs in the Pages folder. The IndexModel class contains handler methods that process all PDF operations on the server, such as loading documents, rendering pages, handling annotations, and managing downloads.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Syncfusion.EJ2.PdfViewer;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Reflection;
using System.Net;
namespace PDFViewerSample.Pages
{
[IgnoreAntiforgeryToken(Order = 1001)]
public class IndexModel : PageModel
{
private readonly Microsoft.AspNetCore.Hosting.IHostingEnvironment _hostingEnvironment;
private IMemoryCache _cache;
public IndexModel(Microsoft.AspNetCore.Hosting.IHostingEnvironment hostingEnvironment, IMemoryCache cache)
{
_hostingEnvironment = hostingEnvironment;
_cache = cache;
}
public IActionResult OnPostLoad([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
MemoryStream stream = new MemoryStream();
var jsonObject = JsonConverterstring(responseData);
object jsonResult = new object();
if (jsonObject != null && jsonObject.ContainsKey("document"))
{
if (bool.Parse(jsonObject["isFileName"]))
{
string documentPath = GetDocumentPath(jsonObject["document"]);
if (!string.IsNullOrEmpty(documentPath))
{
byte[] bytes = System.IO.File.ReadAllBytes(documentPath);
stream = new MemoryStream(bytes);
}
else
{
string fileName = jsonObject["document"].Split(new string[] { "://" }, StringSplitOptions.None)[0];
if (fileName == "http" || fileName == "https")
{
WebClient WebClient = new WebClient();
byte[] pdfDoc = WebClient.DownloadData(jsonObject["document"]);
stream = new MemoryStream(pdfDoc);
}
else
return this.Content(jsonObject["document"] + " is not found");
}
}
else
{
byte[] bytes = Convert.FromBase64String(jsonObject["document"]);
stream = new MemoryStream(bytes);
}
}
jsonResult = pdfviewer.Load(stream, jsonObject);
return Content(JsonConvert.SerializeObject(jsonResult));
}
public Dictionary<string, string> JsonConverterstring(jsonObjects results)
{
Dictionary<string, object> resultObjects = new Dictionary<string, object>();
resultObjects = results.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(results, null));
var emptyObjects = (from kv in resultObjects
where kv.Value != null
select kv).ToDictionary(kv => kv.Key, kv => kv.Value);
Dictionary<string, string> jsonResult = emptyObjects.ToDictionary(k => k.Key, k => k.Value.ToString());
return jsonResult;
}
//Post action for processing the PDF documents.
public IActionResult OnPostRenderPdfPages([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
object jsonResult = pdfviewer.GetPage(jsonObject);
return Content(JsonConvert.SerializeObject(jsonResult));
}
//Post action for unloading and disposing the PDF document resources
public IActionResult OnPostUnload([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
pdfviewer.ClearCache(jsonObject);
return this.Content("Document cache is cleared");
}
//Post action for rendering the ThumbnailImages
public IActionResult OnPostRenderThumbnailImages([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
object result = pdfviewer.GetThumbnailImages(jsonObject);
return Content(JsonConvert.SerializeObject(result));
}
//Post action for processing the bookmarks from the PDF documents
public IActionResult OnPostBookmarks([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
object jsonResult = pdfviewer.GetBookmarks(jsonObject);
return Content(JsonConvert.SerializeObject(jsonResult));
}
//Post action for rendering the annotation comments
public IActionResult OnPostRenderAnnotationComments([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
object jsonResult = pdfviewer.GetAnnotationComments(jsonObject);
return Content(JsonConvert.SerializeObject(jsonResult));
}
//Post action for exporting the annotations
public IActionResult OnPostExportAnnotations([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
string jsonResult = pdfviewer.ExportAnnotation(jsonObject);
return Content(jsonResult);
}
//Post action for importing the annotations
public IActionResult OnPostImportAnnotations([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
string jsonResult = string.Empty;
object JsonResult;
if (jsonObject != null && jsonObject.ContainsKey("fileName"))
{
string documentPath = GetDocumentPath(jsonObject["fileName"]);
if (!string.IsNullOrEmpty(documentPath))
{
jsonResult = System.IO.File.ReadAllText(documentPath);
}
else
{
return this.Content(jsonObject["document"] + " is not found");
}
}
else
{
string extension = Path.GetExtension(jsonObject["importedData"]);
if (extension != ".xfdf")
{
JsonResult = pdfviewer.ImportAnnotation(jsonObject);
return Content(JsonConvert.SerializeObject(JsonResult));
}
else
{
string documentPath = GetDocumentPath(jsonObject["importedData"]);
if (!string.IsNullOrEmpty(documentPath))
{
byte[] bytes = System.IO.File.ReadAllBytes(documentPath);
jsonObject["importedData"] = Convert.ToBase64String(bytes);
JsonResult = pdfviewer.ImportAnnotation(jsonObject);
return Content(JsonConvert.SerializeObject(JsonResult));
}
else
{
return this.Content(jsonObject["document"] + " is not found");
}
}
}
return Content(jsonResult);
}
//Post action for downloading the PDF documents
public IActionResult OnPostDownload([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
string documentBase = pdfviewer.GetDocumentAsBase64(jsonObject);
return Content(documentBase);
}
//Post action for printing the PDF documents
public IActionResult OnPostPrintImages([FromBody] jsonObjects responseData)
{
PdfRenderer pdfviewer = new PdfRenderer(_cache);
var jsonObject = JsonConverterstring(responseData);
object pageImage = pdfviewer.GetPrintImage(jsonObject);
return Content(JsonConvert.SerializeObject(pageImage));
}
//Gets the path of the PDF document
private string GetDocumentPath(string document)
{
string documentPath = string.Empty;
if (!System.IO.File.Exists(document))
{
string basePath = _hostingEnvironment.WebRootPath;
string dataPath = string.Empty;
dataPath = basePath + "/";
if (System.IO.File.Exists(dataPath + (document)))
documentPath = dataPath + document;
}
else
{
documentPath = document;
}
return documentPath;
}
}
public class jsonObjects
{
public string document { get; set; }
public string password { get; set; }
public string zoomFactor { get; set; }
public string isFileName { get; set; }
public string xCoordinate { get; set; }
public string yCoordinate { get; set; }
public string pageNumber { get; set; }
public string documentId { get; set; }
public string hashId { get; set; }
public string sizeX { get; set; }
public string sizeY { get; set; }
public string startPage { get; set; }
public string endPage { get; set; }
public string stampAnnotations { get; set; }
public string textMarkupAnnotations { get; set; }
public string stickyNotesAnnotation { get; set; }
public string shapeAnnotations { get; set; }
public string measureShapeAnnotations { get; set; }
public string action { get; set; }
public string pageStartIndex { get; set; }
public string pageEndIndex { get; set; }
public string fileName { get; set; }
public string elementId { get; set; }
public string pdfAnnotation { get; set; }
public string importPageList { get; set; }
public string uniqueId { get; set; }
public string data { get; set; }
public string viewPortWidth { get; set; }
public string viewPortHeight { get; set; }
public string tilecount { get; set; }
public bool isCompletePageSizeNotReceived { get; set; }
public string freeTextAnnotation { get; set; }
public string signatureData { get; set; }
public string fieldsData { get; set; }
public string formDesigner { get; set; }
public string inkSignatureData { get; set; }
public bool hideEmptyDigitalSignatureFields { get; set; }
public bool showDigitalSignatureAppearance { get; set; }
public bool digitalSignaturePresent { get; set; }
public string tileXCount { get; set; }
public string tileYCount { get; set; }
public string digitalSignaturePageList { get; set; }
public string annotationCollection { get; set; }
public string annotationsPageList { get; set; }
public string formFieldsPageList { get; set; }
public bool isAnnotationsExist { get; set; }
public bool isFormFieldAnnotationsExist { get; set; }
public string documentLiveCount { get; set; }
public string annotationDataFormat { get; set; }
public string importedData { get; set; }
}
}Code explanation
The implementation includes the following key components:
- The ejs-pdfviewer tag helper renders the PDF Viewer control with the id
pdfviewer - The serviceUrl property specifies the server endpoint (
/Index) that processes all PDF operations - The documentPath property defines the PDF document to load (can be a URL or local file path)
Step 9: Run the application
Press Ctrl+F5 (Windows) or ⌘+F5 (macOS) to run the application. The Syncfusion® ASP.NET Core PDF Viewer will render in the default web browser with the server-backed rendering engine.

The serviceUrl can be updated dynamically at runtime. After updating the value, invoke pdfViewer.dataBind() to apply the change and then load the document. This feature is supported in version 23.1.36 or later.
function load() {
var pdfViewer = document.getElementById('pdfviewer').ej2_instances[0];
pdfViewer.serviceUrl = "/Index";
pdfViewer.documentPath = "https://cdn.syncfusion.com/content/pdf/pdf-succinctly.pdf";
pdfViewer.dataBind();
pdfViewer.load(pdfViewer.documentPath, null);
}NOTE
A complete working sample is available on GitHub. View the ASP.NET Core PDF Viewer sample.
Unlike the standalone PDF Viewer which performs client-side rendering, the server-backed PDF Viewer processes and renders PDFs entirely on the server. As a result, the following files are not required and should be omitted during deployment:
pdfium.jspdfium.wasm
NOTE
For hosting the web service on Linux, include SkiaSharp.NativeAssets.Linux. For AWS environments, use the following packages:
| Amazon Web Services (AWS) | NuGet package name |
|---|---|
| AWS Lambda | SkiaSharp.NativeAssets.Linux |
| AWS Elastic Beanstalk | SkiaSharp.NativeAssets.Linux.NoDependencies v3.116.1 |