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);
}
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:
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:
And In database It would be kept as like below: