Search code examples
c#blazorasp.net-core-webapiblazor-server-sideasp.net-core-7.0

multipartdataformcontent not working on razor page but works in swagger


I'm following microsoft's example for file upload operation in my blazor server project. And my API works in Swagger, in the page no files are transferred to my API layer.

Here is my code - Razor page:

@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using Dostware.PromoPazarV1.Files
@using Dostware.PromoPazarV1.Models
@using Dostware.PromoPazarV1.Models.UploadResult
@using Microsoft.Extensions.Logging
@using System.Net.Http.Json
@inject HttpClient Http
@inject ILogger<ImageUpload> Logger
@inject FileUploadAppService FileUploadAppService

<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 * 100000;
        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)
        {
            // UrlConst sabitUrl = new UrlConst();
            // Http.BaseAddress = new Uri(@sabitUrl.Url);
            // var response = await Http.PostAsync("Filesave", content);    
            //var response = await Http.PostAsync("PostFile", content);
            var response = await FileUploadAppService.PostFile(content);
             
            //var deneme = await Http.PostAsJsonAsync("FileSave/PostFile", content);
        
            // var newUploadResults = await response.Content
            //     .ReadFromJsonAsync<IList<UploadResult>>(); 

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

            //var client = ClientFactory.CreateClient();
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<ImageUpload> 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; }
    }
}

My controller (works in Swagger) gets files.count = 0 if sent from the Razor page:

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

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

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

                    // Dosya adını rastgele bir şekilde oluştur
                    trustedFileNameForFileStorage = Path.GetRandomFileName();

                    // Dosyanın orijinal adını al
                    var originalFileName = file.FileName;

                    // Orijinal dosyanın uzantısını al
                    var fileExtension = Path.GetExtension(originalFileName);

                    // Yeni dosya adını ve uzantısını oluştur
                    var newFileName = trustedFileNameForFileStorage + fileExtension;

                    // Dosyanın tam yolunu oluştur
                    var path = Path.Combine(env.ContentRootPath, "wwwroot", "uploads", newFileName);

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

Here is my service layer:

public async Task<ActionResult<IList<UploadResult>>> PostFile(MultipartFormDataContent multipartFormDataContent)
{
    try
    {
        try
        {
            var response =  _http.PostAsync("FileSave/PostFile", multipartFormDataContent);
        }
        catch (Exception ex)
        {
            var den = ex.Message;
        }
    }   
    catch (Exception ex)
    {
        var den = ex.Message;
    }

    return new CreatedResult("", uploadResults);
}

I try stackoverflow results, nothing works. I work with .NET 7.0.


Solution

  • In case anyone comes here i found the problem and official Microsoft documentation working with following change: detailed explanation and github issue

    This change in program.cs worked: (In .Net 7.x)

    builder.Services
    .AddServerSideBlazor()
    .AddHubOptions(opt =>
    {
        opt.DisableImplicitFromServicesParameters = true;
    });