ASHX File Documentation


Summary

An ASP.NET Web Handler file (.ashx) is server-side code that runs on a Microsoft IIS web server and writes raw output (an image, a PDF, JSON, a download) straight to the browser, without the full page machinery of an .aspx. It is not a document you open. If a website made you download something.ashx when you expected a PDF or image, the server just set the wrong name: rename it to .pdf or .jpg and open it. Developers edit .ashx source in Visual Studio or VS Code.

Technical details

FeatureValue
Full nameASP.NET Generic HTTP Handler
File extension.ashx
Response MIME typeSet by the handler (e.g. image/png, application/pdf, application/json)
Format typeServer-side source: a directive plus C# or VB.NET code
DeveloperMicrosoft
Introduced2002 (ASP.NET 1.0, .NET Framework)
Runs onMicrosoft IIS with the ASP.NET runtime
Executed byThe server — the browser never receives the .ashx itself
EncodingPlain text (UTF-8 / ASCII source)
Magic numberNone — text file, no binary signature
Key directive<%@ WebHandler Language="C#" Class="..." %>
Required interfaceIHttpHandler (ProcessRequest + IsReusable)
Typical useDynamic images, file downloads, thumbnails, small data endpoints
Appears asA URL suffix (e.g. /GetFile.ashx?id=123), not a saved document
Open standardNo — Microsoft framework technology
Modern equivalentASP.NET Core middleware, minimal APIs, MVC controllers
Related extensions.aspx, .asmx, .ascx, .cs, .vb, .asp
Specificationlearn.microsoft.com/previous-versions/aspnet/ms227675
Syntax at a glance

An .ashx is plain text with no magic number. A genuine handler source opens with a <%@ WebHandler Language="C#" Class="MyHandler" %> directive, then a class that implements IHttpHandler: a ProcessRequest(HttpContext) method that sets context.Response.ContentType and writes the output bytes, plus an IsReusable property. The browser never sees this file. Most people who “have” an .ashx instead saved a download that an .ashx URL served, in which case it is the real file (PDF, image) under the wrong name — rename it to inspect it.

What is an ASHX file?

ASHX is the extension of an ASP.NET generic HTTP handler, part of Microsoft’s .NET web stack since ASP.NET 1.0 in 2002. It is server-side program source, not a document. Where an .aspx page builds a full HTML page through the Web Forms page lifecycle, an .ashx handler is a lightweight endpoint: it runs a small piece of code on the server and writes its response straight to the output stream. That makes handlers the natural way to serve dynamic images, file downloads, thumbnails, chart pictures, captchas, or small JSON responses, anything where you want the raw bytes rather than a rendered page.

Two very different audiences meet this extension. A developer edits the .ashx source. Everyone else meets it by accident: a website served a download or an image from an .ashx URL, and the browser saved a file named report.ashx or image.ashx instead of the PDF or JPG that was expected. Those are not the same thing, and this article covers both, starting with how the handler actually works on the server.

The WebHandler directive and IHttpHandler

A real .ashx file is short and always begins with a processing directive on its first line:

<%@ WebHandler Language="C#" Class="Thumbnailer" %>
using System.Web;

public class Thumbnailer : IHttpHandler {

    public void ProcessRequest(HttpContext context) {
        context.Response.ContentType = "image/png";
        byte[] png = BuildThumbnail(context.Request["id"]);
        context.Response.BinaryWrite(png);
    }

    public bool IsReusable {
        get { return true; }
    }
}

The <%@ WebHandler %> directive tells ASP.NET two things: the language of the code (C# or VB) and the name of the Class that implements the handler. That class must implement the IHttpHandler interface, which has exactly two members. The runtime calls ProcessRequest(HttpContext) once per request, passing an HttpContext that exposes the incoming Request and the outgoing Response. The IsReusable property tells ASP.NET whether a single handler instance can be pooled and reused across requests (return true when the handler keeps no per-request state).

ProcessRequest: content type and writing bytes

Everything a handler does happens inside ProcessRequest, and the pattern is always the same: set the output type, then write the bytes. context.Response.ContentType declares the MIME type the browser should expect, image/png for a picture, application/pdf for a document, application/json for data. The body is then emitted with context.Response.Write for text or context.Response.BinaryWrite for binary data such as an image or a file. A handler that offers a file download also sets a Content-Disposition header to suggest a filename:

context.Response.ContentType = "application/pdf";
context.Response.AddHeader(
    "Content-Disposition",
    "attachment; filename=\"invoice-123.pdf\"");
context.Response.BinaryWrite(pdfBytes);

This one detail explains the most common real-world encounter with .ashx. If the handler produces a PDF but the developer forgets that Content-Disposition filename, or sets it wrong, the browser has nothing better to name the download than the URL, so it saves GetFile.ashx. The bytes are a perfectly good PDF; only the name is wrong.

What .ashx means in a web address

Because a handler is addressed like any other resource, .ashx shows up inside URLs on ASP.NET sites, typically with a query string that tells the handler what to produce: /GetImage.ashx?id=42 or /Download.ashx?file=report. The server maps that request to the handler, runs ProcessRequest, and returns whatever the handler wrote. The browser never receives the .ashx source itself and cannot; it receives the handler’s output. This is the key difference from a static file: opening the URL does not fetch a file called GetImage.ashx, it triggers server code that generates a response on the spot.

The misnamed download: turning an .ashx back into your file

If you clicked a download or an image link and ended up with an .ashx file on disk, it is almost always the real file with the wrong extension. The fix is a rename, not a conversion, because there is nothing to convert: the handler already produced your document. Rename report.ashx to report.pdf, image.ashx to image.jpg or .png, a spreadsheet to .xlsx, and open it normally. If a rename does not work, right-click the original link and choose “Save link as”, or check the site for a correct download button. There is no offline “ashx to PDF” converter, and none is needed: a genuine .ashx is server code with no printable content, while a saved .ashx download is your file waiting for the right name. To confirm what a mystery download really is, open it in a text editor and read the first bytes: %PDF marks a PDF, PK marks a ZIP-based file such as an .xlsx, and the PNG or JPEG signature marks an image.

Security: why a handler is server code, and where the risk actually is

The dangerous confusion around .ashx is treating it as a harmless static file. It is not: on the server it is a program with the full power of the ASP.NET application, running under the web server’s identity. The risk lives on the server side, and it matters to developers and site operators more than to the person who downloaded a file.

Because a handler runs arbitrary code, an attacker who can upload an .ashx into a writable, executable folder on an IIS server has effectively planted a web shell. A hostile handler can read its own query string and shell out to the operating system, letting a remote attacker run commands through a normal-looking URL:

<%@ WebHandler Language="C#" Class="x" %>
using System.Web; using System.Diagnostics;
public class x : IHttpHandler {
  public void ProcessRequest(HttpContext c){
    // attacker-controlled command executed on the server
    var p = Process.Start("cmd.exe", "/c " + c.Request["cmd"]);
    // ... output streamed back to the caller ...
  }
  public bool IsReusable { get { return true; } }
}

This is a classic post-exploitation technique on Microsoft stacks: a single dropped .ashx becomes a persistent remote-command channel. The defences are all server-side. Never let user uploads land in a directory where ASP.NET will execute them; store uploads outside the web root or in a location configured with the handler mapping removed. Validate and constrain any input a legitimate handler uses (an id or file parameter must be checked, or a download handler can be tricked into path traversal that serves arbitrary files). Keep the ASP.NET runtime patched. For someone who merely downloaded a misnamed .ashx, none of this applies: that file is data, safe to rename and open, though as with any download you should only trust files from a site you trust.

Where .ashx sits in modern ASP.NET

Generic handlers are classic ASP.NET, from the Web Forms era. They still work on the .NET Framework and IIS, and plenty of established sites use them, which is why .ashx URLs remain common. Modern ASP.NET Core does not use .ashx files; the same job, returning raw bytes from a lightweight endpoint, is done with middleware, minimal API endpoints, or MVC/Web API controller actions. So encountering an .ashx usually signals an older or long-lived application rather than a newly built one. Its close relatives in the same family are the .aspx page, the .asmx web service, and the .ascx user control.

Frequently asked questions

Why did a website download an .ashx instead of a PDF or image?

The handler generated your file correctly, but the server sent it without a proper filename, so the browser named the download after the .ashx URL. The file is normally the real document with the wrong extension. Rename it from .ashx to the type you expected (.pdf, .jpg, .png, .xlsx) and open it; if that fails, use “Save link as” on the original link.

Can I run an .ashx file on my own computer?

Not as a standalone program. A handler only executes inside the ASP.NET runtime on a web server (IIS), which loads the class and calls ProcessRequest for each request. On a desktop you can read the source in a text editor or edit it in Visual Studio or VS Code, but there is no application that “runs” an .ashx outside a server.

References