
Free ASP.NET MVC File Manager with Built‑in PDF Viewer
Build a Free ASP.NET MVC File Manager that Shows PDFs
You want a page that lists the files stored on the server, lets the user download or delete them, and opens any PDF in‑browser without leaving the site. The following guide shows you how to do exactly that with plain ASP.NET MVC, the built‑in session cache, and Doconut’s universal document viewer.
1. Scaffold a Minimal MVC Application
Create a new MVC project in Visual Studio (any edition, including the free Community edition).
Add a FileController that will host the file‑manager actions:
public class FileController : Controller
{
private readonly string _root = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "Docs");
public IActionResult Index()
{
var files = Directory.GetFiles(_root).Select(Path.GetFileName).ToList();
return View(files);
}
public IActionResult Download(string name)
{
var path = Path.Combine(_root, name);
if (!System.IO.File.Exists(path)) return NotFound();
var mime = "application/octet-stream";
return PhysicalFile(path, mime, name);
}
public IActionResult Delete(string name)
{
var path = Path.Combine(_root, name);
if (System.IO.File.Exists(path)) System.IO.File.Delete(path);
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> ViewPdf(string name)
{
var path = Path.Combine(_root, name);
if (!System.IO.File.Exists(path)) return NotFound();
// The viewer token is created here (see section 2)
var token = await _viewer.OpenDocumentAsync(
path,
new Doconut.PdfConfig { AllowSearch = true },
new DocOptions(),
CancellationToken.None);
ViewBag.Token = token;
ViewBag.BasePath = "doconut"; // matches the middleware branch
ViewBag.ResPath = "doconut-res/images";// embedded resources
return View();
}
private readonly Doconut.Viewer _viewer;
public FileController(Doconut.Viewer viewer) => _viewer = viewer;
}
The controller does three things:
- Index – reads the
App_Data/Docsfolder and passes the file names to a view. - Download / Delete – standard MVC actions that use the built‑in
PhysicalFilehelper. - ViewPdf – opens the selected PDF with Doconut, receives a security token, and passes it to a Razor view.
2. Wire Up Session State and Doconut Services
Doconut’s viewer relies on ASP.NET session state to protect the token that identifies a document. Add the required services in Program.cs (or Startup.cs for .NET 6 projects):
var builder = WebApplication.CreateBuilder(args);
// MVC services
builder.Services.AddControllersWithViews();
// Session cache – required for token validation
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
// Doconut registration – point to your license file
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", "Doconut.Viewer.lic");
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false; // keep the default security
});
var app = builder.Build();
// Session must run before the viewer middleware
app.UseSession();
// The Doconut middleware must be mapped to the path configured above.
// See Doconut documentation for the exact mapping call (e.g., app.Map("/doconut", …)).
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
app.Run();
Key points:
AddDistributedMemoryCachesupplies the in‑memory store thatAddSessionneeds.UseSession()must appear before the Doconut middleware; otherwise you’ll see the runtime error “Session middleware not configured.”MiddlewarePathandResourcesPathare coordination strings – the actual middleware branch must match the path you configure.
3. Create the File‑Manager View
Create Views/File/Index.cshtml. It lists files and provides actions for download, delete, and PDF view.
@model List<string>
<h2>Document Library</h2>
<table>
<thead><tr><th>Name</th><th>Actions</th></tr></thead>
<tbody>
@foreach (var f in Model)
{
<tr>
<td>@f</td>
<td>
<a asp-action="Download" asp-route-name="@f">Download</a> |
<a asp-action="Delete" asp-route-name="@f">Delete</a> |
@if (Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
{
<a asp-action="ViewPdf" asp-route-name="@f">View PDF</a>
}
</td>
</tr>
}
</tbody>
</table>
When the user clicks View PDF, the ViewPdf action creates a token and returns a second view that hosts the viewer widget.
4. Render the Doconut Viewer
Create Views/File/ViewPdf.cshtml. The page only needs a container element; the JavaScript widget is loaded from the embedded resources.
@{
var token = ViewBag.Token as string;
var basePath = ViewBag.BasePath as string;
var resPath = ViewBag.ResPath as string;
}
<h2>PDF Preview</h2>
<div id="div_ctlDoc"></div>
<script src="@($"{basePath}/docViewer.js")"></script>
<link rel="stylesheet" href="@($"{basePath}/docViewer.css")" />
<script>
$('#div_ctlDoc').docViewer({
AccessToken: '@token',
BasePath: '@basePath',
ResPath: '@resPath',
FitType: 'width',
showThumbs: true,
autoLoad: true,
onError: function (msg) { console.error(msg); }
});
</script>
The widget reads the AccessToken you supplied, contacts the /doconut/DocImage.axd endpoint, and streams each page as an image. Because the token is tied to the current ASP.NET session, a user cannot copy the URL and view the document from another browser without the same session cookie.
5. Handling Token Expiration and Security
Doconut’s default token timeout is 60 minutes (configurable via DocOptions.TimeOut). If the viewer receives “Document session not found” or “You Are Not Authorized To View This Page”, the session has either expired or the request is coming from a different browser context.
Typical remedies:
- Refresh the page – the controller will generate a fresh token.
- Increase the timeout – pass a custom
DocOptionswhen opening the document:
var options = new DocOptions { TimeOut = TimeSpan.FromHours(2) };
var token = await _viewer.OpenDocumentAsync(
path,
new Doconut.PdfConfig { AllowSearch = true },
options,
CancellationToken.None);
- Cross‑origin setups – ensure the
SameSiteattribute on the session cookie is compatible with your front‑end domain. The defaultLaxworks for most same‑origin portals.
6. Extending the Manager (Optional)
The core file manager is already functional, but you may want to add:
- Upload – a simple form that posts an
IFormFileand saves it to_root. - Folder navigation – modify the
Indexaction to accept a relative path and guard it against directory traversal (Path.GetFullPath+StartsWith(_root)check). - Search – filter
filesby name before passing them to the view.
All these extensions stay within the same MVC pattern and continue to benefit from the same session‑protected Doconut viewer.
7. What You Have Achieved
- A free ASP.NET MVC file manager – no third‑party UI libraries, no licensing fees.
- In‑browser PDF rendering via Doconut’s universal viewer, avoiding the need for Office or Adobe installations on the client.
- Secure token‑based access that leverages ASP.NET session state, preventing arbitrary URL sharing.
- A single code base that works for .NET 6 and .NET 8 and can be ported to Razor Pages or minimal APIs with only the registration calls (
AddDoconut,UseSession) changing.
Deploy the app to IIS, Azure App Service, or Docker – the same Program.cs configuration works everywhere because Doconut runs on .NET 6+ and does not require any native Office components.