Anto Subash.

Published on

dotnet core large file upload with resume using tus and react/nextjs

Table of contents

Large file upload with dotnet and react with tus

In this post we will see how to do large file upload in chunks with resume capabilities in dotnet core as a backend and react/nextjs as frontend.

dotnet project

Create the .net project using this following command

1dotnet new webapp -n FileUpload -o .

Add tusdotnet nuget package

1dotnet add package tusdotnet --version 2.4.0

Enable Cors

Update the ConfigureServices

1services.AddCors();

Update Configure method

1app.UseCors(builder => builder
2        .AllowAnyHeader()
3        .AllowAnyMethod()
4        .AllowAnyOrigin()
5        .WithExposedHeaders(CorsHelper.GetExposedHeaders()));

Configure MaxRequestBodySize

Update Configure method and make sure this is the first pipeline request.

1app.Use((context, next) =>
2{
3    // Default limit was changed some time ago. Should work by setting MaxRequestBodySize to null using ConfigureKestrel but this does not seem to work for IISExpress.
4    // Source: https://github.com/aspnet/Announcements/issues/267
5    context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = null;
6    return next.Invoke();
7});

Configure tus

Update Configure method

1app.UseTus(httpContext => new DefaultTusConfiguration
2{
3    Store = new TusDiskStore(@"C:\tusfiles\"),
4    UrlPath = "/files",
5    Events = new Events
6    {
7        OnFileCompleteAsync = async eventContext =>
8        {
9            // eventContext.FileId is the id of the file that was uploaded.
10            // eventContext.Store is the data store that was used (in this case an instance of the TusDiskStore)
11
12            // A normal use case here would be to read the file and do some processing on it.
13            ITusFile file = await eventContext.GetFileAsync();
14            var result = await DoSomeProcessing(file, eventContext.CancellationToken).ConfigureAwait(false);
15
16            if (!result)
17            {
18                //throw new MyProcessingException("Something went wrong during processing");
19            }
20        }
21    }
22});

Make sure to put this before UseRouting and UseAuthorization

Nextjs App

Create next app

1yarn create next-app --typescript

Add tus package

1yarn add tus-js-client

Create file upload component

1import React from "react";
2import { Upload } from "tus-js-client";
3interface Props {}
4
5const FileUpload = (props: Props) => {
6  const onFileChange = (e: any) => {
7    var file = e.target.files[0];
8    const upload = new Upload(file, {
9      endpoint: "https://localhost:5001/files",
10      retryDelays: [0, 1000, 3000, 5000],
11      metadata: {
12        filename: file.name,
13        filetype: file.type,
14      },
15      onError: function (error) {
16        console.log("Failed because: " + error);
17      },
18      onProgress: function (bytesUploaded, bytesTotal) {
19        var percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
20        console.log(bytesUploaded, bytesTotal, percentage + "%");
21      },
22      onSuccess: function () {
23        console.log("Download %s from %s", upload.file.name, upload.url);
24      },
25    });
26
27    // Check if there are any previous uploads to continue.
28    upload.findPreviousUploads().then(function (previousUploads) {
29      // Found previous uploads so we select the first one.
30      if (previousUploads.length) {
31        upload.resumeFromPreviousUpload(previousUploads[0]);
32      }
33
34      // Start the upload
35      upload.start();
36    });
37  };
38  return (
39    <div className="text-center text-2xl p-6">
40      <input type="file" name="file" id="" onChange={onFileChange} />
41    </div>
42  );
43};
44
45export default FileUpload;

Add the component to the page.

1<FileUpload></FileUpload>

Github Repo: https://github.com/antosubash/LargeFileUploadSample