asp.net-web-apiasp.net-core-webapiwebapi

How do I upload an image in ASP.NET Core WEB API with other form data?


I'm trying to make a form that will take necessary form data plus a profile picture and store it in a WEB API because I'm gonna consume this API later in MVC. I'm kind of confused on how I should configure my HttpPost. This is my User class:

public partial class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string Email { getl set; }
    public string ProfilePhoto { get; set; }
}

This is what my HttpPost looks like in my UsersController:

[HttpPost]
public async Task<ActionResult<User>> PostUser(User user)
{
    _context.User.Add(user);
    await _context.SaveChangesAsync();

    return CreatedAtAction("GetUser", new { id = user.Id }, user);
}

Solution

  • How do I upload an image in ASP.NET Core WEB API with other form data?

    The way you are trying it might work initially but still it’s not elegant even will bring additional hassle in future if you would like to upload multiple pictures against a single user. So you could try this way which mostly practiced.

    ViewModel:

    public class UserViewModel
            {
               
                public string FirstName { get; set; }
    
                public string LastName { get; set; }
    
                public string Email { get; set; }
               
                public List<IFormFile> profilePicture { get; set; }
            }
    

    Note: As you can notice property from your User Model Are same we have introduced profilePicture List as List<IFormFile>.

    UserProfilePicture Model:

    public class UserProfilePicture
        {
            [Key]
            public int UserProfilePictureId { get; set; }
            public string UserId { get; set; }
            public string ImageName { get; set; }
            public string ImagePath { get; set; }
        }
    

    Note: This this the main table/Class which will deal all the pictures and files related stuff to the users class which make the User Class loosely coupled as per SOLID principle which stated

    Single-Responsibility Principle "A class should have one and only one reason to change, meaning that a class should have only one job"

    Open-Closed Principle "Objects or entities should be open for extension but closed for modification."

    As you can see UserId has used as foreignkey reference. You can refer the related database table below:

    enter image description here

    Note: Always keep in mind while the project small and best practice followed in a long run it will be well maintained otherwise lot of issues may begin gradually.

    Controller:

            [Route("CreateUserProfilePic")]
            [HttpPost]
            public async Task<IActionResult> CreateUserProfilePic([FromForm] UserViewModel model)
            {
    
                if (model == null)
                {
                    return Content("Invalid Submission!");
                }
                //Insert in User Model
                var userModel = new User
                {
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    Email = model.Email,
    
                };
                _context.Add(userModel);
                await _context.SaveChangesAsync();
                var lastUserId = userModel.Id;
               
                foreach (var item in model.profilePicture)
                {
                   
                    if (item.FileName == null || item.FileName.Length == 0)
                    {
                        return Content("File not selected");
                    }
                    var path = Path.Combine(_environment.WebRootPath, "Images/", item.FileName);
    
                    using (FileStream stream = new FileStream(path, FileMode.Create))
                    {
                        await item.CopyToAsync(stream);
                        stream.Close();
                    }
    
    
                    //Insert In User Profile table
                    var userProfileModel = new UserProfilePicture
                    {
                        UserId = lastUserId.ToString(),
                        ImageName = item.FileName,
                        ImagePath = path
    
                    };
                    _context.Add(userProfileModel);
                    await _context.SaveChangesAsync();
                }
               
                return Ok(model);
    
            }
    

    Note: You can split the upload functionality in a separate method. In addition, you picture should be saved in wwwroot folder and database should save it's referece as path or image name. As you can see below:

    enter image description here

    And In database It would be kept as like below:

    enter image description here

    Output: enter image description here