Поделиться через


Скачивание файлов ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этой статье объясняется, как скачать файлы в Blazor приложениях.

Скачивание файлов

Файлы можно загрузить из собственных статических ресурсов приложения или из любого другого расположения:

  • ASP.NET приложения Core используют ПО промежуточного слоя статических файлов для обслуживания файлов клиентам серверных приложений.
  • Рекомендации в этой статье также относятся к другим типам файловых серверов, которые не используют .NET, например, к сетям доставки содержимого (CDN).

В этой статье рассматриваются подходы к следующим сценариям, в которых файл не должен быть открыт браузером, а скачан и сохранен на клиенте:

При скачивании файлов из источника, отличного от источника приложения, применяются правила общего доступа к ресурсам независимо от источника (CORS). Дополнительные сведения см. в разделе Общий доступ к ресурсам независимо от источника (CORS).

Вопросы безопасности

Необходимо соблюдать осторожность, если вы предоставляете пользователям возможность скачивать файлы с сервера. Злоумышленники могут выполнять атаки типа "отказ в обслуживании" (DoS), атаки на эксплуатацию API или пытаться скомпрометировать сети и серверы другими способами.

Ниже приведены некоторые действия по обеспечению безопасности, которые снижают вероятность успешных атак.

  • Скачивайте файлы из области, выделенной на сервере специально для скачиваемых файлов, желательно не на системном диске. Использование выделенного расположения упрощает применение мер безопасности к доступным для скачивания файлам. Отключите разрешения на выполнение для расположения отправки файлов.
  • Злоумышленникам легко обойти проверки безопасности на стороне клиента. Всегда выполняйте проверки безопасности на стороне клиента и на сервере.
  • Не получайте файлы от пользователей или других ненадежных источников и не делайте файлы доступными для немедленного скачивания без проверки безопасности файлов. Подробные сведения см. в статье Отправка файлов в ASP.NET Core.

Скачивание из потока

Этот раздел относится к файлам размером до 250 МБ.

Рекомендуемый подход к скачиванию относительно небольших файлов (< 250 МБ) заключается в потоковой передаче содержимого файла в буфер необработанных двоичных данных на клиенте с помощью взаимодействия с JavaScript (JS).

Предупреждение

Подход, описанный в этом разделе, позволяет считать содержимое файла в JS ArrayBuffer. При этом весь файл загружается в память клиента, что может снизить производительность. Чтобы скачать относительно большие файлы (>= 250 МБ), рекомендуется выполнить инструкции из раздела Скачивание по URL-адресу.

Следующая функция downloadFileFromStreamJS:

  • Чтение предоставленного потока в ArrayBuffer.
  • Создание Blob в качестве оболочки для ArrayBuffer.
  • Создает URL-адрес объекта, который будет служить адресом скачивания файла.
  • HTMLAnchorElement Создает элемент (<a>).
  • Назначает имя файла (fileName) и URL-адрес (url) для скачивания.
  • Активирует скачивание путем запуска click события в элементе привязки.
  • Удаляет элемент привязки.
  • Отменяет URL-адрес объекта (url) путем вызова URL.revokeObjectURL. Это важный шаг, позволяющий избежать утечки памяти на клиенте.
<script>
  window.downloadFileFromStream = async (fileName, contentStreamReference) => {
    const arrayBuffer = await contentStreamReference.arrayBuffer();
    const blob = new Blob([arrayBuffer]);
    const url = URL.createObjectURL(blob);
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
    URL.revokeObjectURL(url);
  }
</script>

Примечание.

Общие рекомендации по JS расположению и нашим рекомендациям для рабочих приложений см. в расположении JavaScript в приложениях ASP.NET CoreBlazor.

Приведенный ниже компонент делает следующее.

  • Использует собственный потоковый поток байтов для обеспечения эффективной передачи файла клиенту.
  • Имеет метод GetFileStream для получения файла Stream, скачиваемого на клиенты. Альтернативные подходы включают извлечение файла из хранилища или динамическое создание файла в коде C#. Для нашего демонстрационного примера приложение создает файл случайных данных размером 50 КБ из нового массива байтов (new byte[]). Эти байты упаковываются в MemoryStream, что дает нам пример динамически создаваемого двоичного файла.
  • Метод:DownloadFileFromStream
    • Извлекает Stream из GetFileStream.
    • Указывает имя файла при сохранении файла на компьютере пользователя. В следующем примере файлу присваивается имя quote.txt.
    • Заключает Stream в DotNetStreamReference, чтобы выполнить потоковую передачу файла клиенту.
    • Вызывает функцию downloadFileFromStreamJS , чтобы принять данные на клиенте.

FileDownload1.razor:

@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<PageTitle>File Download 1</PageTitle>

<h1>File Download Example 1</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<h1>File Download Example</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<h1>File Download Example</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}

Для компонента в серверном приложении, которое должно возвращать Stream физический файл, компонент может вызываться File.OpenRead, как показано в следующем примере:

private Stream GetFileStream()
{
    return File.OpenRead(@"{PATH}");
}

В предыдущем примере заполнитель {PATH} — это путь к файлу. Префикс @ указывает, что строка является буквальным строковым литералом, что позволяет использовать обратную косые черты (\) в пути ОС Windows и встроенные двойные кавычки ("") для одинарной кавычки в пути. Кроме того, избегайте строкового литерала (@) и используйте любой из следующих подходов:

  • Используйте экранированные обратные косые черты (\\) и кавычки (\").
  • Используйте косые черты (/) в пути, что поддерживаются на разных платформах в приложениях ASP.NET Core, а также экранированные кавычки (\").

Скачивание по URL-адресу

Этот раздел относится к файлам, которые относительно большие, обычно 250 МБ или больше.

В примере в этом разделе используется скачиваемый файл quote.txt, который находится в папке files в корневом каталоге веб-приложения (папка wwwroot). Папка files используется только для демонстрации. Вы можете упорядочивать скачиваемые файлы в любом расположении папок внутри корневого веб-сайта (папка wwwroot), которое вы предпочитаете, включая предоставление файлов непосредственно из папки wwwroot.

wwwroot/files/quote.txt:

When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00pq2gc)
  ©1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00pq2gc)
  ©1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00pq2gc)
  ©1975 BBC (https://www.bbc.co.uk/)

Следующая функция triggerFileDownloadJS:

  • HTMLAnchorElement Создает элемент (<a>).
  • Назначает имя файла (fileName) и URL-адрес (url) для скачивания.
  • Активирует скачивание путем запуска click события в элементе привязки.
  • Удаляет элемент привязки.
<script>
  window.triggerFileDownload = (fileName, url) => {
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
  }
</script>

Примечание.

Общие рекомендации по JS расположению и нашим рекомендациям для рабочих приложений см. в расположении JavaScript в приложениях ASP.NET CoreBlazor.

В следующем примере компонент скачивает файл из источника приложения. Если попытка скачать файл выполняется из другого источника, настройте общий доступ к ресурсам независимо от источника (CORS). Дополнительные сведения см. в разделе Общий доступ к ресурсам независимо от источника (CORS).

Измените порт в следующем примере, чтобы он соответствовал порту разработки localhost среды.

FileDownload2.razor:

@page "/file-download-2"
@inject IJSRuntime JS

<PageTitle>File Download 2</PageTitle>

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}
@page "/file-download-2"
@inject IJSRuntime JS

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "https://localhost:5001/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}
@page "/file-download-2"
@inject IJSRuntime JS

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "https://localhost:5001/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}

Общий доступ к ресурсам между источниками (CORS)

Без дальнейших шагов по включению общего доступа к ресурсам независимо от источника (CORS) для файлов, которые не имеют того же происхождения, что и приложение, скачиваемые файлы не будут проходить проверки CORS, сделанные браузером.

Дополнительные сведения о CORS с приложениями ASP.NET Core и другими продуктами и службами Microsoft, в которых размещаются файлы для загрузки, см. в следующих ресурсах:

Дополнительные ресурсы