ASP.NET Core MVC PDF Viewer
How to read, view PDF in browser in C# ASP.NET Core MVC web applications


Step by step guide how to create a new ASP.NET Core MVC web app with online PDF viewer enabled using EdgePDF web control













Prerequisites







Create a ASP.NET Core MVC web app with EdgePDF ASP.NET PDF Viewer installed using C#



Step 1: Create a new ASP.NET Core MVC app in Visual Studio 2022

  1. Start Visual Studio 2022 and select Create a new project.


  2. Select ASP.NET Core Web App (Model-View-Controller) in the dialog, and then press Next button.


  3. Create a new project with name "EdgePDFMVCDemo". Click button Next.


  4. Select .NET 6.0 (Long-term support), and then press Create.


  5. Now, all auto-generated files could be found in the solution explorer







Step 2: Download and install Nuget packages

EdgePDF for ASP.NET Core MVC requires the following Nuget packages:

  • System.Drawing.Common (Version 6.0.0 or later)
  • System.IO.Packaging (Version 6.0.0 or later)
  • Newtonsoft.Json (Version 11.0.2 or later)
  • WaterTrans.GlyphLoader (Version 1.0.0 or later)



  1. Right-click "Dependencies" in the Solution Explorer, and select "Manage NuGet Packages ...".


  2. Select "Browse" and use the search control to find the above four packages from the package source "nugget.org"


  3. Choose the minimum version or later to install the package


  4. Check "Packages" in the Solution Explorer to ensure the installation is success.





Step 3: Install EdgePDF DLLs and resource files



  1. Add all RasterEdge DLL references (add all DLLs with prefix "RasterEdge" in file name).

    Please go to download package "/Bin", and choose .NET Standard 2.0 DLLs.



  2. Copy all VC++ DLLs (both x86 and x64 versions) manually to the same folder as the assembly "RasterEdge.Imaging.Basic.dll".



  3. Add the folder /EdgePDFDemo/wwwroot/RasterEdge_Resource_Files/ (all content) to the project and add an empty folder RasterEdge_Cache.



  4. Set the configuration file "appsettings.json"

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "AppSettings": {
        "reCacheFolder": "RasterEdge_Cache",
        "reCustomStampFolder": "RasterEdge_Resource_Files/images/stamp",
        //  Set the server folder if you want to open the file on server.
        "reDefaultFolder": "RasterEdge_Demo_Docs",
        //  Set the default file when open the web first time, if set "", this function is disabled. (reDefaultFolder needed)
        "reDefaultFilePath": "",
        //  Image quality in PDF document
        "rePageImageZoom": "2",
        "reImageZoom": "2",
        //  Image annotation in PDF document
        "reAnnotationImageZoom": "2",
        //  Write log 
        "reOutputLogData": "true",
        "reSDKLogerEnable": "true",
        //  DEBUG ,INFO ,WARNING,ERROR
        "reLogLevel": "DEBUG",
        "reWDPFileCacheMaxLimit": "0",
        "reWDPSinglePDFMaxLinkCount": "5000",
        //  If true, SDK will automatically convert many shape and path inside PDF page into image.
        "reIntelliDrawShapesToImage": "true",
        //  Valid values: "all", "firefox", "chrome", "ie", "edge", "salari", "others".
        //  If "all" included, ignore the rest;
        //  Default: "all"
        "reIntelliDrawShapesToImageSupportBrowsers": "all",
        //  Set the type of the show page.
        //  Valid values: "svg", "png", "html"
        //  Default: "html"
        "reDocRenderEngine": "svg",
        "reRestfulFolder": "c:/RasterEdge_Restful",
        "reI18NFolder": "/RasterEdge_Resource_Files/i18n/",
        //  Set the domain for remote client
        "reServerURL": "",
        //  If true, SDK will automatically all pages after file has been uploaded.
        //  Deafult: false.
        "autoProcessWholeDocument": "false",
        //  If true, SDK will automatically render extract text content after file has been uploaded.
        //  Default: false.
        "autoIndexTextSearchWholeDocument": "false",
        //  Set the js response max try time when save file or save as.
        "reJSResponseMaxTryTime": "120"
      }
    }
    


  5. Add middleware UserCommandProcessMiddleware.cs to the project.

    Add a New Item to the project.


    Add a Middleware Class "UserCommandProcessMiddleware.cs".


    Copy all following contents to the class file.

    using System;
    using RasterEdge.WDP;
    using RasterEdge.XDoc.PDF.HTML5Editor;
    
    namespace EdgePDFMVCDemo
    {
        // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
        public class UserCommandProcessMiddleware : ProcessMiddleware
        {
            public UserCommandProcessMiddleware(RequestDelegate next)
                : base(next)
            {
            }
    
            public override PDFWebDocument FileProcess(REHttpContext context)
            {
                HttpRequest request = context.Request;
    
                if (!String.IsNullOrEmpty(request.Query["yourtarget"]))
                {
                    // load file
                    String docid = request.Query["yourtarget"];
                    if (docid == null) docid = "0";
                    byte[] dataBytes = System.IO.File.ReadAllBytes(@"C:\\temp\" + docid);
                    String fileName = docid;
                    return REProcessControl.PageLoadFile(request, this.Manager, dataBytes, fileName);
                }
                else
                {
                    return REProcessControl.PageLoadFile(request, this.Manager, "", LoadType.Server);
                }
            }
    
            //  fid: Task ID.
            //  savePath: The abosolute path of the saved PDF file in the task's output folder.
            //  responseMsg: The response message for saving the current document to the task's output folder.
            //               The string value is the relative path of the output file. "Error" means that the saving process is failed.
            public override void SaveFile_OnServer(String fid, String savePath, String responseMsg)
            {
                //  You can process saved pdf document here, like add watermark, ...
                var documentPath = savePath;
                if (!String.IsNullOrEmpty(documentPath))
                {
                    Logger.LogFile(fid, "SaveFileOnServer: output file path " + documentPath, LogType.DEBUG);
    
                    //  To verify the output file.
                    RasterEdge.Imaging.Basic.BaseDocument document = null;
                    if (documentPath.EndsWith(".pdf"))
                    {
                        // document object includes user modified content
                        document = new RasterEdge.XDoc.PDF.PDFDocument(documentPath);
                    }
                    if (document != null)
                    {
                        RasterEdge.XDoc.PDF.PDFDocument pdfDoc = document as RasterEdge.XDoc.PDF.PDFDocument;
                        try
                        {
                            //  Post-process
                            RasterEdge.XDoc.PDF.PDFMetadata metadata = pdfDoc.GetDescription();
                            metadata.Producer = "RasterEdge EdgePDF";
                            pdfDoc.SetDescription(metadata);
                        }
                        catch (Exception ex)
                        {
                            //  Process error code, and return error information here
                            Logger.LogFile(fid, ex.Message + ". fail to do post-process.", LogType.ERROR);
                        }
    
                        //  Get the upload information of the file
                        RasterEdge.WDP.DocUploadInfo docinfo = RasterEdge.WDP.Manager.FileManager.getUploadinfoByFid(fid);
                        //  Get your file open url parameters value, if needed.
                        String paraFilepathValue = docinfo.GetRequestParameters("yourtarget");
                        if (!String.IsNullOrEmpty(paraFilepathValue))
                        {
                            try
                            {
                                pdfDoc.Save(@"C:\temp\" + paraFilepathValue);
                            }
                            catch (Exception ex)
                            {
                                //  Process error code, and return error information here
                                Logger.LogFile(fid, ex.Message + ". fail to save file to server.", LogType.ERROR);
                            }
                        }
                        else
                        {
                            Logger.LogFile(fid, "no 'yourtarget' in the HTTPRequest.", LogType.INFO);
                        }
                    }
                    else
                    {
                        Logger.LogFile(fid, "output PDF file is invalid.", LogType.ERROR);
                    }
                }
                else
                {
                    Logger.LogFile(fid, "fail to save file to server. output file path is null or empty.", LogType.ERROR);
                }
            }
        }
    
        // Extension method used to add the middleware to the HTTP request pipeline.
        public static class UserCommandProcessMiddlewareExtensions
        {
            public static IApplicationBuilder UseUserCommandProcessMiddleware(this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<UserCommandProcessMiddleware>();
            }
        }
    }
    


  6. Add another Middleware Class DummyMiddleware.cs with the following class source code.

    using System;
    using System.Net;
    using Microsoft.Extensions.Primitives;
    using Microsoft.Extensions.Caching.Memory;
    using RasterEdge.WDP;
    
    namespace EdgePDFMVCDemo
    {
        // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
        public class DummyMiddleware
        {
            private const String DummyCacheItemKey = "CacheRegistry";
            private static String DummyPageUrl = "";
    
            private readonly RequestDelegate _next;
    
            public DummyMiddleware(RequestDelegate next)
            {
                _next = next;
            }
    
            public Task Invoke(HttpContext httpContext, IMemoryCache memoryCache)
            {
                if (DummyPageUrl == "")
                    DummyPageUrl = getRequestUrl(httpContext.Request);
    
                if (memoryCache.Get(DummyCacheItemKey) == null)
                {
                    int expirationMinutes = 15;
                    MemoryCacheEntryOptions cacheExpirationOptions = new MemoryCacheEntryOptions();
                    cacheExpirationOptions.AbsoluteExpiration = DateTime.Now.AddMinutes(expirationMinutes);
                    cacheExpirationOptions.Priority = CacheItemPriority.NeverRemove;
                    IChangeToken expirationToken = new CancellationChangeToken(new CancellationTokenSource(TimeSpan.FromMinutes(expirationMinutes + .01)).Token);
                    cacheExpirationOptions.AddExpirationToken(expirationToken);
                    cacheExpirationOptions.RegisterPostEvictionCallback((key, value, reason, state) => {
                        //  call back
                        try
                        {
                            Logger.Log("DummyCacheItemKey expired.", LogType.DEBUG);
                            WebClient client = new WebClient();
                            client.DownloadData(DummyPageUrl);
                        }
                        catch (Exception)
                        {
                        }
    
                    }, this);
    
                    memoryCache.Set<String>(DummyCacheItemKey, DateTime.Now.ToString(), cacheExpirationOptions);
                    Logger.Log("Set DummyCacheItemKey.", LogType.DEBUG);
                }
    
                return _next(httpContext);
            }
    
            private String getRequestUrl(HttpRequest request)
            {
                try
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    sb.Append(request.Scheme);
                    sb.Append("://");
                    sb.Append(request.Host);
                    return sb.ToString();
                }
                catch (Exception)
                {
                    return "";
                }
            }
        }
    
        // Extension method used to add the middleware to the HTTP request pipeline.
        public static class DummyMiddlewareExtensions
        {
            public static IApplicationBuilder UseDummyMiddleware(this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<DummyMiddleware>();
            }
        }
    }
    


  7. Use the default controller HomeController and default view Index.cshtml.



    Copy all following content to the Index.cshtml file.
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
        <title>RasterEdge Application</title>
        <script src="/RasterEdge_Resource_Files/javascript/jquery.js" type="text/javascript"></script>
        <script src="/RasterEdge_Resource_Files/javascript/RasterEdge_WebApp_Customize.js" type="text/javascript"></script>
        <script src="/RasterEdge_Resource_Files/javascript/RasterEdge_WebApp.js" type="text/javascript"></script>
        <script src="/RasterEdge_Resource_Files/javascript/RasterEdge.js" type="text/javascript"></script>
        <link rel="stylesheet" href="/RasterEdge_Resource_Files/css/process.css" type="text/css" />
        <link rel="stylesheet" href="/RasterEdge_Resource_Files/css/customize.css" type="text/css" />
        <link rel="stylesheet" href="/RasterEdge_Resource_Files/css/jquery-ui.css" type="text/css" />
        <script type="text/javascript">
            var _rootpath = "/";
    
            _WDPApp = new WDPOnlineApplication({
                _serverUrl: "/UserCommandProcessMiddleware"
            });
        </script>
    </head>
    <body>
        <div id='rasteredge_wdp'>
            <div id='wdp_Toolbar'></div>
            <div id='wdp_LeftSidebar'></div>
            <div id='wdp_Viewer'></div>
            <div id='wdp_RightSidebar'></div>
            <div id='wdp_Footer'></div>
        </div>
    </body>
    </html>
    


  8. Replace all contents in the project file "Program.cs" by the following codes

    using EdgePDFMVCDemo;
    using RasterEdge.WDP;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddControllersWithViews();
    builder.Services.AddMemoryCache();
    
    var app = builder.Build();
    
    //  Config RasterEdge.WDP
    RasterEdge.WDP.REHttpRuntime.AppDomainAppPath = app.Environment.WebRootPath;
    RasterEdge.WDP.Logger.initLog();
    //  
    Scheduler.ClearAllFolder();
    Scheduler.StartFileCacheCleanTask(FileCacheCleanType.FileLifeMaxTime, new IntervalTime(3, 0, 0));
    Scheduler.StartFileCacheCleanTask(FileCacheCleanType.FileCacheCleanTime, new IntervalTime(3, 0, 0));
    Scheduler.StartUserCacheCleanTask(UserCacheCleanType.UserRequestMaxTime, new IntervalTime(3, 0, 0));
    Scheduler.StartUserCacheCleanTask(UserCacheCleanType.UserFileRequestCacheCleanTime, new IntervalTime(3, 0, 0));
    Logger.LogSystem("Cache Auto clear Start", LogType.INFO);
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        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();
    }
    
    //  This middleware would send request to the local host every 15 minutes.
    //  Must before UseDefaultFiles & UseStaticFiles
    app.UseDummyMiddleware();
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    //  Must use the middleware after UseStaticFiles.
    app.MapWhen(context => (!String.IsNullOrEmpty(context.Request.Path.Value)
                        && context.Request.Path.Value.StartsWith("/UserCommandProcessMiddleware")),
                        appBuilder => { appBuilder.UseUserCommandProcessMiddleware(); });
    
    app.Run();
    






Step 4: Run the web app in Kestrel server



  1. It is done. Now press "Ctrl+F5" to run the project.



    It launches the Kestrel server and opens the default web browser.





  2. Enable PDF text, image editing feature in browser in C# ASP.NET Core MVC





    To support PDF text and image editing function in browser, EdgePDF library will convert PDF pages to html files in the ASP.NET web server. To enable this feature in your ASP.NET Core MVC web application, please follow the guides below.

    1. Create a new ASP.NET Core MVC web app with EdgePDF integrated

    2. Open app config file appsettings.json, change property reDocRenderEngine value to html. By default it is "svg".

    3. Run the application.





    Deploy ASP.NET Core MVC PDF Viewer web app to Azure Windows App Service



    It is simple to publish and deploy an ASP.NET Core MVC web application with EdgePDF ASP.NET PDF Viewer to Azure App Service using Visual Studio .NET. View the step by step guide at How to enable ASP.NET Core PDF Viewer web application on Azure?