How to make use of IFormFile and attach it to the DTO to be sent to client in ASP.NET Core

Viewed 99

I am writing a web app using .NET for the backend and React as client. I want to implement the authorization to a login form and thus made two model (DTOs) to send back to the client. One for the login and register respectively. I have an AccountController class where I am handling the Post and Get requests for the current user (user after logged in).

As mentioned above I have a model class named User and its UserDTO. Inside of that model class, I made some props (eg. username, password, profilePictureURL, email) etc. I want the user to upload an image which in turn will get appended to the profilePictureURL into the request back to the server.

This is my User model:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;

namespace API.Entities
{
    public class User : IdentityUser
    {
        public IFormFile profilePhotoURL {get; set; }
        public string Name { get; set; }
    }
}

userName, email and phone numbers are being derived from IdentityUser class from .NET.

registerDTO

using Microsoft.AspNetCore.Http;

namespace API.DTOs
{
    public class RegisterDTO : LoginDTO
    {
         public string Email { get; set; }
         public string Name { get; set; }
         public FormFile profilePhotoURL { get; set; }
         public string PhoneNumber { get; set; }
    }
}

Inside of AccountController, my POST method for registering is:

[HttpPost("register"), DisableRequestSizeLimit]
public async Task<IActionResult> RegisterUser(RegisterDTO registerDTO)
{
    //getting the file from request
    var postedProfile = Request.Form.Files[0];

    // setting the Uploads folder
    var Uploads = Path.Combine(Directory.GetCurrentDirectory(), "Uploads");

    if (postedProfile.Length > 0)
    {
        var fileName = ContentDispositionHeaderValue.Parse(postedProfile.ContentDisposition).FileName.Trim();
        var pathToSave = Path.Combine(Uploads, fileName.ToString());

        using (var fileStream = new FileStream(pathToSave, FileMode.Create))
        {
            await postedProfile.CopyToAsync(fileStream);
        }

        Ok($"File Uploaded successfully");
    }
    else 
    {
        return BadRequest(new ProblemDetails
                              {
                                  Title = "400 - Bad Request",
                                  Status = 400,
                                  Detail = "File not uploaded"
                              });
    }

    var registeredUser = new User 
                             {
                                 UserName = registerDTO.userName,
                                 Email = registerDTO.Email,
                                 Name = registerDTO.Name,
                                 profilePhotoURL = postedProfile,
                                 PhoneNumber = registerDTO.PhoneNumber
                             };

    var result = await _userManager.CreateAsync(registeredUser, registerDTO.Password);

    if (!result.Succeeded) 
    {
        foreach (var Error in result.Errors)
        {
            ModelState.AddModelError(Error.Code, Error.Description);
        }

        return ValidationProblem();
    }

    await _userManager.AddToRoleAsync(registeredUser, "Member");

    return StatusCode(201);
}

I want to set the uploaded image into the profilePhotoURL property of my registerDTO class, but when on checking this in swagger, I get the following error:

The JSON value could not be converted to Microsoft.AspNetCore.Http.FormFile. Path: $.profilePhotoURL | LineNumber: 5 | BytePositionInLine: 36.

The above error is in the ModelState errors.

How could I make a method (inside of AccountController's POST request for registering a new user) to upload a file of type IFormFile and then set it inside of the User object?

All suggestions are welcome :)

1 Answers

Your backend was a webapi project, model binding get data from the request body(Json value) by default,but formfile get values from posted form fields. If you could post a form in your react app,just create a model for the form and add the [FromForm]Attribute

[HttpPost("register"), DisableRequestSizeLimit]
        public IActionResult RegisterUser([FromForm] RegisterModel registermodel)
        {
            return StatusCode(200);
        }

enter image description here

enter image description here

Related