Serving dynamic files with Blazor in ASP.NET

Contents

One of the many great features of frames like Blazor and ASP.NET (in which it runs) is the ability to deliver dynamic content to any endpoint your application needs. If you want to serve generated file downloads, it's easy to do with a little configuration.

Why serve dynamic files?

Simply, you have two options as a web server: respond to a request with static content, as an HTML page or a JPG file, or generate a custom response to send to the user. Blazor runs on ASP.NET, so the built-in HTTP server supports a wide range of alternatives and enables great flexibility.

As an example, maybe you want to host a JSON file in /images/pathname.json. It doesn't have to be a literal file on disk; the server can interpret this request and respond with any type of content, included something unexpected like a PNG file. You can respond to this request by getting some results from an API, creating a response and sending the string back to the user.

Or maybe you would like to generate the actual file on the fly. As an example, there are many graphics libraries used to draw custom images. You can use one of these to generate an image and respond to the user's request with the data, all in memory.

In the latter case, it may make sense to cache the solution by saving it to disk and responding with a real file most of the time. This can be useful for generations of files that are resource intensive and do not change as often..

Configure

File service like this is built in and quite simple to do. You will need to create a new Razor page, what is Blazor It executes in. You can do this by right-clicking in Visual Studio and selecting Add> Razor Page.

By doing this, two files are created that are linked to each other in the hierarchy: Name.cshtml, which handles the HTML side of things, and Name.cshtml.cs, which handles the model and the actual code. Since this will not be a real web page, just one file, you can ignore the first one for the most part.

Despite this, you will need to configure the @page attribute to match where you want this file to be hosted. You probably want to include some wildcards, what you do with brackets.

At Name.cshtml.cs file, you will see a real code that extends PageModel. The main function here is OnGet(), which you will probably want to change to OnGetAsync() if you are doing any asynchronous processing.

You have three main options of this feature. First, is returning a PhysicalFile, which literally reads a file on disk given a path and sends it to the user with a type, optionally with a different download name than the actual path.

Although it is likely here to generate something dynamically, this can be very useful for caching. If your render function saves the result to a file, you can check if that file exists before processing it again, and if it does, just return the cached solution.

The next option is to return a virtual file, given a byte array. This is what you will want to use for most applications, since it works absolutely on memory and should be very fast.

Depending on the encoding you are trying to use, you might want to convert a string to a byte array using the Encoding helper class.

Encoding.UTF8.GetBytes(string);

Finally, can return a content string directly, what to use if you want to show the content to the user instead of triggering a download in their browser.

There are other options at the same time of these three, but the rest involves responding with status codes, redirect, unauthorized responses and render the page itself.

File delivery according to paths and parameters

Of course, none of this is useful if you can't respond to requests supported by user input. The two alternatives for input are in the URL: routing parameters and url parameters. The routing parameters are the ones you specified via wildcards on the page itself and are the actual path to the file. URL parameters are optional.

Finding out this can be a bit tricky, but luckily you have a debugger by your side, so you can determine a breakpoint at OnGetAsync() and see the whole tree of local variables.

You'll find, below this.PageContext.RouteData, there is a RouteValueDictionary<string, object> which stores all routes. Note that this includes the path of the page itself, so if you used /Download/{param} as route, the param will be the second option.

The best way to get the parameters is to search them by key:

In the same way, query parameters are also available, even when from a different object. You will need to enter HttpContext.Request.Query, which is a QueryValueDictionary which contains the url parameters, and it works the same way as the path.

Next, you can use these parameters to perform searches or affect logic. Despite this, if you are caching responses, you'll want to make sure your cache and search conditions are also affected by these parameters, or you could have problems with unexpected caching behaviors.

Subscribe to our Newsletter

We will not send you SPAM mail. We hate it as much as you.