Home > Back-end >  How to upload pictures in ASP.net Core Web API and Angular 13
How to upload pictures in ASP.net Core Web API and Angular 13

Time:06-06

I need to save pictures in the file directory. Data is already being saved in the database. But I want to save an image. I do not have a proper understanding of that

Angular Form

<form [formGroup]="myForm" (ngSubmit)="submit()">
            <mat-card>
                <h2 >Product Management</h2>
                <label  for="">Product Name</label>
                <input type="text" name="name" id="name" formControlName="ProductName" >

                <input type="text" name="description" id="description" placeholder="Product Description"  formControlName="ProductDescription">
                <input type="text" name="price" id="price" placeholder="Product Price"   formControlName="price">
                <input type="text" name="created" id="created" placeholder="Product created"   formControlName="created">
                <input type="text" name="cat" id="cat" placeholder="Product created"   formControlName="ProductCatID">

                <input type="file" name="Image" id="Image"  (change)="onFileChange($event)" formControlName="ImageUrl">
                <img [src]="imageSrc" *ngIf="imageSrc" style="height: 300px; width:500px">

                <button type="submit" >Submit</button>
            </mat-card>
        </form>

Angular TS file

submit(){
console.log(this.myForm.value);
this.http.post('https://localhost:5001/api/Products', this.myForm.value)
.subscribe(res => {
  console.log(res);
  alert('Uploaded Successfully.');
})

}

I think there is no problem with the angular part.

Web API Controller

 [HttpPost]
   public ActionResult<ProductDto> CreateProduct(CreateProductDto pro)
    {
        try
        {
            
            var productEntity = _mapper.Map<Product>(pro);
            var newProduct = _SqlService.AddProduct(productEntity);

            var productForReturn = _mapper.Map<ProductDto>(newProduct);

            return CreatedAtRoute("GetProduct", new { id = productForReturn.ProId },
                productForReturn);
        }
        catch(Exception ex)
        {
            return StatusCode(500, $"Internal server error: {ex}");
        }
        
    }

This is the Model class

 public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ProId { get; set; }

    [Required]
    [StringLength(255)]
    public string ProductName { get; set; }

    [Required]
    [StringLength(255)]
    public string ProductDescription { get; set; }

    [Required]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal price { get; set; }
    public DateTime created { get; set; }
    public int ProductCatID { get; set; }
    public ProductCat Category { get; set; }
    
    [StringLength(255)]
    public string ImageUrl { get; set; }
}

This is Create Dto class

public class CreateProductDto
{
    public string ProductName { get; set; }
    public string ProductDescription { get; set; }
    public decimal price { get; set; }
    public DateTime created { get; set; }
    public int ProductCatID { get; set; }
    public string ImageUrl { get; set; }
    
}

This is my SQL Service Code

public Product AddProduct(Product product)
    {
        _context.Products.Add(product);
        _context.SaveChanges();

        return _context.Products.Find(product.ProId);
    }

CodePudding user response:

"I need to save pictures in the file directory. Data is already being saved in the database. But I want to save an image. I do not have a proper understanding of that"

Well, let's assume we want to upload product image in the image folder under wwwroot within our application. Just like the image below:

enter image description here

The common scenario in our daily development life cycle is, to save the image into a desired folder within the application and save that image name or image path location into the database which is the best practice so far.

Your Current Scenario:

As per your given code sample it seems that you are sending picture from your front-end application (angular) by type="file" name="Image" id="Image" which seems good. Unfortunately, your asp.net core backend has no capabilities to receive that picture at this moment. So it would be best if you had a few modifications to your existing code as below.

Modify Controller Definition :

        [HttpPost]
        public async Task<IActionResult> CreateProduct(CreateProductDto pro, IFormFile Image)
        {
            try
            {
                //Checking if the user uploaded the image correctly
                if (Image == null || Image.Length == 0)
                {
                    return Content("File not selected");
                }
                //Set the image location under WWWRoot folder. For example if you have the folder name image then you should set "image" in "FolderNameOfYourWWWRoot"
                var path = Path.Combine(_environment.WebRootPath, "FolderNameOfYourWWWRoot", Image.FileName);
                //Saving the image in that folder 
                using (FileStream stream = new FileStream(path, FileMode.Create))
                {
                    await Image.CopyToAsync(stream);
                    stream.Close();
                }

                //Setting Image name in your product DTO
                //If you want to save image name then do like this But if you want to save image location then write assign the path 
                pro.ImageUrl = Image.FileName;

                var productEntity = _mapper.Map<Product>(pro);
                var newProduct = _SqlService.AddProduct(productEntity);

                var productForReturn = _mapper.Map<ProductDto>(newProduct);

                return CreatedAtRoute("GetProduct", new { id = productForReturn.ProId },
                    productForReturn);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex}");
            }

        }

Explanation:

Firstly, your controller signature was like ActionResult<ProductDto> seems you are trying to return your product dto after a successful response. But async Task<IActionResult> can also do the same. So I have modified the signature.

Secondly, your existing controller parameter was like CreateProduct(CreateProductDto pro) which cannot handle the uploaded picture from your front-end application request. So to handle that you should have this modification CreateProduct(CreateProductDto pro, IFormFile Image) now your controller will understand a picture property would be sent from your front-end application by name of name="Image".

Output:

Once you upload the picture it will save the information into the database as below.

enter image description here

Note:

When you would save ImageName it will save into the database as ImageName on the other hand when you would save the path it will save as ImageLocation fashion.

CodePudding user response:

From Angular your sending a file while your modal is waiting for an ImageUrl. The missing part here is a an image saving service (Intercepts the file from Angular, save it in the database, then return an URL (/yourServer/yourProject/pictures/picture01.jpeg). Then you set the returned URL to th DTO object and you persist it). One of the good ways to save pictures from Angular to the Database is to use Base64 converting like this example: https://www.thecodehubs.com/generate-base64-string-and-display-image-in-angular-12/

  • Related