ASP.NET Core  

Offline Document Preview in Web Apps (Angular + ASP.NET Core with PDF/DOCX)

Introduction

In many enterprise web applications—like maintenance systems, quality control apps, or internal portals—users need to view documents (PDF, DOCX, etc.) even when internet connectivity is lost.
Offline document preview enables users to access and read files that were previously downloaded, without reconnecting to the server.

In this article, we’ll explore how to implement an offline document preview system using Angular (frontend) and ASP.NET Core (backend) with a focus on PDF and DOCX files.

Why Offline Preview Matters

Offline functionality improves user experience and reliability, especially in scenarios like:

  • Remote sites with weak or unstable networks.

  • Mobile users accessing internal portals.

  • Industries like manufacturing, aviation, or field inspection where documents must be available 24×7.

With proper caching and synchronization, users can view their required documents even without a live connection, and the system updates automatically when online again.

Key Technologies Used

LayerTechnologyPurpose
FrontendAngular 17SPA for document preview
BackendASP.NET Core 8 Web APIFile API and metadata management
StorageIndexedDB (via Service Worker)Local caching of files
File FormatsPDF, DOCXSupported document types
LibraryPDF.js / Docx PreviewerRendering documents in browser

High-Level Architecture

+-------------------+       +--------------------------+| Angular Frontend  | <---> | ASP.NET Core File API     ||-------------------|       |--------------------------||  Service Worker   |       |   File Storage / DB       ||  IndexedDB Cache  |       |   API Controller          ||  PDF/DOCX Viewer  |       |   Authentication Filter   |+-------------------+       +--------------------------+
       ↑
       |   (Offline access via cached data)
       ↓
+-----------------------------+|  User Browser (Cache + UI)  |+-----------------------------+

Technical Workflow (Flowchart)

        ┌───────────────────────┐
        │  User Requests File   │
        └──────────┬────────────┘
                   │
                   ▼
        ┌────────────────────────┐
        │ Check IndexedDB Cache   │
        └──────────┬─────────────┘
         Cache Hit │ Cache Miss
                   ▼
     ┌────────────────────────┐
     │ Load from Cache Offline│
     └────────────────────────┘
                   │
                   ▼
     ┌────────────────────────┐
     │ Fetch from API (Online)│
     └──────────┬─────────────┘
                │
                ▼
     ┌────────────────────────┐
     │ Store in IndexedDB     │
     └──────────┬─────────────┘
                │
                ▼
     ┌────────────────────────┐
     │ Render PDF/DOCX Viewer │
     └────────────────────────┘

Step 1: Setting Up the ASP.NET Core Backend

Let’s start by building the backend API for serving document files securely.

1.1. Create the API Controller

[ApiController]
[Route("api/[controller]")]
public class DocumentController : ControllerBase
{
    private readonly IWebHostEnvironment _env;

    public DocumentController(IWebHostEnvironment env)
    {
        _env = env;
    }

    [HttpGet("{fileName}")]
    public IActionResult GetDocument(string fileName)
    {
        var filePath = Path.Combine(_env.ContentRootPath, "Documents", fileName);

        if (!System.IO.File.Exists(filePath))
            return NotFound("File not found.");

        var contentType = GetContentType(filePath);
        var bytes = System.IO.File.ReadAllBytes(filePath);
        return File(bytes, contentType, fileName);
    }

    private string GetContentType(string path)
    {
        var ext = Path.GetExtension(path).ToLowerInvariant();
        return ext switch
        {
            ".pdf" => "application/pdf",
            ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            _ => "application/octet-stream",
        };
    }
}

1.2. Folder Structure

/Documents
   ├── report1.pdf
   ├── inspection.docx
   └── manual.pdf

This API serves the requested file bytes securely to the frontend.

Step 2: Angular Service for File Access

Create a service that fetches documents from the API and manages offline caching using IndexedDB.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class DocumentService {
  private baseUrl = 'https://localhost:5001/api/document';

  constructor(private http: HttpClient) {}

  async getDocument(fileName: string): Promise<Blob> {
    const cached = await this.getFromCache(fileName);
    if (cached) return cached;

    const blob = await this.http.get(`${this.baseUrl}/${fileName}`, { responseType: 'blob' }).toPromise();
    await this.saveToCache(fileName, blob);
    return blob!;
  }

  private async getFromCache(key: string): Promise<Blob | null> {
    const db = await this.openDB();
    return (await db.get('files', key)) || null;
  }

  private async saveToCache(key: string, value: Blob) {
    const db = await this.openDB();
    await db.put('files', value, key);
  }

  private async openDB(): Promise<any> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('DocumentCache', 1);
      request.onupgradeneeded = (event: any) => {
        event.target.result.createObjectStore('files');
      };
      request.onsuccess = (event: any) => resolve(event.target.result);
      request.onerror = reject;
    });
  }
}

Step 3: Preview Component in Angular

3.1. HTML Template

<div class="preview-container">
  <ng-container *ngIf="isPdf; else wordPreview">
    <iframe [src]="fileUrl | safeUrl" width="100%" height="600px"></iframe>
  </ng-container>

  <ng-template #wordPreview>
    <iframe [src]="fileUrl | safeUrl" width="100%" height="600px"></iframe>
  </ng-template>
</div>

3.2. Component Logic

import { Component, OnInit } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { DocumentService } from './document.service';

@Component({
  selector: 'app-document-preview',
  templateUrl: './document-preview.component.html',
})
export class DocumentPreviewComponent implements OnInit {
  fileUrl: any;
  isPdf = true;
  fileName = 'report1.pdf';

  constructor(private docService: DocumentService, private sanitizer: DomSanitizer) {}

  async ngOnInit() {
    const blob = await this.docService.getDocument(this.fileName);
    this.fileUrl = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(blob));
    this.isPdf = this.fileName.endsWith('.pdf');
  }
}

Step 4: Making it Work Offline (Service Worker)

Use Angular’s built-in PWA support for service workers.

4.1. Enable PWA

Run

ng add @angular/pwa

This generates:

  • ngsw-config.json

  • Required service worker setup.

4.2. Configure Caching in ngsw-config.json

{"assetGroups": [
    {
      "name": "documents",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": ["/assets/documents/*.pdf", "/assets/documents/*.docx"]
      }
    }]}

Step 5: Handling DOCX Rendering

While PDF can be displayed directly, DOCX files can be rendered using an embedded viewer like Office Viewer or converted to PDF server-side.

Example for online rendering

<iframe [src]="'https://view.officeapps.live.com/op/embed.aspx?src=' + documentUrl"
        width="100%" height="600px"></iframe>

Step 6: Real-World Example — Maintenance Portal

Imagine a Maintenance Portal used by technicians at remote locations:

  • When online, files (manuals, reports) are fetched from the server and cached locally.

  • When offline, cached files are loaded instantly from IndexedDB.

  • Upon reconnection, updated versions are downloaded silently in the background.

Best Practices

  1. Compress large PDFs before caching.

  2. Implement versioning — store file metadata to check if newer versions are available.

  3. Clean cache periodically to avoid IndexedDB bloating.

  4. Secure API endpoints with JWT authentication.

  5. Use lazy loading for large files.

Performance Optimization

  • Use PDF.js for smooth rendering and zoom support.

  • Use Blob streaming in ASP.NET Core for large files instead of reading full bytes into memory.

  • Prefer lazy caching — store files only when accessed.

Summary

By combining Angular’s PWA capabilities, IndexedDB caching, and ASP.NET Core APIs, you can provide a robust offline document preview system that supports PDF and DOCX files seamlessly.

This solution enhances user experience, reliability, and productivity — making it ideal for enterprise-grade web applications that must function in both connected and disconnected environments.