How to receive JSON object in POST and GET using web api

 

ASP.NET Web API is a great tool for building HTTP services with ASP.NET. It makes many things HTTP that used to be ill defined in .NET easy and allows you to build a variety of services very easily. Like other complex abstraction frameworks it makes complex scenarios super easy, while some very simple and common operations are not quite as straight forward or as transparent as they should be.

 

Capturing the raw Request Body

But things are not so easy and transparent when you want to pass simple parameters like strings, numbers, dates etc. Because Web API is based on a host of conventions, some things that should be easy, such as easily picking up the raw content of a POST or PUT operation and capturing it, aren't quite so transparent as the automatic type mapping shown above.

One thing you might expect to be able to easily do, is to pick up the entire content body and map it to a parameter like this:




       



[HttpPost]

        public string PostRawBuffer(string raw)

        {

            return raw;

        }


Quick, what do you think is required by the client to call this method the string parameter? I’ll wait here while you ponder…

The answer is - not easily and not without some additional ‘hints’.

There are a number of issues here that actually make this one of the worst parameter signatures in Web API.
This parameter signature 
does not work with any of these posted values:

  • Raw Content Buffer Data (entire buffer)
  • A JSON string with application/json content type
  • A UrlEncoded Form Variable
  • A QueryString Variable

In fact, no matter what you pass here in posted body content – the string parameter is always null. The same is true if you have any other simple parameter type – numbers, bools, dates, byte[] etc. Plain parameter mapping (without special attributes) works only complex types like objects and arrays.

If you really think about how Web API’s parameter bindings work, this sort of makes sense with the exception of the JSON string parameter. Parameter bindings map based on media types (ie. content-type header) using the Coning algorithm by default and try to map parameters as whole entities. If you post a a raw string or buffer Web API internally really has no idea how to map this to anything. Should it map the entire buffer? A form variable? A JSON string? So it needs some hints to do it’s thing.

 

[FromBody] to retrieve Content

I mentioned hints, and Web API allows you to use parameter binding attributes to provide these hints. These allow you to tell Web API where the content is coming from explicitly. There are [FromBody] and [FromUri] attributes that can force content to be mapped from POST or query string content for example.

Using [FromBody] like this:


       



        [HttpGet]

        [Route("GetProduct")]

        public async Task<IActionResult> GetProduct([FromBody] JObject Productsearch)

        {

              return StatusCode(200, Productsearch);

        }


Now allows JSON or XML content to be mapped from the body. Same goes for other simple parameter types like numbers, dates, bools etc.

 

Now we have Create web API That code is below: 

First Of We create Service Response Class for set Response Structure of web api

ServiceResponse.cs

public class ServiceResponse

       {

              public ServiceResponse()

              {

                     this.IsSuccess = true;

                     this.Errors = new List<string>();

              }

              public ServiceResponse(string errorCode)

              {

                     this.IsSuccess = false;

                     this.Errors.Add(errorCode);

              }

      

              public List<string> Errors { get; set; }

              public bool IsSuccess { get; set; }

              public object Data { get; set; }

 

              public void AddError(string error)

              {

                     this.IsSuccess = false;

                     this.Errors.Add(error);

              }

              public void AddErrorList(List<string> Error) {

                     this.IsSuccess = false;

                     this.Errors.AddRange(Error);

              }

       }



And now we create Model of the product 

public class Product

    {

        public long Id { get; set; }

        public string Name { get; set; }

        public string Brand { get; set; }

        public decimal Price { get; set; }

        public string Category { get; set; }

        public string Image { get; set; }

    }


Now we create SortingExtenson static class that Contain Common Code For Dynamic Orderby, Get value From json Object

 

SortingExtension.cs

 

        // Create dynamic Orderby just Pass IQueryble Querya Column name And descending

        public static IQueryable<T> OrderByDynamic<T>(this IQueryable<T> query, string sortColumn, bool descending)

        {

            // Dynamically creates a call like this: query.OrderBy(p => p.SortColumn)

            var parameter = Expression.Parameter(typeof(T), "p");

 

            string command = "OrderBy";

 

            if (descending)

            {

                command = "OrderByDescending";

            }

 

            Expression resultExpression = null;

 

            var property = typeof(T).GetProperty(sortColumn);

            // this is the part p.SortColumn

            var propertyAccess = Expression.MakeMemberAccess(parameter, property);

 

            // this is the part p =&gt; p.SortColumn

            var orderByExpression = Expression.Lambda(propertyAccess, parameter);

 

            // finally, call the "OrderBy" / "OrderByDescending" method with the order by lamba expression

            resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { typeof(T), property.PropertyType },

               query.Expression, Expression.Quote(orderByExpression));

 

            return query.Provider.CreateQuery<T>(resultExpression);

        }

 

        // get All Key from Json object

        public static void GetKeys(JObject obj, List<string> keys)

        {

            var result = obj.Descendants()

                .Where(f => f is JProperty) //.Where(f => f is JProperty)

                                            //.Select(f => f as JProperty)// and .Select(f => f as JProperty) can be replaced with .OfType<JProperty>()

                .OfType<JProperty>()

                .Select(f => f.Name)

                .Where(f => !keys.Contains(f));

            keys.AddRange(result);

        }

 

        // Check json Key List into Db Table key is exist or not in Db

        public static void CheckKeyInDb<T>(List<string> Keys, List<string> Error)

        {

 

            for (int i = 0; i < Keys.Count; i++)

            {

                if (typeof(T).GetProperty(Keys[i].ToString()) == null)

                {

                    Error.Add(Keys[i].ToString() + " Parameter is Not Valid");

                }

            }

        }

 

        // Get Value from JsonObject By Parse List Of key and Store into List Same Index of Key

        public static void GetValuefromJsononject(JObject obj, List<string> Keys, List<string> Value)

        {

            for (int i = 0; i < Keys.Count(); i++)

            {

                Value.Add(obj[Keys[i].ToString()] != null ? obj[Keys[i].ToString()].ToString() : "");

 

            }

        }

 

        // Get Value from JsonObject By Parse List Of key and Store Into dictionary key and value paire

        public static void GetValuefromJsononject(JObject obj, List<string> Keys, Dictionary<string, string> Value)

        {

            for (int i = 0; i < Keys.Count(); i++)

            {

                Value.Add(Keys[i].ToString(), obj[Keys[i].ToString()] != null ? obj[Keys[i].ToString()].ToString() : "");

 

            }

        }

 

Now we create Interface that contain definition of get data from Database

IProductService.cs

        Task<List<Product>> GetProducts(Dictionary<string, string> filter, int skip, int limit, string sortField, bool descending);



Now we create Productservice that inherit IProductService interface

private readonly IProductRepository _productRepository;

        private readonly UsersDbContext _dbContext;

 

        // initialize UserDbContext And IProductRepository object

        public ProductService(IProductRepository productRepository, UsersDbContext usersDbContext)

        {

            this._productRepository = productRepository;

            _dbContext = usersDbContext;

        }

 

public async Task<List<Product>> GetProducts(Dictionary<string, string> filter, int skip = 0, int limit = 10, string sortField = "Name", bool descending = false)

        {

            List<Product> lstProduct = new List<Product>();

 

            var productList = _dbContext.Products.AsQueryable();

            foreach (var d in filter)

            {

                string colName = d.Key;

                string colValue = d.Value;

 

                switch (colName.ToLower())

                {

                    case "name":

                        productList = productList.Where(p => p.Name.Contains(colValue));

                        break;

                    case "brand":

                        productList = productList.Where(p => p.Brand == colValue);

                        break;

                    case "price":

                        productList = productList.Where(p => p.Price <= Convert.ToDecimal(colValue));

                        break;

                    case "category":

                        productList = productList.Where(p => p.Category == colValue);

                        break;

                    case "id":

                        productList = productList.Where(p => p.Id == Convert.ToInt64(colValue));

                        break;

                    default:

 

                        break;

                }

            }

 

            productList = SortingExtension.OrderByDynamic<Product>(productList, sortField, descending);

            productList = productList.Skip(skip).Take(limit);

            return lstProduct = await productList.ToListAsync();

        }


And last We Create Controller that handle the Request calling From Front-end or Postman

 

Controller.cs

[HttpGet]

        [Route("GetProduct")]

        public async Task<IActionResult> GetProduct([FromBody] JObject Productsearch)

        {

            ServiceResponse response = new ServiceResponse();

            try

            {

                int Skip = 0, Limit = 10;

                bool descending = true;

                List<string> Filterkey = new List<string>();

                List<string> Sortkey = new List<string>();

                List<string> Error = new List<string>();

                Dictionary<string, string> FilterValue = new Dictionary<string, string>();

                if (Productsearch != null)

                {

                    var detail = Productsearch["data"];

                    if (detail != null && detail["filter"] != null)

                    {

                        SortingExtension.GetKeys((JObject)detail["filter"], Filterkey);

                    }

                    else

                    {

                        response.AddError("Filter List Required");

                    }

                    if (detail["sort"] != null)

                    {

                        SortingExtension.GetKeys((JObject)detail["sort"], Sortkey);

                        SortingExtension.CheckKeyInDb<Product>(Sortkey, Error);

                        if (Error.Count == 0)

                        {

                            if (detail["sort"][Sortkey[0]].ToString().ToLower() == "asc")

                            {

                                descending = false;

                            }

                        }

                        else

                        {

                            response.AddErrorList(Error);

                        }

                    }

                    if (detail["paging"] != null)

                    {

                        Skip = detail["paging"]["skip"] != null ? Convert.ToInt32(detail["paging"]["skip"].ToString()) : 0;

                        Limit = detail["paging"]["limit"] != null ? Convert.ToInt32(detail["paging"]["limit"].ToString()) : 10;

                    }

                    SortingExtension.GetValuefromJsononject((JObject)detail["filter"], Filterkey, FilterValue);

                    string sort = Sortkey.Count > 0 ? Sortkey[0].ToString() : "Name";

                    response.Data = await _productService.GetProducts(FilterValue, Skip, Limit, sort, descending);

                }

            }

            catch (Exception ex)

            {

                response.AddError(ex.ToString());

            }

            return StatusCode(200, response);

        }



Now we have testing the code from Postman

Passing Parameter from body Json Raw Data here is Sample Json Data That pass in Request.

{

    "data": {

        "filter": {

            "Name""Coffee"

        },

        "sort": {

            "Brand""asc"

        },

        "paging": {

            "skip"10,

            "limit"20

        }

    }

}




Comments

Popular posts from this blog

Private Chat Using Node js and socket.io with encrypt and decrypt message and insert into mongo db

How To Migrate MVC 3 Application To MVC 5

Populate a drop-down in Vue.js and Asp.net Core from an ajax call