Udostępnij za pośrednictwem


pobieranie plików ASP.NET Core Blazor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak pobierać pliki w Blazor aplikacjach.

Operacje pobierania plików

W tym artykule opisano podejścia do następujących scenariuszy, w których plik nie powinien być otwierany przez przeglądarkę, ale pobierany i zapisywany na kliencie:

Podczas pobierania plików z innego źródła niż aplikacja mają zastosowanie zagadnienia dotyczące współużytkowania zasobów między źródłami (CORS). Aby uzyskać więcej informacji, zobacz sekcję Współużytkowanie zasobów między źródłami (CORS).

Zagadnienia dotyczące zabezpieczeń

Należy zachować ostrożność podczas zapewniania użytkownikom możliwości pobierania plików z serwera. Cyberataki mogą wykonywać ataki typu "odmowa usługi" , ataki wykorzystujące interfejs API lub próbować naruszyć bezpieczeństwo sieci i serwerów w inny sposób.

Kroki zabezpieczeń, które zmniejszają prawdopodobieństwo pomyślnego ataku, to:

  • Pobierz pliki z dedykowanego obszaru pobierania plików na serwerze, najlepiej z dysku innego niż system. Użycie dedykowanej lokalizacji ułatwia nakładanie ograniczeń zabezpieczeń na pliki do pobrania. Wyłącz uprawnienia wykonywania w obszarze pobierania pliku.
  • Kontrole zabezpieczeń po stronie klienta są łatwe do obejścia przez złośliwych użytkowników. Zawsze przeprowadzaj kontrole zabezpieczeń po stronie klienta na serwerze.
  • Nie odbieraj plików od użytkowników ani innych niezaufanych źródeł, a następnie udostępniaj pliki do natychmiastowego pobierania bez przeprowadzania kontroli zabezpieczeń plików. Aby uzyskać więcej informacji, zobacz Przekazywanie plików w programie ASP.NET Core.

Pobieranie ze strumienia

Ta sekcja dotyczy plików, które zazwyczaj mają rozmiar do 250 MB.

Zalecanym podejściem do pobierania stosunkowo małych plików (<250 MB) jest przesyłanie strumieniowe zawartości plików do nieprzetworzonego buforu danych binarnych na kliencie za pomocą międzyoperacyjnego języka JavaScript (JS). Takie podejście jest skuteczne w przypadku składników, które przyjmują interaktywny tryb renderowania, ale nie składniki, które przyjmują statyczne renderowanie po stronie serwera (statyczny przewodnik SSR).

Zalecanym podejściem do pobierania stosunkowo małych plików (<250 MB) jest przesyłanie strumieniowe zawartości plików do nieprzetworzonego buforu danych binarnych na kliencie za pomocą międzyoperacyjnego języka JavaScript (JS).

Ostrzeżenie

Podejście w tej sekcji odczytuje zawartość pliku do elementu JS ArrayBuffer. Takie podejście powoduje załadowanie całego pliku do pamięci klienta, co może obniżyć wydajność. Aby pobrać stosunkowo duże pliki (>= 250 MB), zalecamy wykonanie wskazówek w sekcji Pobieranie z adresu URL .

Następująca downloadFileFromStreamJS funkcja:

  • Odczytuje udostępniony strumień do elementu ArrayBuffer.
  • Tworzy obiekt w Blob celu opakowania .ArrayBuffer
  • Tworzy adres URL obiektu, który będzie służył jako adres pobierania pliku.
  • Tworzy element HTMLAnchorElement (<a> ).
  • Przypisuje nazwę pliku (fileName) i adres URL (url) do pobrania.
  • Wyzwala pobieranie, uruchamiając click zdarzenie w elemecie kotwicy.
  • Usuwa element kotwicy.
  • Odwołuje adres URL obiektu (url) przez wywołanie metody URL.revokeObjectURL. Jest to ważny krok, aby upewnić się, że pamięć nie wyciekła na kliencie.
<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>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

Następujący składnik:

  • Używa natywnego międzyoperacyjności przesyłania strumieniowego bajtów w celu zapewnienia wydajnego transferu pliku do klienta.
  • Ma metodę o nazwie GetFileStream , aby pobrać Stream plik pobrany do klientów. Alternatywne podejścia obejmują pobieranie pliku z magazynu lub dynamiczne generowanie pliku w kodzie języka C#. Na potrzeby tego pokazu aplikacja tworzy plik 50 KB danych losowych z nowej tablicy bajtów (new byte[]). Bajty są opakowane z wartością , MemoryStream która będzie służyć jako dynamicznie generowany plik binarny przykładu.
  • Metoda DownloadFileFromStream :
    • Pobiera element Stream z GetFileStream.
    • Określa nazwę pliku, gdy plik jest zapisywany na komputerze użytkownika. Poniższy przykład nazywa plik quote.txt.
    • Zawija element Stream w obiekcie DotNetStreamReference, który umożliwia przesyłanie strumieniowe danych plików do klienta.
    • Wywołuje funkcję w celu zaakceptowania danych na kliencie 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

<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);
    }
}

W przypadku składnika w aplikacji po stronie serwera, który musi zwrócić Stream element dla pliku fizycznego, składnik może wywołać metodę File.OpenRead, jak pokazano w poniższym przykładzie:

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

W poprzednim przykładzie {PATH} symbol zastępczy jest ścieżką do pliku. Prefiks @ wskazuje, że ciąg jest literałem ciągu dosłownego, który umożliwia użycie ukośników odwrotnych (\) w ścieżce systemu operacyjnego Windows i osadzonych podwójnych cudzysłowów ("") dla pojedynczego cudzysłowu w ścieżce. Alternatywnie należy unikać literału ciągu (@) i użyć jednej z następujących metod:

  • Użyj ukośników odwrotnych (\\) i cudzysłowów (\").
  • Użyj ukośników (/) w ścieżce, które są obsługiwane na różnych platformach w aplikacjach ASP.NET Core i cudzysłowów ucieczki (\").

Pobieranie z adresu URL

Ta sekcja dotyczy plików, które są stosunkowo duże, zazwyczaj 250 MB lub większe.

Zalecaną metodą pobierania stosunkowo dużych plików (>= 250 MB) z interaktywnie renderowanych składników lub plików o dowolnym rozmiarze statycznie renderowanych składników jest JS użycie do wyzwalania elementu kotwicy z nazwą i adresem URL pliku.

Zalecane podejście do pobierania stosunkowo dużych plików (>= 250 MB) polega na JS wyzwoleniu elementu kotwicy z nazwą i adresem URL pliku.

W przykładzie w tej sekcji jest używany plik pobierania o nazwie quote.txt, który znajduje się w folderze o nazwie files w katalogu głównym aplikacji (wwwroot folder). Korzystanie z files folderu jest przeznaczone tylko do celów demonstracyjnych. Pliki do pobrania można organizować w dowolnym układzie folderów w preferowanym folderze głównym (wwwroot folderze), w tym obsługiwać wwwroot pliki bezpośrednio z folderu.

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/p00vd5g2)
  Copyright 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/p00vd5g2)
  Copyright 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/p00vd5g2)
  Copyright 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/p00vd5g2)
  Copyright 1975 BBC (https://www.bbc.co.uk/)

Następująca triggerFileDownloadJS funkcja:

  • Tworzy element HTMLAnchorElement (<a> ).
  • Przypisuje nazwę pliku (fileName) i adres URL (url) do pobrania.
  • Wyzwala pobieranie, uruchamiając click zdarzenie w elemecie kotwicy.
  • Usuwa element kotwicy.
<script>
  window.triggerFileDownload = (fileName, url) => {
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
  }
</script>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

Poniższy przykładowy składnik pobiera plik z tego samego źródła, którego używa aplikacja. Jeśli próba pobrania pliku zostanie podjęta z innego źródła, skonfiguruj współużytkowanie zasobów między źródłami (CORS). Aby uzyskać więcej informacji, zobacz sekcję Współużytkowanie zasobów między źródłami (CORS).

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);
    }
}

W przypadku składników interaktywnych przycisk w poprzednim przykładzie wywołuje DownloadFileFromURL procedurę obsługi w celu wywołania funkcji triggerFileDownloadJavaScript (JS).

Jeśli składnik przyjmuje statyczne renderowanie po stronie serwera (statyczny przewodnik SSR), dodaj procedurę obsługi zdarzeń dla przycisku (addEventListenerdokumentacja MDN)), aby wywołać następujące triggerFileDownload wskazówki w ASP.NET Core Blazor JavaScript ze statycznym renderowaniem po stronie serwera (statyczne SSR).

@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);
    }
}

W przypadku składników interaktywnych przycisk w poprzednim przykładzie wywołuje DownloadFileFromURL procedurę obsługi w celu wywołania funkcji triggerFileDownloadJavaScript (JS).

Jeśli składnik przyjmuje statyczne renderowanie po stronie serwera (statyczny przewodnik SSR), dodaj procedurę obsługi zdarzeń dla przycisku (addEventListenerdokumentacja MDN)), aby wywołać następujące triggerFileDownload wskazówki w ASP.NET Core Blazor JavaScript ze statycznym renderowaniem po stronie serwera (statyczne SSR).

@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);
    }
}

Zmień port w poprzednim przykładzie, aby był zgodny z portem programowania localhost środowiska.

@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);
    }
}

Zmień port w poprzednim przykładzie, aby był zgodny z portem programowania localhost środowiska.

Udostępnianie zasobów z różnych źródeł (CORS)

Bez wykonywania dalszych kroków w celu włączenia współużytkowania zasobów między źródłami (CORS) dla plików, które nie mają tego samego źródła co aplikacja, pobieranie plików nie będzie przechodzić testów CORS wykonanych przez przeglądarkę.

Aby uzyskać więcej informacji na temat mechanizmu CORS z aplikacjami ASP.NET Core i innymi produktami i usługami firmy Microsoft hostujących pliki do pobrania, zobacz następujące zasoby:

Dodatkowe zasoby