3

I`m getting this error when i try to post some order through HTTP URL

The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'DatabaseService_WebAPI.Models.Product GetProduct(Int32)' in 'DatabaseService_WebAPI.Controllers.ProductController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

i make my api controller by using a tutorial which is availabe on ASP.NET Web API.

This is my URL

http://localhost:3325/api/Product/PostProduct?User=Haris2&ShopName=Dwatson&city=RYK&OrderDate=28/9/2012&OrderDetail=Strips

Product.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace DatabaseService_WebAPI.Models
{
    public class Product
    {
        [ScaffoldColumn(false)]
        public int Id { get; set; }
        [Required]
        public string User { get; set; }
        public string ShopName { get; set; }
        public string city { get; set; }
        public string OrderDate { get; set; }
        public string OrderDetail { get; set; }
    }
}

ProductController.cs

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.Web;
using System.Web.Http;
using DatabaseService_WebAPI.Models;

namespace DatabaseService_WebAPI.Controllers
{
    public class ProductController : ApiController
    {
        private ProductContext db = new ProductContext();

        // GET api/Product
        public IEnumerable<Product> GetProducts()
        {
            return db.Products.AsEnumerable();
        }

        // GET api/Product/5
        public Product GetProduct(int id)
        {
            Product product = db.Products.Find(id);
            if (product == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            return product;
        }

        // PUT api/Product/5
        public HttpResponseMessage PutProduct(int id, Product product)
        {
            if (ModelState.IsValid && id == product.Id)
            {
                db.Entry(product).State = EntityState.Modified;

                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        // POST api/Product
        public HttpResponseMessage PostProduct(Product product)
        {
            if (ModelState.IsValid)
            {
                db.Products.Add(product);
                db.SaveChanges();

                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, product);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = product.Id }));
                return response;
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        // DELETE api/Product/5
        public HttpResponseMessage DeleteProduct(int id)
        {
            Product product = db.Products.Find(id);
            if (product == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            db.Products.Remove(product);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            return Request.CreateResponse(HttpStatusCode.OK, product);
        }

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

RouteConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace DatabaseService_WebAPI
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

Global.asax

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using DatabaseService_WebAPI.App_Start;

namespace DatabaseService_WebAPI
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        System.Data.Entity.Database.SetInitializer(new DatabaseService_WebAPI.Models.ProductContextInitializer());

       // WebApiConfig.Configure(GlobalConfiguration.Configuration);

        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

}

Is my calling method is wrong or i have to do something else for to skip id?

tugberk
  • 57,477
  • 67
  • 243
  • 335
Haris
  • 1,179
  • 7
  • 15
  • 32
  • 1
    Did you call api/Product/5 or api/Product ? if the former, then the required id is obviously null so error is correct – Mohsen Afshin Oct 16 '12 at 07:19
  • 1
    try changing public Product GetProduct(int id){} to public Product GetProduct(int? id){} – MMK Oct 16 '12 at 07:20
  • @MohsenAfshin i`ve called api/Product/PostProduct @MMK I`m not getting the products. I`m trying to post the products. – Haris Oct 16 '12 at 07:31
  • @Haris Bad url schema! Right one would be `api/Products` and call such URL using HTTP POST verb. – Matías Fidemraizer Oct 16 '12 at 07:34
  • Calling api/Product/PostProduct without /id=5 at the end would cause id become null – Mohsen Afshin Oct 16 '12 at 07:40
  • @MatíasFidemraizer i`ve tried with api/Product but no success. – Haris Oct 16 '12 at 07:44
  • @Haris that's because you're not mapping the URL route. You need to map to your controller `api/products` (note that there're no URL parameters) and you need to configure such action for POST verb. – Matías Fidemraizer Oct 16 '12 at 08:16
  • @MatíasFidemraizer can u give me a code example how can i map my POST Verb? – Haris Oct 16 '12 at 12:47
  • there has to be a routing rule which can distinguish between an id being present and not. I am surprised the default webapi routing is not preconfigured to work with the template webapi (v2) class which provides two Get methods: one with no parameter which returns a collection of objects and the other with an id parameter which returns a single object. – BraveNewMath Oct 29 '13 at 16:36

3 Answers3

2

Try adding the following attribute [FromUri] to your POST method:

    // POST api/Product
    public HttpResponseMessage PostProduct([FromUri]Product product)
    {

Your relative URL should be

http://localhost:xxxx/api/Product

This should allow you to POST your model using this URL:

http://localhost:xxxx/api/Product?User=Haris2&ShopName=Dwatson&city=RYK&OrderDate=28/9/2012&OrderDetail=Strips

Also consider using a JSON [FromBody] payload instead:

    // POST api/Product
    public HttpResponseMessage PostProduct([FromBody]Product product)
    {

With request like:

User-Agent: Fiddler
Host: localhost:55805
Content-Length: 98
Content-Type: application/json

POST: http://localhost:xxxx/api/product

BODY: {"User":"Haris2","ShopName":"Dwatson","city":"RYK","OrderDate":"28/9/2012","OrderDetail":"Strips"}
Mark Jones
  • 12,156
  • 2
  • 50
  • 62
2

Two things:

  1. You need [FromUri] on your Product parameter if you want to pass this complex type from the Url:

    // POST api/Product
    public HttpResponseMessage PostProduct(Product product)
    {...}
    
  2. You need to add a Http route that accepts the action name in the Uri (since your uri you provided has "PostProduct" in it...)

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    
Maggie Ying
  • 10,095
  • 2
  • 33
  • 36
  • [FromUri] working is fine. but when i add {action} it gives me a bad request response. anyways thx for ur answer. – Haris Oct 16 '12 at 18:01
-3

you must add form method in the action link

 @Html.ActionLink("عرض التفاصيل", "JobDetails","Job",  new { id = item.UniqueId },***FormMethod.Get or post***)
Liam
  • 27,717
  • 28
  • 128
  • 190
mmh
  • 1