Search code examples
c#restasp.net-corefile-uploadjson-patch

It's possible to use JsonPatchDocument with FromForm and IFormFile?


I'm working with a small application just to study .NET Core and C#. I have a model called Movie and one of its fields is a byte array to store an image. I want to know how is it possible to use JsonPatchDocument to update that field.

The Movie model:

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

    [Required]
    public string name_movie { get; set; }

    public byte[]? img_movie {  get; set; }

    public string? desc_movie { get; set; }

    public int duration_movie { get; set; }

    public type_class_movie class_movie { get; set; }

    public DateTime? created_at_movie { get; set; }

    public DateTime? updated_at_movie { get; set; }

    public int id_category_movie { get; set; }

    [ForeignKey("id_category_movie")]
    public Category? Category { get; set; }
}

public enum type_class_movie { Siete, Trece, Diesciseis, Dieciocho }

The MoviesController:

 [HttpPatch("update_movie/{id_movie:int}", Name = "UpdateMovie")]
public IActionResult UpdateMovie(int id_movie, [FromForm] Movie movie, IFormFile imagen)
{
    try
    {
        if (!_mRepo.MovieExistsById(id_movie))
        {
            var errorResponse = new
            {
                StatusCode = 400,
                Message = "Movie doesn't exists"
            };

            return StatusCode(400, errorResponse);
        }

        using (var memoryStream = new MemoryStream())
        {
             await imagen.CopyToAsync(memoryStream);
             movie.img_movie = memoryStream.ToArray();
        }


        if (!_mRepo.UpdateMovie(entity))
        {
            var errorResponse = new
            {
                StatusCode = 500,
                Message = "An error ocurred while processing the request"
            };

            return StatusCode(500, errorResponse);
        }

        return StatusCode(200, new { updt_cat = entity });
    } 
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());

        var errorResponse = new
        {
            StatusCode = "Error",
            Message = "An error occurred while processing the request."
        };

        return StatusCode(500, errorResponse);
    }
}

I like the way the JsonPatchDocument partial update works, but I don't know how to use it to get a partial update of a form that may include an image, any help is appreciated.

UPDATE: This is a screenshot of patchDocument values: enter image description here

Screenshot of request in Potman:

enter image description here


Solution

  • Sure it is possible. Do you follow this tutorial? https://trycatchdebug.net/news/1211513/jsonpatchdocument-and-iformfile-in-c Based on this document,I think you need to do following modification:

            [HttpPatch("update_movie/{id_movie:int}", Name = "UpdateMovie")]
            //change mehtod to async
            public async Task<IActionResult> UpdateMovie(int id_movie, [FromForm] JsonPatchDocument<Movie> patchDocument, IFormFile imagen)
            {
                try
                {
    
                    var movie = await _mRepoawait.MovieFindById(id_movie); // "MovieFindById implement from _dbcontext.Movies.FindAsync(id);
    
                    if (movie == null)
                    {
                        var errorResponse = new
                        {
                            StatusCode = 400,
                            Message = "Movie doesn't exists"
                        };
    
                        return StatusCode(400, errorResponse);
                    }
    
                    patchDocument.ApplyTo(movie); //use "ApplyTo" to update the "movie" model
    
                    using (var memoryStream = new MemoryStream())
                    {
                        await imagen.CopyToAsync(memoryStream);
                        movie.img_movie = memoryStream.ToArray();
                    }
    
                    if (!_mRepo.UpdateMovie(movie))    //"UpdateMovie" should have implement _dbcontext.SaveChangesAsync();
                    {
                        var errorResponse = new
                        {
                            StatusCode = 500,
                            Message = "An error ocurred while processing the request"
                        };
    
                        return StatusCode(500, errorResponse);
                    }
    
                    return StatusCode(200, new { updt_cat = movie });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
    
                    var errorResponse = new
                    {
                        StatusCode = "Error",
                        Message = "An error occurred while processing the request."
                    };
    
                    return StatusCode(500, errorResponse);
                }
            }
    

    Packages you need to install:
    Microsoft.AspNetCore.JsonPatch
    Microsoft.AspNetCore.Mvc.NewtonsoftJson

    And if your controller has the [ApiController] attribute, the multipart/formdata won't work. You will need to change the program.cs like following:

    builder.Services.AddControllers().AddNewtonsoftJson().ConfigureApiBehaviorOptions(o => {
        o.SuppressInferBindingSourcesForParameters = true;
    });
    

    Then you could use postman to test your endpoint like this: (change movie name and image) enter image description here

    Reference: https://learn.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-8.0