Aracılığıyla paylaş


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 9 sürümüne bakın.

Uyarı

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. 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 9 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. Bileşen, InputFile tek dosya karşıya yüklemeleri için türünde file bir HTML <input> öğesi işler. 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şenler için uygulama performansının düşmesine ve olası Hizmet Reddi (DoS) riskine 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.

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

Önerilmez: Dosyanın Stream içeriği bellekte String (reader) okunduğu için aşağıdaki yaklaşım ÖNERILMEZ:

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

Önerilmez: 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));

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.

Denetimin Ters Çevrilmesi (IoC) kapsayıcısı kullanıcılarını otomatik olarak kullanma

Yerleşik ASP.NET Core bağımlılık ekleme kapsayıcısı yerine Autofac Inversion of Control (IoC) kapsayıcısını kullanıyorsanız, sunucu tarafı bağlantı hattı işleyici hub seçeneklerinde olarak true ayarlayınDisableImplicitFromServicesParameters. Daha fazla bilgi için bkz . FileUpload: Ayrılan sürede veri alınmadı (dotnet/aspnetcore #38842).

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 InputFile InputFile 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, s veya Blazor Server uygulamalardaki Blazor Web AppEtkileşimli Sunucu bileşenleri için 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; }
}

Ü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 LazyBrowserFileStream sınıf, akışın ilk baytları istenmeden hemen önce lazily çağrıları OpenReadStream özel bir akış türü tanımlar. Akış, .NET'te okunmaya başlayana kadar tarayıcıdan sunucuya iletilmez.

LazyBrowserFileStream.cs:

using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;

namespace BlazorSample;

internal sealed class LazyBrowserFileStream(IBrowserFile file, int maxAllowedSize) 
    : Stream
{
    private readonly IBrowserFile file = file;
    private readonly int maxAllowedSize = maxAllowedSize;
    private Stream? underlyingStream;
    private bool isDisposed;

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => false;

    public override long Length => file.Size;

    public override long Position
    {
        get => underlyingStream?.Position ?? 0;
        set => throw new NotSupportedException();
    }

    public override void Flush() => underlyingStream?.Flush();

    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, 
        CancellationToken cancellationToken)
    {
        EnsureStreamIsOpen();

        return underlyingStream.ReadAsync(buffer, offset, count, cancellationToken);
    }

    public override ValueTask<int> ReadAsync(Memory<byte> buffer, 
        CancellationToken cancellationToken = default)
    {
        EnsureStreamIsOpen();
        return underlyingStream.ReadAsync(buffer, cancellationToken);
    }

    [MemberNotNull(nameof(underlyingStream))]
    private void EnsureStreamIsOpen() => 
        underlyingStream ??= file.OpenReadStream(maxAllowedSize);

    protected override void Dispose(bool disposing)
    {
        if (isDisposed)
        {
            return;
        }

        underlyingStream?.Dispose();
        isDisposed = true;

        base.Dispose(disposing);
    }

    public override int Read(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();

    public override long Seek(long offset, SeekOrigin origin)
        => throw new NotSupportedException();

    public override void SetLength(long value)
        => throw new NotSupportedException();

    public override void Write(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();
}
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;

namespace BlazorSample;

internal sealed class LazyBrowserFileStream : Stream
{
    private readonly IBrowserFile file;
    private readonly int maxAllowedSize;
    private Stream? underlyingStream;
    private bool isDisposed;

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => false;

    public override long Length => file.Size;

    public override long Position
    {
        get => underlyingStream?.Position ?? 0;
        set => throw new NotSupportedException();
    }

    public LazyBrowserFileStream(IBrowserFile file, int maxAllowedSize)
    {
        this.file = file;
        this.maxAllowedSize = maxAllowedSize;
    }

    public override void Flush()
    {
        underlyingStream?.Flush();
    }

    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, 
        CancellationToken cancellationToken)
    {
        EnsureStreamIsOpen();

        return underlyingStream.ReadAsync(buffer, offset, count, cancellationToken);
    }

    public override ValueTask<int> ReadAsync(Memory<byte> buffer, 
        CancellationToken cancellationToken = default)
    {
        EnsureStreamIsOpen();
        return underlyingStream.ReadAsync(buffer, cancellationToken);
    }

    [MemberNotNull(nameof(underlyingStream))]
    private void EnsureStreamIsOpen()
    {
        underlyingStream ??= file.OpenReadStream(maxAllowedSize);
    }

    protected override void Dispose(bool disposing)
    {
        if (isDisposed)
        {
            return;
        }

        underlyingStream?.Dispose();
        isDisposed = true;

        base.Dispose(disposing);
    }

    public override int Read(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();

    public override long Seek(long offset, SeekOrigin origin)
        => throw new NotSupportedException();

    public override void SetLength(long value)
        => throw new NotSupportedException();

    public override void Write(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();
}
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;

namespace BlazorSample;

internal sealed class LazyBrowserFileStream : Stream
{
    private readonly IBrowserFile file;
    private readonly int maxAllowedSize;
    private Stream? underlyingStream;
    private bool isDisposed;

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => false;

    public override long Length => file.Size;

    public override long Position
    {
        get => underlyingStream?.Position ?? 0;
        set => throw new NotSupportedException();
    }

    public LazyBrowserFileStream(IBrowserFile file, int maxAllowedSize)
    {
        this.file = file;
        this.maxAllowedSize = maxAllowedSize;
    }

    public override void Flush()
    {
        underlyingStream?.Flush();
    }

    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, 
        CancellationToken cancellationToken)
    {
        EnsureStreamIsOpen();

        return underlyingStream.ReadAsync(buffer, offset, count, cancellationToken);
    }

    public override ValueTask<int> ReadAsync(Memory<byte> buffer, 
        CancellationToken cancellationToken = default)
    {
        EnsureStreamIsOpen();
        return underlyingStream.ReadAsync(buffer, cancellationToken);
    }

    [MemberNotNull(nameof(underlyingStream))]
    private void EnsureStreamIsOpen()
    {
        underlyingStream ??= file.OpenReadStream(maxAllowedSize);
    }

    protected override void Dispose(bool disposing)
    {
        if (isDisposed)
        {
            return;
        }

        underlyingStream?.Dispose();
        isDisposed = true;

        base.Dispose(disposing);
    }

    public override int Read(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();

    public override long Seek(long offset, SeekOrigin origin)
        => throw new NotSupportedException();

    public override void SetLength(long value)
        => throw new NotSupportedException();

    public override void Write(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();
}
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Forms;

namespace BlazorSample;

internal sealed class LazyBrowserFileStream : Stream
{
    private readonly IBrowserFile file;
    private readonly int maxAllowedSize;
    private Stream? underlyingStream;
    private bool isDisposed;

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => false;

    public override long Length => file.Size;

    public override long Position
    {
        get => underlyingStream?.Position ?? 0;
        set => throw new NotSupportedException();
    }

    public LazyBrowserFileStream(IBrowserFile file, int maxAllowedSize)
    {
        this.file = file;
        this.maxAllowedSize = maxAllowedSize;
    }

    public override void Flush()
    {
        underlyingStream?.Flush();
    }

    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, 
        CancellationToken cancellationToken)
    {
        EnsureStreamIsOpen();

        return underlyingStream.ReadAsync(buffer, offset, count, cancellationToken);
    }

    public override ValueTask<int> ReadAsync(Memory<byte> buffer, 
        CancellationToken cancellationToken = default)
    {
        EnsureStreamIsOpen();
        return underlyingStream.ReadAsync(buffer, cancellationToken);
    }

    [MemberNotNull(nameof(underlyingStream))]
    private void EnsureStreamIsOpen()
    {
        underlyingStream ??= file.OpenReadStream(maxAllowedSize);
    }

    protected override void Dispose(bool disposing)
    {
        if (isDisposed)
        {
            return;
        }

        underlyingStream?.Dispose();
        isDisposed = true;

        base.Dispose(disposing);
    }

    public override int Read(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();

    public override long Seek(long offset, SeekOrigin origin)
        => throw new NotSupportedException();

    public override void SetLength(long value)
        => throw new NotSupportedException();

    public override void Write(byte[] buffer, int offset, int count)
        => throw new NotSupportedException();
}

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.Any())
{
    <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;
        int 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 stream = new LazyBrowserFileStream(file, maxFileSize);
                    var fileContent = new StreamContent(stream);

                    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.Net.Http.Headers
@using System.Text.Json
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<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;
        int 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 stream = new LazyBrowserFileStream(file, maxFileSize);
                    var fileContent = new StreamContent(stream);
                    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.Net.Http.Headers
@using System.Text.Json
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<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;
        int 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 stream = new LazyBrowserFileStream(file, maxFileSize);
                    var fileContent = new StreamContent(stream);
                    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.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@inject IHttpClientFactory ClientFactory
@inject ILogger<FileUpload2> Logger

<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;
        int 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 stream = new LazyBrowserFileStream(file, maxFileSize);
                    var fileContent = new StreamContent(stream);
                    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; }
    }
}

Bileşen, dosyayı tek seferde tek bir dosyaya yüklerse veya bileşen yalnızca etkileşimli istemci tarafı işlemeyi (CSR, ) benimsiyorsa, InteractiveWebAssemblybileşen öğesinin LazyBrowserFileStream kullanılmasını önleyebilir ve kullanabilir Stream. Aşağıda, bileşene yönelik değişiklikler gösterilmektedir FileUpload2 :

- var stream = new LazyBrowserFileStream(file, maxFileSize);
- var fileContent = new StreamContent(stream);
+ var fileContent = new StreamContent(file.OpenReadStream(maxFileSize));

Kullanılmadığından sınıfını LazyBrowserFileStream ()LazyBrowserFileStream.cs kaldırın.

Bileşen limit dosyası tek seferde tek bir dosyaya yüklenirse, bileşen ve kullanmaktan LazyBrowserFileStream Streamkaçınabilir. Aşağıda, bileşene yönelik değişiklikler gösterilmektedir FileUpload2 :

- var stream = new LazyBrowserFileStream(file, maxFileSize);
- var fileContent = new StreamContent(stream);
+ var fileContent = new StreamContent(file.OpenReadStream(maxFileSize));

Kullanılmadığından sınıfını LazyBrowserFileStream ()LazyBrowserFileStream.cs kaldırın.

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(
    IHostEnvironment env, ILogger<FilesaveController> logger) 
    : ControllerBase
{
    [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 = [];

        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. Tarayıcı tarafından sağlanan dosya adına asla güvenmeyin; bir siber saldırı uzmanı, 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çebilir.

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.

İstemci tarafı işleme (CSR) ile bir sunucuya dosya yükleme

Bu bölüm, s veya Blazor WebAssembly uygulamalardaki Blazor Web Appistemci tarafı işlenmiş (CSR) bileşenleri için geçerlidir.

Aşağıdaki örnek, CSR veya uygulamadaki bir bileşeni benimseyen bir bileşenden ayrı bir uygulamadaki Blazor Web App (büyük olasılıkla ayrı bir sunucuda) arka uç web API'sinin denetleyicisine Blazor WebAssembly dosya yükleme işlemini gösterir.

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.

Ana projedeBlazor Web App, 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 istemci projesinin Blazor Web App (.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.

içinde aşağıdaki bileşenin Blazor Web Appen ü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(
    IHostEnvironment env, ILogger<FilesaveController> logger) 
    : ControllerBase
{
    [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 = [];

        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. Tarayıcı tarafından sağlanan dosya adına asla güvenmeyin; bir siber saldırı uzmanı, 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çebilir.

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ğlantı 'Hata: Sunucu kapatma sırasında bir hata döndürdü: Bağlantı bir hatayla kapatıldı' hatasıyla kesildi. blazor@.server e.log.js:1

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

İstemci hub'ı başına en fazla paralel çağrı ayarı

BlazorMaximumParallelInvocationsPerClient varsayılan değer olan 1 olarak ayarlanır.

Değerin artırılması, işlemlerin oluşturma System.InvalidOperationException: 'Reading is not allowed after reader was completed.'olasılığının yüksek olmasına CopyTo neden olur. Daha fazla bilgi için bkz . MaximumParallelInvocationsPerClient > 1, dosya yüklemeyi modda sonlar Blazor Server (dotnet/aspnetcore #53951).

Sorun giderme

Çağıran IBrowserFile.OpenReadStream satır bir System.TimeoutExceptionoluşturur:

System.TimeoutException: Did not receive any data in the allotted time.

Olası nedenler:

Ek kaynaklar