ASP.NET Core Blazor dosyası karşıya yüklemeleri

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Bu makalede, bileşenle birlikte dosyaları Blazor karşıya yükleme işlemi InputFile açıklanmaktadır.

Dosya karşıya yüklemeleri

Uyarı

Kullanıcıların dosyaları karşıya yüklemesine izin verilirken her zaman en iyi güvenlik yöntemlerini izleyin. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

InputFile Tarayıcı dosya verilerini .NET koduna okumak için bileşenini kullanın. InputFile Bileşen, türünde filebir HTML <input> öğesi işler. Varsayılan olarak, kullanıcı tek dosyaları seçer. multiple Kullanıcının aynı anda birden çok dosya yüklemesine izin vermek için özniteliğini ekleyin.

Bir bileşen veya temel HTML <input type="file">kullanılırken InputFile dosya seçimi birikmeli olmadığından, var olan bir dosya seçimine dosya ekleyemezsiniz. Bileşen her zaman kullanıcının ilk dosya seçiminin yerini alır, bu nedenle önceki seçimlerden dosya başvuruları kullanılamaz.

() olayı gerçekleştiğinde LoadFiles aşağıdaki InputFile bileşen yöntemini OnChangechangeyürütür. , InputFileChangeEventArgs seçili dosya listesine ve her dosyayla ilgili ayrıntılara erişim sağlar:

<InputFile OnChange="LoadFiles" multiple />

@code {
    private void LoadFiles(InputFileChangeEventArgs e)
    {
        ...
    }
}

İşlenen HTML:

<input multiple="" type="file" _bl_2="">

Not

Yukarıdaki örnekte, öğesinin <input>_bl_2 özniteliği iç işleme için Blazorkullanılır.

Kullanıcı tarafından seçilen bir dosyadaki verileri okumak için, dosyayı arayın IBrowserFile.OpenReadStream ve döndürülen akıştan okuyun. Daha fazla bilgi için Dosya akışları bölümüne bakın.

OpenReadStream bayt cinsinden en büyük boyutu zorlar Stream. Bir dosya veya 500 KB'tan büyük birden çok dosyanın okunması özel durumla sonuçlandı. Bu sınır, geliştiricilerin yanlışlıkla büyük dosyaları belleğe okumasını engeller. maxAllowedSize parametresiOpenReadStream, gerekirse daha büyük bir boyut belirtmek için kullanılabilir.

Dosyanın baytlarını temsil eden bir Stream öğesine erişmeniz gerekiyorsa kullanın IBrowserFile.OpenReadStream. Gelen dosya akışını bir kerede doğrudan belleğe okumaktan kaçının. Örneğin, dosyanın tüm baytlarını bir MemoryStream içine kopyalamayın veya akışın tamamını aynı anda bayt dizisine okumayın. Bu yaklaşımlar, özellikle sunucu tarafı bileşenleri için performans ve güvenlik sorunlarına neden olabilir. Bunun yerine, aşağıdaki yaklaşımlardan birini benimsemeyi göz önünde bulundurun:

  • Akışı belleğe okumadan doğrudan disk üzerindeki bir dosyaya kopyalayın. Blazor Sunucuda kod yürüten uygulamaların istemcinin dosya sistemine doğrudan erişemeyeceğini unutmayın.
  • dosyaları istemciden doğrudan bir dış hizmete yükleyin. Daha fazla bilgi için Dosyaları dış hizmete yükleme bölümüne bakın.

Aşağıdaki örneklerde, browserFile karşıya yüklenen dosyayı temsil eder ve uygular IBrowserFile. için IBrowserFile çalışan uygulamalar, bu makalenin devamında dosya yükleme bileşenlerinde gösterilir.

Desteklenmiyor: Dosyanın içeriği bir String bellektereader () okunduğu için aşağıdaki yaklaşım ÖNERILMEZStream:

var reader = 
    await new StreamReader(browserFile.OpenReadStream()).ReadToEndAsync();

Desteklenmiyor: Aşağıdaki yaklaşım Microsoft Azure Blob Depolama için önerilmez çünkü dosyanın Stream içeriği çağrılmadan UploadBlobAsyncönce bir MemoryStream bellekte (memoryStream) kopyalanır:

var memoryStream = new MemoryStream();
await browserFile.OpenReadStream().CopyToAsync(memoryStream);
await blobContainerClient.UploadBlobAsync(
    trustedFileName, memoryStream));

Aşağıdaki yaklaşım önerilir çünkü dosyanınkiler Stream doğrudan tüketiciye sağlanır ve sağlanan yolda dosyayı oluşturan bir FileStream yöntemdir:

await using FileStream fs = new(path, FileMode.Create);
await browserFile.OpenReadStream().CopyToAsync(fs);

Desteklenir: Aşağıdaki yaklaşım Microsoft Azure Blob Depolama için önerilir çünkü dosyanınkiler Stream doğrudan öğesine UploadBlobAsyncsağlanır:

await blobContainerClient.UploadBlobAsync(
    trustedFileName, browserFile.OpenReadStream());

Görüntü dosyası alan bir bileşen, görüntü uygulamaya akışla aktarilmeden önce tarayıcının JavaScript çalışma zamanı içindeki görüntü verilerini yeniden boyutlandırmak için dosyada kolaylık yöntemini çağırabilir BrowserFileExtensions.RequestImageFileAsync . Arama RequestImageFileAsync için kullanım örnekleri en çok uygulamalar için Blazor WebAssembly uygundur.

Dosya boyutu okuma ve karşıya yükleme sınırları

Sunucu tarafı veya istemci tarafı, özellikle bileşen için InputFile dosya okuma veya karşıya yükleme boyutu sınırı yoktur. Ancak istemci tarafı Blazor , verileri JavaScript'ten C# 'ye (2 GB veya cihazın kullanılabilir belleğiyle sınırlı) sıralarken dosyanın baytlarını tek bir JavaScript dizi arabelleğine okur. Büyük dosya yüklemeleri (> 250 MB), bileşeni kullanan InputFile istemci tarafı karşıya yüklemeleri için başarısız olabilir. Daha fazla bilgi için aşağıdaki tartışmalara bakın:

Bileşen için InputFile desteklenen dosya boyutu üst sınırı 2 GB'tır. Ayrıca istemci tarafı Blazor , verileri JavaScript'ten 2 GB veya cihazın kullanılabilir belleğiyle sınırlı olan C# öğesine sıralarken dosyanın baytlarını tek bir JavaScript dizi arabelleğine okur. Büyük dosya yüklemeleri (> 250 MB), bileşeni kullanan InputFile istemci tarafı karşıya yüklemeleri için başarısız olabilir. Daha fazla bilgi için aşağıdaki tartışmalara bakın:

Bileşeni kullanmaya çalışırken başarısız olan büyük istemci tarafı dosya yüklemeleri için, bileşeni kullanmak InputFileInputFile yerine birden çok HTTP aralığı isteği kullanarak büyük dosyaları özel bir bileşenle öbeklemenizi öneririz.

İstemci tarafı dosya boyutu karşıya yükleme sınırlamasını ele almak için çalışma şu anda .NET 9 (2024 sonu) için zamanlanmıştır.

Örnekler

Aşağıdaki örneklerde bir bileşende birden çok dosya karşıya yükleme gösterilmektedir. InputFileChangeEventArgs.GetMultipleFiles birden çok dosya okumaya izin verir. Kötü amaçlı bir kullanıcının uygulamanın beklediğinden daha fazla sayıda dosya yüklemesini önlemek için en fazla dosya sayısını belirtin. InputFileChangeEventArgs.File , dosya yükleme işlemi birden çok dosyayı desteklemiyorsa ilk ve tek dosyanın okunmasına izin verir.

InputFileChangeEventArgsgenellikle uygulamanın _Imports.razor dosyasındaki Microsoft.AspNetCore.Components.Forms ad alanlarından biri olan ad alanındadır. Ad alanı dosyada _Imports.razor mevcut olduğunda, uygulamanın bileşenlerine API üyesi erişimi sağlar.

Dosyadaki _Imports.razor ad alanları C# dosyalarına (.cs ) uygulanmaz. C# dosyaları, sınıf dosyasının en üstünde açık using bir yönerge gerektirir:

using Microsoft.AspNetCore.Components.Forms;

Dosya karşıya yükleme bileşenlerini test etme için PowerShell ile her boyutta test dosyası oluşturabilirsiniz:

$out = new-object byte[] {SIZE}; (new-object Random).NextBytes($out); [IO.File]::WriteAllBytes('{PATH}', $out)

Yukarıdaki komutta:

  • Yer {SIZE} tutucu, dosyanın bayt cinsinden boyutudur (örneğin, 2097152 2 MB'lık bir dosya için).
  • Yer {PATH} tutucu, dosya uzantısı olan yol ve dosyadır (örneğin, D:/test_files/testfile2MB.txt).

Sunucu tarafı dosya yükleme örneği

Aşağıdaki kodu kullanmak için, ortamda çalışan uygulamanın kökünde Development bir Development/unsafe_uploads klasör oluşturun.

Örnek, dosyaların kaydedildiği yolun bir parçası olarak uygulamanın ortamını kullandığından, test ve üretimde diğer ortamlar kullanılıyorsa ek klasörler gerekir. Örneğin, ortam için Staging bir Staging/unsafe_uploads klasör oluşturun. Ortam için Production bir Production/unsafe_uploads klasör oluşturun.

Uyarı

Örnek, dosyaları içeriklerini taramadan kaydeder ve bu makaledeki yönergeler karşıya yüklenen dosyalar için ek güvenlik en iyi yöntemlerini hesaba katmıyor. Hazırlama ve üretim sistemlerinde karşıya yükleme klasöründe yürütme iznini devre dışı bırakın ve karşıya yüklemeden hemen sonra dosyaları virüsten koruma/kötü amaçlı yazılımdan koruma tarayıcı API'siyle tarayın. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

FileUpload1.razor:

@page "/file-upload-1"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@inject ILogger<FileUpload1> Logger
@inject IWebHostEnvironment Environment

<PageTitle>File Upload 1</PageTitle>

<h1>File Upload Example 1</h1>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                var trustedFileName = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                    Environment.EnvironmentName, "unsafe_uploads",
                    trustedFileName);

                await using FileStream fs = new(path, FileMode.Create);
                await file.OpenReadStream(maxFileSize).CopyToAsync(fs);

                loadedFiles.Add(file);

                Logger.LogInformation(
                    "Unsafe Filename: {UnsafeFilename} File saved: {Filename}",
                    file.Name, trustedFileName);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);

                var trustedFileNameForFileStorage = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                        Environment.EnvironmentName, "unsafe_uploads",
                        trustedFileNameForFileStorage);

                await using FileStream fs = new(path, FileMode.Create);
                await file.OpenReadStream(maxFileSize).CopyToAsync(fs);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);

                var trustedFileNameForFileStorage = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                        Environment.EnvironmentName, "unsafe_uploads",
                        trustedFileNameForFileStorage);

                await using FileStream fs = new(path, FileMode.Create);
                await file.OpenReadStream(maxFileSize).CopyToAsync(fs);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);

                var trustedFileNameForFileStorage = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                        Environment.EnvironmentName, "unsafe_uploads",
                        trustedFileNameForFileStorage);

                await using FileStream fs = new(path, FileMode.Create);
                await file.OpenReadStream(maxFileSize).CopyToAsync(fs);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}

İstemci tarafı dosya yükleme örneği

Aşağıdaki örnek dosya baytlarını işler ve uygulama dışındaki bir hedefe dosya göndermez. Sunucuya veya hizmete dosya gönderen bir bileşen örneği Razor için aşağıdaki bölümlere bakın:

Bileşen, Interactive WebAssembly işleme modunun (InteractiveWebAssembly) bir üst bileşenden devralındığını veya uygulamaya genel olarak uygulandığını varsayar.

@page "/file-upload-1"
@inject ILogger<FileUpload1> Logger

<PageTitle>File Upload 1</PageTitle>

<h1>File Upload Example 1</h1>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private void LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {FileName} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private void LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {FileName} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private void LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-1"
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload1> Logger

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Uploading...</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;

    private void LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}

IBrowserFiletarayıcı tarafından sunulan meta verileri özellik olarak döndürür. Ön doğrulama için bu meta verileri kullanın.

Önceki özelliklerin değerlerine, özellikle de Name kullanıcı arabiriminde görüntülenme özelliğine asla güvenmeyin. Kullanıcı tarafından sağlanan tüm verileri uygulama, sunucu ve ağ için önemli bir güvenlik riski olarak değerlendirin. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

Sunucu tarafı işleme ile dosyaları sunucuya yükleme

Bu bölüm, Web Apps'teki Blazor Etkileşimli Sunucu bileşenleri için geçerlidir.

Bu bölüm uygulamalar için Blazor Server geçerlidir.

Aşağıdaki örnekte, bir sunucu tarafı uygulamasından arka uç web API'sinin denetleyicisine ayrı bir uygulamada(muhtemelen ayrı bir sunucuda) dosya yükleme işlemi gösterilmektedir.

Sunucu tarafı uygulamasının dosyasında, uygulamanın Program örnek oluşturmasına HttpClient izin veren ve ilgili hizmetleri ekleyinIHttpClientFactory:

builder.Services.AddHttpClient();

Daha fazla bilgi için, bkz. ASP.NET Core'da IHttpClientFactory kullanarak HTTP isteği yapma.

Bu bölümdeki örnekler için:

  • Web API'si URL'de çalışır: https://localhost:5001
  • Sunucu tarafı uygulaması URL'de çalışır: https://localhost:5003

Test için, önceki URL'ler projelerin Properties/launchSettings.json dosyalarında yapılandırılır.

Aşağıdaki UploadResult sınıf, karşıya yüklenen bir dosyanın sonucunu korur. Bir dosya sunucuya yüklenemediğinde, kullanıcıya görüntülenmesi için içinde ErrorCode bir hata kodu döndürülür. Her dosya için sunucuda güvenli bir dosya adı oluşturulur ve görüntülenmek üzere istemciye StoredFileName döndürülür. Dosyalar, içinde güvenli olmayan/güvenilmeyen dosya adı FileNamekullanılarak istemci ile sunucu arasında anahtarlanır.

UploadResult.cs:

public class UploadResult
{
    public bool Uploaded { get; set; }
    public string? FileName { get; set; }
    public string? StoredFileName { get; set; }
    public int ErrorCode { get; set; }
}

Not

Üretim uygulamaları için en iyi güvenlik uygulaması, istemcilere uygulama, sunucu veya ağ hakkındaki hassas bilgileri ortaya çıkarabilecek hata iletileri göndermekten kaçınmaktır. Ayrıntılı hata iletileri sağlamak, kötü amaçlı bir kullanıcının uygulama, sunucu veya ağ üzerindeki saldırıları geliştirmelerine yardımcı olabilir. Bu bölümdeki örnek kod, yalnızca sunucu tarafı hatası oluşursa bileşen istemci tarafı tarafından görüntülenmesi için bir hata kodu numarası (int) gönderir. Bir kullanıcı dosya yükleme konusunda yardıma ihtiyaç duyarsa, hatanın tam nedenini bilmeden destek bileti çözümü için destek personeline hata kodunu sağlar.

Aşağıdaki FileUpload2 bileşen:

  • Kullanıcıların istemciden dosya yüklemesine izin verir.
  • kullanıcı arabiriminde istemci tarafından sağlanan güvenilmeyen/güvenli olmayan dosya adını görüntüler. Güvenilmeyen/güvenli olmayan dosya adı, kullanıcı arabiriminde güvenli görüntü için tarafından Razor otomatik olarak HTML ile kodlanır.

Uyarı

İstemciler tarafından sağlanan dosya adlara güvenmeyin:

  • Dosyayı bir dosya sistemine veya hizmete kaydetme.
  • Dosya adlarını otomatik olarak veya geliştirici kodu aracılığıyla kodlamamış OLAN UI'lerde görüntüleyin.

Bir sunucuya dosya yüklerken dikkat edilmesi gereken güvenlik konuları hakkında daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

FileUpload2.razor:

@page "/file-upload-2"
@using System.Net.Http.Headers
@using System.Text.Json
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<PageTitle>File Upload 2</PageTitle>

<h1>File Upload Example 2</h1>

<p>
    This example requires a backend server API to function. For more information, 
    see the <em>Upload files to a server</em> section 
    of the <em>ASP.NET Core Blazor file uploads</em> article.
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var client = ClientFactory.CreateClient();

            var response = 
                await client.PostAsync("https://localhost:5001/Filesave", 
                content);

            if (response.IsSuccessStatusCode)
            {
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true,
                };

                using var responseStream =
                    await response.Content.ReadAsStreamAsync();

                var newUploadResults = await JsonSerializer
                    .DeserializeAsync<IList<UploadResult>>(responseStream, options);

                if (newUploadResults is not null)
                {
                    uploadResults = uploadResults.Concat(newUploadResults).ToList();
                }
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var client = ClientFactory.CreateClient();

            var response = 
                await client.PostAsync("https://localhost:5001/Filesave", 
                content);

            if (response.IsSuccessStatusCode)
            {
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true,
                };

                using var responseStream =
                    await response.Content.ReadAsStreamAsync();

                var newUploadResults = await JsonSerializer
                    .DeserializeAsync<IList<UploadResult>>(responseStream, options);

                if (newUploadResults is not null)
                {
                    uploadResults = uploadResults.Concat(newUploadResults).ToList();
                }
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var client = ClientFactory.CreateClient();

            var response = 
                await client.PostAsync("https://localhost:5001/Filesave", 
                content);

            if (response.IsSuccessStatusCode)
            {
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true,
                };

                using var responseStream =
                    await response.Content.ReadAsStreamAsync();

                var newUploadResults = await JsonSerializer
                    .DeserializeAsync<IList<UploadResult>>(responseStream, options);

                if (newUploadResults is not null)
                {
                    uploadResults = uploadResults.Concat(newUploadResults).ToList();
                }
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var client = ClientFactory.CreateClient();

            var response = 
                await client.PostAsync("https://localhost:5001/Filesave", 
                content);

            if (response.IsSuccessStatusCode)
            {
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true,
                };

                using var responseStream =
                    await response.Content.ReadAsStreamAsync();

                var newUploadResults = await JsonSerializer
                    .DeserializeAsync<IList<UploadResult>>(responseStream, options);

                uploadResults = uploadResults.Concat(newUploadResults).ToList();
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName);

        if (result is null)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result = new();
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string Name { get; set; }
    }
}

Web API projesindeki aşağıdaki denetleyici, istemciden karşıya yüklenen dosyaları kaydeder.

Önemli

Bu bölümdeki denetleyici, uygulamadan ayrı bir web API'sinde Blazor kullanılmak üzere tasarlanmıştır. Dosya yükleme kullanıcılarının kimliği doğrulanırsa web API'sinin Siteler Arası İstek Sahteciliği (XSRF/CSRF) saldırılarını azaltması gerekir.

Not

.NET 6'da ASP.NET Core'daki Minimum API'ler için özniteliğine sahip [FromForm] form değerlerini bağlama yerel olarak desteklenmez. Bu nedenle, aşağıdaki Filesave denetleyici örneği Minimum API'leri kullanacak şekilde dönüştürülemez. Minimum API'lere sahip form değerlerinden bağlama desteği ,NET 7 veya sonraki sürümlerde ASP.NET Core'da kullanılabilir.

Aşağıdaki kodu kullanmak için, ortamda çalışan uygulamanın web API'sinin projesinin kökünde Development bir Development/unsafe_uploads klasör oluşturun.

Örnek, dosyaların kaydedildiği yolun bir parçası olarak uygulamanın ortamını kullandığından, test ve üretimde diğer ortamlar kullanılıyorsa ek klasörler gerekir. Örneğin, ortam için Staging bir Staging/unsafe_uploads klasör oluşturun. Ortam için Production bir Production/unsafe_uploads klasör oluşturun.

Uyarı

Örnek, dosyaları içeriklerini taramadan kaydeder ve bu makaledeki yönergeler karşıya yüklenen dosyalar için ek güvenlik en iyi yöntemlerini hesaba katmıyor. Hazırlama ve üretim sistemlerinde karşıya yükleme klasöründe yürütme iznini devre dışı bırakın ve karşıya yüklemeden hemen sonra dosyaları virüsten koruma/kötü amaçlı yazılımdan koruma tarayıcı API'siyle tarayın. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

Controllers/FilesaveController.cs:

using System.Net;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("[controller]")]
public class FilesaveController : ControllerBase
{
    private readonly IHostEnvironment env;
    private readonly ILogger<FilesaveController> logger;

    public FilesaveController(IHostEnvironment env, 
        ILogger<FilesaveController> logger)
    {
        this.env = env;
        this.logger = logger;
    }

    [HttpPost]
    public async Task<ActionResult<IList<UploadResult>>> PostFile(
        [FromForm] IEnumerable<IFormFile> files)
    {
        var maxAllowedFiles = 3;
        long maxFileSize = 1024 * 15;
        var filesProcessed = 0;
        var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/");
        List<UploadResult> uploadResults = new();

        foreach (var file in files)
        {
            var uploadResult = new UploadResult();
            string trustedFileNameForFileStorage;
            var untrustedFileName = file.FileName;
            uploadResult.FileName = untrustedFileName;
            var trustedFileNameForDisplay =
                WebUtility.HtmlEncode(untrustedFileName);

            if (filesProcessed < maxAllowedFiles)
            {
                if (file.Length == 0)
                {
                    logger.LogInformation("{FileName} length is 0 (Err: 1)",
                        trustedFileNameForDisplay);
                    uploadResult.ErrorCode = 1;
                }
                else if (file.Length > maxFileSize)
                {
                    logger.LogInformation("{FileName} of {Length} bytes is " +
                        "larger than the limit of {Limit} bytes (Err: 2)",
                        trustedFileNameForDisplay, file.Length, maxFileSize);
                    uploadResult.ErrorCode = 2;
                }
                else
                {
                    try
                    {
                        trustedFileNameForFileStorage = Path.GetRandomFileName();
                        var path = Path.Combine(env.ContentRootPath,
                            env.EnvironmentName, "unsafe_uploads",
                            trustedFileNameForFileStorage);

                        await using FileStream fs = new(path, FileMode.Create);
                        await file.CopyToAsync(fs);

                        logger.LogInformation("{FileName} saved at {Path}",
                            trustedFileNameForDisplay, path);
                        uploadResult.Uploaded = true;
                        uploadResult.StoredFileName = trustedFileNameForFileStorage;
                    }
                    catch (IOException ex)
                    {
                        logger.LogError("{FileName} error on upload (Err: 3): {Message}",
                            trustedFileNameForDisplay, ex.Message);
                        uploadResult.ErrorCode = 3;
                    }
                }

                filesProcessed++;
            }
            else
            {
                logger.LogInformation("{FileName} not uploaded because the " +
                    "request exceeded the allowed {Count} of files (Err: 4)",
                    trustedFileNameForDisplay, maxAllowedFiles);
                uploadResult.ErrorCode = 4;
            }

            uploadResults.Add(uploadResult);
        }

        return new CreatedResult(resourcePath, uploadResults);
    }
}

Yukarıdaki kodda, GetRandomFileName güvenli bir dosya adı oluşturmak için çağrılır. Bir saldırgan, var olan bir dosyanın üzerine yazan veya uygulamanın dışına yazmaya çalışan bir yol gönderen mevcut bir dosya adını seçeebileceği için, tarayıcı tarafından sağlanan dosya adına asla güvenmeyin.

Sunucu uygulamasının denetleyici hizmetlerini ve eşleme denetleyicisi uç noktalarını kaydetmesi gerekir. Daha fazla bilgi için bkz . ASP.NET Core'da denetleyici eylemlerine yönlendirme.

Dosyaları sunucuya yükleme

Aşağıdaki örnekte bir web API denetleyicisine dosya yükleme işlemi gösterilmektedir.

Aşağıdaki UploadResult sınıf, karşıya yüklenen bir dosyanın sonucunu korur. Bir dosya sunucuya yüklenemediğinde, kullanıcıya görüntülenmesi için içinde ErrorCode bir hata kodu döndürülür. Her dosya için sunucuda güvenli bir dosya adı oluşturulur ve görüntülenmek üzere istemciye StoredFileName döndürülür. Dosyalar, içinde güvenli olmayan/güvenilmeyen dosya adı FileNamekullanılarak istemci ile sunucu arasında anahtarlanır.

UploadResult.cs:

public class UploadResult
{
    public bool Uploaded { get; set; }
    public string? FileName { get; set; }
    public string? StoredFileName { get; set; }
    public int ErrorCode { get; set; }
}

Not

Önceki UploadResult sınıf istemci ve sunucu tabanlı projeler arasında paylaşılabilir. İstemci ve sunucu projeleri sınıfı paylaştığında, paylaşılan proje için her projenin _Imports.razor dosyasına bir içeri aktarma ekleyin. Örneğin:

@using BlazorSample.Shared

Aşağıdaki FileUpload2 bileşen:

  • Kullanıcıların istemciden dosya yüklemesine izin verir.
  • kullanıcı arabiriminde istemci tarafından sağlanan güvenilmeyen/güvenli olmayan dosya adını görüntüler. Güvenilmeyen/güvenli olmayan dosya adı, kullanıcı arabiriminde güvenli görüntü için tarafından Razor otomatik olarak HTML ile kodlanır.

Üretim uygulamaları için en iyi güvenlik uygulaması, istemcilere uygulama, sunucu veya ağ hakkındaki hassas bilgileri ortaya çıkarabilecek hata iletileri göndermekten kaçınmaktır. Ayrıntılı hata iletileri sağlamak, kötü amaçlı bir kullanıcının uygulama, sunucu veya ağ üzerindeki saldırıları geliştirmelerine yardımcı olabilir. Bu bölümdeki örnek kod, yalnızca sunucu tarafı hatası oluşursa bileşen istemci tarafı tarafından görüntülenmesi için bir hata kodu numarası (int) gönderir. Bir kullanıcı dosya yükleme konusunda yardıma ihtiyaç duyarsa, hatanın tam nedenini bilmeden destek bileti çözümü için destek personeline hata kodunu sağlar.

Uyarı

İstemciler tarafından sağlanan dosya adlara güvenmeyin:

  • Dosyayı bir dosya sistemine veya hizmete kaydetme.
  • Dosya adlarını otomatik olarak veya geliştirici kodu aracılığıyla kodlamamış OLAN UI'lerde görüntüleyin.

Bir sunucuya dosya yüklerken dikkat edilmesi gereken güvenlik konuları hakkında daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

Web Uygulaması ana projesindeBlazor, projenin Program dosyasına ve ilgili hizmetleri ekleyinIHttpClientFactory:

builder.Services.AddHttpClient();

HttpClient İstemci tarafı bileşeni sunucuda önceden depolandığından, hizmetler ana projeye eklenmelidir. Aşağıdaki bileşen için ön kayıt özelliğini devre dışı bırakırsanız, hizmetleri ana uygulamada sağlamanız HttpClient gerekmez ve önceki satırı ana projeye eklemeniz gerekmez.

ASP.NET Core uygulamasına hizmet ekleme HttpClient hakkında daha fazla bilgi için bkz . ASP.NET Core'da IHttpClientFactory kullanarak HTTP istekleri oluşturma.

Bir Web Uygulamasının Blazor istemci projesinin (.Client) bir arka uç web API denetleyicisine HTTP POST istekleri için de kaydetmesi HttpClient gerekir. İstemci projesinin Program dosyasına aşağıdakileri onaylayın veya ekleyin:

builder.Services.AddScoped(sp => 
    new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

Yukarıdaki örnek, uygulamanın temel adresini alan ve genellikle ana bilgisayar sayfasındaki etiketin href değerinden <base> türetilen temel adresi ()IWebAssemblyHostEnvironment.BaseAddress ile builder.HostEnvironment.BaseAddress ayarlar. Dış web API'sini çağırıyorsanız URI'yi web API'sinin temel adresine ayarlayın.

Bir Web Uygulamasında aşağıdaki bileşenin Blazor en üstünde Interactive WebAssembly işleme modu özniteliğini belirtin:

@rendermode InteractiveWebAssembly

FileUpload2.razor:

@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@inject HttpClient Http
@inject ILogger<FileUpload2> Logger

<PageTitle>File Upload 2</PageTitle>

<h1>File Upload Example 2</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var response = await Http.PostAsync("/Filesave", content);

            var newUploadResults = await response.Content
                .ReadFromJsonAsync<IList<UploadResult>>();

            if (newUploadResults is not null)
            {
                uploadResults = uploadResults.Concat(newUploadResults).ToList();
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using Microsoft.Extensions.Logging
@inject HttpClient Http
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var response = await Http.PostAsync("/Filesave", content);

            var newUploadResults = await response.Content
                .ReadFromJsonAsync<IList<UploadResult>>();

            if (newUploadResults is not null)
            {
                uploadResults = uploadResults.Concat(newUploadResults).ToList();
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using Microsoft.Extensions.Logging
@inject HttpClient Http
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var response = await Http.PostAsync("/Filesave", content);

            var newUploadResults = await response.Content
                .ReadFromJsonAsync<IList<UploadResult>>();

            if (newUploadResults is not null)
            {
                uploadResults = uploadResults.Concat(newUploadResults).ToList();
            }
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}
@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using Microsoft.Extensions.Logging
@inject HttpClient Http
@inject ILogger<FileUpload2> Logger

<h1>Upload Files</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                           out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 15;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent = 
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType = 
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}", 
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                        {
                            FileName = file.Name, 
                            ErrorCode = 6, 
                            Uploaded = false
                        });
                }
            }
        }

        if (upload)
        {
            var response = await Http.PostAsync("/Filesave", content);

            var newUploadResults = await response.Content
                .ReadFromJsonAsync<IList<UploadResult>>();

            uploadResults = uploadResults.Concat(newUploadResults).ToList();
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string fileName, ILogger<FileUpload2> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName);

        if (result is null)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result = new();
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string Name { get; set; }
    }
}

Sunucu tarafı projesindeki aşağıdaki denetleyici, karşıya yüklenen dosyaları istemciden kaydeder.

Not

.NET 6'da ASP.NET Core'daki Minimum API'ler için özniteliğine sahip [FromForm] form değerlerini bağlama yerel olarak desteklenmez. Bu nedenle, aşağıdaki Filesave denetleyici örneği Minimum API'leri kullanacak şekilde dönüştürülemez. Minimum API'lere sahip form değerlerinden bağlama desteği ,NET 7 veya sonraki sürümlerde ASP.NET Core'da kullanılabilir.

Aşağıdaki kodu kullanmak için, ortamda çalışan uygulamanın sunucu tarafı projesinin kökünde Development bir Development/unsafe_uploads klasör oluşturun.

Örnek, dosyaların kaydedildiği yolun bir parçası olarak uygulamanın ortamını kullandığından, test ve üretimde diğer ortamlar kullanılıyorsa ek klasörler gerekir. Örneğin, ortam için Staging bir Staging/unsafe_uploads klasör oluşturun. Ortam için Production bir Production/unsafe_uploads klasör oluşturun.

Uyarı

Örnek, dosyaları içeriklerini taramadan kaydeder ve bu makaledeki yönergeler karşıya yüklenen dosyalar için ek güvenlik en iyi yöntemlerini hesaba katmıyor. Hazırlama ve üretim sistemlerinde karşıya yükleme klasöründe yürütme iznini devre dışı bırakın ve karşıya yüklemeden hemen sonra dosyaları virüsten koruma/kötü amaçlı yazılımdan koruma tarayıcı API'siyle tarayın. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

Aşağıdaki örnekte, paylaşılan proje sınıfını sağladığında paylaşılan projenin ad alanını paylaşılan projeyle eşleşecek şekilde güncelleştirin UploadResult .

Controllers/FilesaveController.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using BlazorSample.Shared;

[ApiController]
[Route("[controller]")]
public class FilesaveController : ControllerBase
{
    private readonly IHostEnvironment env;
    private readonly ILogger<FilesaveController> logger;

    public FilesaveController(IHostEnvironment env,
        ILogger<FilesaveController> logger)
    {
        this.env = env;
        this.logger = logger;
    }

    [HttpPost]
    public async Task<ActionResult<IList<UploadResult>>> PostFile(
        [FromForm] IEnumerable<IFormFile> files)
    {
        var maxAllowedFiles = 3;
        long maxFileSize = 1024 * 15;
        var filesProcessed = 0;
        var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/");
        List<UploadResult> uploadResults = new();

        foreach (var file in files)
        {
            var uploadResult = new UploadResult();
            string trustedFileNameForFileStorage;
            var untrustedFileName = file.FileName;
            uploadResult.FileName = untrustedFileName;
            var trustedFileNameForDisplay =
                WebUtility.HtmlEncode(untrustedFileName);

            if (filesProcessed < maxAllowedFiles)
            {
                if (file.Length == 0)
                {
                    logger.LogInformation("{FileName} length is 0 (Err: 1)",
                        trustedFileNameForDisplay);
                    uploadResult.ErrorCode = 1;
                }
                else if (file.Length > maxFileSize)
                {
                    logger.LogInformation("{FileName} of {Length} bytes is " +
                        "larger than the limit of {Limit} bytes (Err: 2)",
                        trustedFileNameForDisplay, file.Length, maxFileSize);
                    uploadResult.ErrorCode = 2;
                }
                else
                {
                    try
                    {
                        trustedFileNameForFileStorage = Path.GetRandomFileName();
                        var path = Path.Combine(env.ContentRootPath,
                            env.EnvironmentName, "unsafe_uploads",
                            trustedFileNameForFileStorage);

                        await using FileStream fs = new(path, FileMode.Create);
                        await file.CopyToAsync(fs);

                        logger.LogInformation("{FileName} saved at {Path}",
                            trustedFileNameForDisplay, path);
                        uploadResult.Uploaded = true;
                        uploadResult.StoredFileName = trustedFileNameForFileStorage;
                    }
                    catch (IOException ex)
                    {
                        logger.LogError("{FileName} error on upload (Err: 3): {Message}",
                            trustedFileNameForDisplay, ex.Message);
                        uploadResult.ErrorCode = 3;
                    }
                }

                filesProcessed++;
            }
            else
            {
                logger.LogInformation("{FileName} not uploaded because the " +
                    "request exceeded the allowed {Count} of files (Err: 4)",
                    trustedFileNameForDisplay, maxAllowedFiles);
                uploadResult.ErrorCode = 4;
            }

            uploadResults.Add(uploadResult);
        }

        return new CreatedResult(resourcePath, uploadResults);
    }
}

Yukarıdaki kodda, GetRandomFileName güvenli bir dosya adı oluşturmak için çağrılır. Bir saldırgan, var olan bir dosyanın üzerine yazan veya uygulamanın dışına yazmaya çalışan bir yol gönderen mevcut bir dosya adını seçeebileceği için, tarayıcı tarafından sağlanan dosya adına asla güvenmeyin.

Sunucu uygulamasının denetleyici hizmetlerini ve eşleme denetleyicisi uç noktalarını kaydetmesi gerekir. Daha fazla bilgi için bkz . ASP.NET Core'da denetleyici eylemlerine yönlendirme.

Dosya yükleme işlemini iptal etme

Bir dosya karşıya yükleme bileşeni, bir kullanıcının veya StreamReader.ReadAsynciçine IBrowserFile.OpenReadStream çağrı yaparken kullanarak CancellationToken bir karşıya yüklemeyi ne zaman iptal ettiğinde algılayabilir.

Bileşen için InputFile bir CancellationTokenSource oluşturun. Yöntemin OnInputFileChange başlangıcında, önceki bir karşıya yükleme işleminin devam ediyor olup olmadığını denetleyin.

Karşıya dosya yükleme işlemi sürüyorsa:

Dosyaları sunucu tarafında ilerleme durumuyla karşıya yükleme

Aşağıdaki örnekte, kullanıcıya karşıya yükleme ilerleme durumunun görüntülendiği sunucu tarafı bir uygulamada dosyaların nasıl karşıya yükleneceği gösterilmektedir.

Bir test uygulamasında aşağıdaki örneği kullanmak için:

  • Karşıya yüklenen dosyaları ortama kaydetmek için Development bir klasör oluşturun: Development/unsafe_uploads.
  • En büyük dosya boyutunu (maxFileSizeaşağıdaki örnekte 15 KB) ve izin verilen en fazla dosya sayısını (maxAllowedFilesaşağıdaki örnekte 3) yapılandırın.
  • Devam eden raporlamada daha fazla ayrıntı düzeyi için arabelleği farklı bir değere (aşağıdaki örnekte 10 KB) ayarlayın. Performans ve güvenlik endişeleri nedeniyle 30 KB'tan büyük bir arabellek kullanılması önerilmez.

Uyarı

Örnek, dosyaları içeriklerini taramadan kaydeder ve bu makaledeki yönergeler karşıya yüklenen dosyalar için ek güvenlik en iyi yöntemlerini hesaba katmıyor. Hazırlama ve üretim sistemlerinde karşıya yükleme klasöründe yürütme iznini devre dışı bırakın ve karşıya yüklemeden hemen sonra dosyaları virüsten koruma/kötü amaçlı yazılımdan koruma tarayıcı API'siyle tarayın. Daha fazla bilgi için bkz . ASP.NET Core'da dosyaları karşıya yükleme.

FileUpload3.razor:

@page "/file-upload-3"
@inject ILogger<FileUpload3> Logger
@inject IWebHostEnvironment Environment

<PageTitle>File Upload 3</PageTitle>

<h1>File Upload Example 3</h1>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Progress: @string.Format("{0:P0}", progressPercent)</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;
    private decimal progressPercent;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();
        progressPercent = 0;

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                var trustedFileName = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                    Environment.EnvironmentName, "unsafe_uploads", trustedFileName);

                await using FileStream writeStream = new(path, FileMode.Create);
                using var readStream = file.OpenReadStream(maxFileSize);
                var bytesRead = 0;
                var totalRead = 0;
                var buffer = new byte[1024 * 10];

                while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
                {
                    totalRead += bytesRead;
                    await writeStream.WriteAsync(buffer, 0, bytesRead);
                    progressPercent = Decimal.Divide(totalRead, file.Size);
                    StateHasChanged();
                }

                loadedFiles.Add(file);

                Logger.LogInformation(
                    "Unsafe Filename: {UnsafeFilename} File saved: {Filename}",
                    file.Name, trustedFileName);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {FileName} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-3"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload3> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Progress: @string.Format("{0:P0}", progressPercent)</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;
    private decimal progressPercent;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();
        progressPercent = 0;

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                var trustedFileName = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                    Environment.EnvironmentName, "unsafe_uploads", trustedFileName);

                await using FileStream writeStream = new(path, FileMode.Create);
                using var readStream = file.OpenReadStream(maxFileSize);
                var bytesRead = 0;
                var totalRead = 0;
                var buffer = new byte[1024 * 10];

                while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
                {
                    totalRead += bytesRead;

                    await writeStream.WriteAsync(buffer, 0, bytesRead);

                    progressPercent = Decimal.Divide(totalRead, file.Size);

                    StateHasChanged();
                }

                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {FileName} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-3"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload3> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Progress: @string.Format("{0:P0}", progressPercent)</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;
    private decimal progressPercent;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();
        progressPercent = 0;

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                var trustedFileName = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                    Environment.EnvironmentName, "unsafe_uploads", trustedFileName);

                await using FileStream writeStream = new(path, FileMode.Create);
                using var readStream = file.OpenReadStream(maxFileSize);
                var bytesRead = 0;
                var totalRead = 0;
                var buffer = new byte[1024 * 10];

                while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
                {
                    totalRead += bytesRead;

                    await writeStream.WriteAsync(buffer, 0, bytesRead);

                    progressPercent = Decimal.Divide(totalRead, file.Size);

                    StateHasChanged();
                }

                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}
@page "/file-upload-3"
@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<FileUpload3> Logger
@inject IWebHostEnvironment Environment

<h3>Upload Files</h3>

<p>
    <label>
        Max file size:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        Max allowed files:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<p>
    <label>
        Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
        <InputFile OnChange="LoadFiles" multiple />
    </label>
</p>

@if (isLoading)
{
    <p>Progress: @string.Format("{0:P0}", progressPercent)</p>
}
else
{
    <ul>
        @foreach (var file in loadedFiles)
        {
            <li>
                <ul>
                    <li>Name: @file.Name</li>
                    <li>Last modified: @file.LastModified.ToString()</li>
                    <li>Size (bytes): @file.Size</li>
                    <li>Content type: @file.ContentType</li>
                </ul>
            </li>
        }
    </ul>
}

@code {
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;
    private decimal progressPercent;

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        isLoading = true;
        loadedFiles.Clear();
        progressPercent = 0;

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                var trustedFileName = Path.GetRandomFileName();
                var path = Path.Combine(Environment.ContentRootPath,
                    Environment.EnvironmentName, "unsafe_uploads", trustedFileName);

                await using FileStream writeStream = new(path, FileMode.Create);
                using var readStream = file.OpenReadStream(maxFileSize);
                var bytesRead = 0;
                var totalRead = 0;
                var buffer = new byte[1024 * 10];

                while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
                {
                    totalRead += bytesRead;

                    await writeStream.WriteAsync(buffer, 0, bytesRead);

                    progressPercent = Decimal.Divide(totalRead, file.Size);

                    StateHasChanged();
                }

                loadedFiles.Add(file);
            }
            catch (Exception ex)
            {
                Logger.LogError("File: {Filename} Error: {Error}", 
                    file.Name, ex.Message);
            }
        }

        isLoading = false;
    }
}

Daha fazla bilgi için aşağıdaki API kaynaklarına bakın:

  • FileStream: Hem zaman uyumlu hem de zaman uyumsuz okuma ve yazma işlemlerini destekleyen bir dosya sağlar Stream .
  • FileStream.ReadAsync: Önceki FileUpload3 bileşen akışı ile ReadAsynczaman uyumsuz olarak okur. Akış ile zaman uyumlu okuma Read , bileşenlerde Razor desteklenmez.

Dosya akışları

Sunucu etkileşimi ile dosya verileri, dosya okundukça sunucudaki .NET koduna bağlantı üzerinden SignalR akışla aktarılır.

RemoteBrowserFileStreamOptions dosya karşıya yükleme özelliklerinin yapılandırılmasına izin verir.

WebAssembly tarafından işlenen bir bileşen için dosya verileri doğrudan tarayıcıdaki .NET koduna akışla aktarılır.

Karşıya resim önizlemesi yükleme

Görüntüleri karşıya yüklemenin görüntü önizlemesi için, bileşen başvurusu ve işleyicisi olan bir OnChange bileşen ekleyerek InputFile başlayın:

<InputFile @ref="inputFile" OnChange="ShowPreview" />

Görüntü önizlemesi için yer tutucu işlevi görecek bir öğe başvurusuna sahip bir görüntü öğesi ekleyin:

<img @ref="previewImageElem" />

İlişkili başvuruları ekleyin:

@code {
    private InputFile? inputFile;
    private ElementReference previewImageElem;
}

JavaScript'te, aşağıdakileri gerçekleştiren HTML input ve img öğesiyle adlı bir işlev ekleyin:

  • Seçili dosyayı ayıklar.
  • ile createObjectURLbir nesne URL'si oluşturur.
  • Görüntü yüklendikten sonra nesne URL'sini revokeObjectURL iptal etmek için bir olay dinleyicisi ayarlar, böylece bellek sızdırılamaz.
  • img Görüntüyü görüntülemek için öğenin kaynağını ayarlar.
window.previewImage = (inputElem, imgElem) => {
  const url = URL.createObjectURL(inputElem.files[0]);
  imgElem.addEventListener('load', () => URL.revokeObjectURL(url), { once: true });
  imgElem.src = url;
}

Son olarak, JavaScript işlevini çağıran işleyiciyi eklemek OnChange için eklenen IJSRuntime öğesini kullanın:

@inject IJSRuntime JS

...

@code {
    ...

    private async Task ShowPreview() => await JS.InvokeVoidAsync(
        "previewImage", inputFile!.Element, previewImageElem);
}

Yukarıdaki örnek, tek bir görüntüyü karşıya yüklemeye yöneliktir. Yaklaşım, görüntüleri destekleyecek multiple şekilde genişletilebilir.

Aşağıdaki FileUpload4 bileşende tam örnek gösterilmektedir.

FileUpload4.razor:

@page "/file-upload-4"
@inject IJSRuntime JS

<h1>File Upload Example</h1>

<InputFile @ref="inputFile" OnChange="ShowPreview" />

<img style="max-width:200px;max-height:200px" @ref="previewImageElem" />

@code {
    private InputFile? inputFile;
    private ElementReference previewImageElem;

    private async Task ShowPreview() => await JS.InvokeVoidAsync(
        "previewImage", inputFile!.Element, previewImageElem);
}
@page "/file-upload-4"
@inject IJSRuntime JS

<h1>File Upload Example</h1>

<InputFile @ref="inputFile" OnChange="ShowPreview" />

<img style="max-width:200px;max-height:200px" @ref="previewImageElem" />

@code {
    private InputFile? inputFile;
    private ElementReference previewImageElem;

    private async Task ShowPreview() => await JS.InvokeVoidAsync(
        "previewImage", inputFile!.Element, previewImageElem);
}

Dosyaları dış hizmete yükleme

İstemciler, dosya yükleme baytlarını işleyen bir uygulama ve karşıya yüklenen dosyaları alan uygulamanın sunucusu yerine dosyaları doğrudan bir dış hizmete yükleyebilir. Uygulama, dış hizmetten gelen dosyaları isteğe bağlı olarak güvenli bir şekilde işleyebilir. Bu yaklaşım, uygulamayı ve sunucusunu kötü amaçlı saldırılara ve olası performans sorunlarına karşı güçlendirmektedir.

Aşağıdaki olası avantajlara sahip Azure Dosyalar, Azure Blob Depolama veya üçüncü taraf hizmet kullanan bir yaklaşımı göz önünde bulundurun:

Azure Blob Depolama ve Azure Dosyalar hakkında daha fazla bilgi için Azure Depolama belgelerine bakın.

Sunucu tarafı SignalR ileti boyutu sınırı

Dosya yüklemeleri, en büyük SignalR ileti boyutunu aşan dosyalar hakkındaki verileri aldığında, Blazor bunlar başlamadan önce bile başarısız olabilir.

SignalR , alınan her ileti için geçerli olan bir ileti Blazor boyutu sınırı tanımlar ve InputFile bileşen, yapılandırılan sınıra uygun iletilerde dosyaları sunucuya akışla aktarır. Ancak, karşıya yüklenecek dosya kümesini gösteren ilk ileti benzersiz bir tek ileti olarak gönderilir. İlk iletinin boyutu ileti boyutu sınırını aşabilir SignalR . Sorun dosyaların boyutuyla değil, dosya sayısıyla ilgilidir.

Günlüğe kaydedilen hata aşağıdakine benzer:

Hata: Bağlan bağlantısı 'Hata: Sunucu kapatma sırasında bir hata döndürdü: Bağlan ion bir hatayla kapatıldı.' hatasıyla kesildi. @ blazor.server.js:1 e.log

Dosyaları karşıya yüklerken, ilk iletide ileti boyutu sınırına ulaşmak nadirdir. Sınıra ulaşılırsa uygulama daha büyük bir değerle yapılandırılabilir HubOptions.MaximumReceiveMessageSize .

Yapılandırma ve ayarlama hakkında SignalR daha fazla bilgi için bkz. ASP.NET Core BlazorSignalR kılavuzu.MaximumReceiveMessageSize

Ek kaynaklar