Patch API Request Implementation With Strategy Pattern ASP.NET (Dot Net)

Code Snippets 4 U

The strategy pattern used below is a simple use case. As we can add more code in the classes that implement a strategy. It is more readable and easy to add to more functionality.

using DbFirstApproach.Exceptions;
using DbFirstApproach.Models;
using System;
using System.Diagnostics;
using System.Linq;
using System.Web.Http;

namespace DbFirstApproach.Controllers
{
    public class PatchStudentController : ApiController
    {
        [Route("api/patchStudent/{id}")]
        [HttpPatch]
        public string PatchStudent(int id, PatchStudentModel patchData)
        {
            StudentEntities db = new StudentEntities();
            var itemToBeUpdated = db.Students.FirstOrDefault(item => item.Id == id);
            
            try
            {
                if (itemToBeUpdated == null) throw new CannotBePatchedException("The student Id not found");
            }
            catch(CannotBePatchedException e)
            {
                Debug.WriteLine(e.Message);
                return e.Message;
            }

            int index = db.Students.ToList().IndexOf(itemToBeUpdated);
            
            if (patchData.name != null)
            {
                new Patcher(new UpdateName()).Update(index, patchData.name, db);
            }

            if (patchData.className != null)
            {
                new Patcher(new UpdateCourse()).Update(index, patchData.className, db);
            }

            if (patchData.rollNumber != -1)
            {
                new Patcher(new UpdateRollNumber()).Update(index, patchData.rollNumber, db);
            }
            db.SaveChanges();
            return "Done";

        }
    }

    // create abstract class
    abstract class PatchStrategy
    {
        public abstract void Update(int index, dynamic itemToBeUpdated, StudentEntities db);
    }

    // create strategies
    class UpdateName : PatchStrategy
    {
        public override void Update(int index, dynamic itemToBeUpdated, StudentEntities db)
        {
            db.Students.ToList()[index].Name = itemToBeUpdated.ToString(); 
        }
    }

    class UpdateRollNumber : PatchStrategy
    {
        public override void Update(int index, dynamic itemToBeUpdated, StudentEntities db)
        {
            db.Students.ToList()[index].RollNumber = Convert.ToInt32(itemToBeUpdated);
        }
    }

    class UpdateCourse : PatchStrategy
    {
        public override void Update(int index, dynamic itemToBeUpdated, StudentEntities db)
        {
            db.Students.ToList()[index].Course = itemToBeUpdated.toString();
        }
    }
    // below is the context. It will create the object of abstract strategy class (but not initialize as it is abstract)
    // Then the concrete strategy received by the constructor is assigned to it
    // and then call the method. The called method will be of concrete class passed in constructor
    class Patcher
    {
        private PatchStrategy _patchStrategy;

        public Patcher(PatchStrategy strategy)
        {
            _patchStrategy = strategy;
        }

        public void Update(int index, dynamic itemToBeUpdated, StudentEntities db)
        {
            _patchStrategy.Update(index, itemToBeUpdated, db);
        }

    }
}

Model used for above request is below. You should provide default values in model because the sender may not send all fields while patching. It will help in identifying the fields submitted.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace DbFirstApproach.Models
{
    public class PatchStudentModel
    {
        public string name { get; set; } = null;
        public string className { get; set; } = null;
        public int rollNumber { get; set; } = -1;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

− three = one