keatklein
keatklein

Reputation: 154

WebAPI POST method throwing null exception

I have created a WebAPI project which works fine when utilizing the DELETE and GET methods, but when I try to POST or PUT I receive

{"Value cannot be null.\r\nParameter name: entity"} on line 84, db.Reviews.Add(review)

I am using Postman to test and I've also tried using XMLHttpRequest but both methods work on GET/DELETE and fail on PUT/POST.

var update1 = new XMLHttpRequest();
var params = "ReviewID=123";
update1.open("POST", "http://localhost:49681/Api/Reviews/", true);
update1.setRequestHeader("Content-type", "application/json");
update1.send(params);

ReviewsController

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using ReviewApp.Models;

namespace ReviewApp.Controllers
{
    public class ReviewsController : ApiController
    {
        private CheetahEntities db = new CheetahEntities();

        // GET: api/Reviews
        public IQueryable<Review> GetReviews()
        {
            return db.Reviews;
        }

        // GET: api/Reviews/5
        [ResponseType(typeof(Review))]
        public async Task<IHttpActionResult> GetReview(string id)
        {
            Review review = await db.Reviews.FindAsync(id);
            if (review == null)
            {
                return NotFound();
            }

            return Ok(review);
        }

        // PUT: api/Reviews/5
        [ResponseType(typeof(void))]
        public async Task<IHttpActionResult> PutReview(string id, Review review)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (id != review.ReviewID)
            {
                return BadRequest();
            }

            db.Entry(review).State = EntityState.Modified;

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ReviewExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return StatusCode(HttpStatusCode.NoContent);
        }

        // POST: api/Reviews
        [ResponseType(typeof(Review))]
        public async Task<IHttpActionResult> PostReview(Review review)
        {
            /*
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            */
            db.Reviews.Add(review);

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateException)
            {
                if (ReviewExists(review.ReviewID))
                {
                    return Conflict();
                }
                else
                {
                    throw;
                }
            }

            return CreatedAtRoute("DefaultApi", new { id = review.ReviewID }, review);
        }

        // DELETE: api/Reviews/5
        [ResponseType(typeof(Review))]
        public async Task<IHttpActionResult> DeleteReview(string id)
        {
            Review review = await db.Reviews.FindAsync(id);
            if (review == null)
            {
                return NotFound();
            }

            db.Reviews.Remove(review);
            await db.SaveChangesAsync();

            return Ok(review);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool ReviewExists(string id)
        {
            return db.Reviews.Count(e => e.ReviewID == id) > 0;
        }
    }
}

Review

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ReviewApp.Models
{
    using System;
    using System.Collections.Generic;

    public partial class Review
    {
        public string ReviewID { get; set; }
        public string ReviewStatus { get; set; }
        public Nullable<System.DateTime> Date { get; set; }
        public string Account { get; set; }
    }
}

CheetahEntities

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ReviewApp.Models
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class CheetahEntities : DbContext
    {
        public CheetahEntities()
            : base("name=CheetahEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<Review> Reviews { get; set; }
    }
}

Upvotes: 1

Views: 1497

Answers (1)

Nkosi
Nkosi

Reputation: 247631

In the request you have the content type as application/json but send your params with ReviewId=123 which is not json. params should be properly formatted JSON object if you are sending Content-Type as application/json.

var update1 = new XMLHttpRequest();
var params = JSON.stringify({ ReviewID : 123 }); //JSON payload
update1.open("POST", "http://localhost:49681/Api/Reviews/", true);
update1.setRequestHeader("Content-type", "application/json");
update1.send(params);

In your PostReview method there is the potential for review variable to be null if the POST request was not properly sent but there was no check of the variable before trying to add it to the database. You commented out the validation check on the model.

// POST: api/Reviews
[ResponseType(typeof(Review))]
public async Task<IHttpActionResult> PostReview(Review review) {

    if (review == null) ModelState.AddModelError("", "invalid data");

    if (!ModelState.IsValid) {
        return BadRequest(ModelState);
    }

    db.Reviews.Add(review);

    try {
        await db.SaveChangesAsync();
    } catch (DbUpdateException) {
        if (ReviewExists(review.ReviewID)) {
            return Conflict();
        } else {
            throw;
        }
    }

    return CreatedAtRoute("DefaultApi", new { id = review.ReviewID }, review);
}

Upvotes: 2

Related Questions