Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi Put "The parameters dictionary contains a null entry for parameter..."

public class ContactsController : ApiController
{
    private static readonly List<Contact> _contacts = new List<Contact>();
    public Contact PutContacts(int id, Contact contact)
    {
        if (_contacts.Any(c => c.Id == contact.Id) == false)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        contact.LastModified = DateTime.Now;
        return contact;
    }
}

http put header:

PUT /api/contacts/3 HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: localhost:8080

body:

{"Id":3,"Name":"mmm","Phone":"000 000 0000","Email":"[email protected]","LastModified":"2012-03-08T23:42:13.8681395+08:00"}

response:

HTTP/1.1 400 Bad Request
"The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'SelfHost.Contact PutContacts(Int32, SelfHost.Contact)' in 'SelfHost.ContactsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."

Why? thanks.

PS:

config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
like image 546
ma huwei Avatar asked Mar 08 '12 16:03

ma huwei


People also ask

How do we do parameter binding in Web API?

When Web API calls a method on a controller, it must set values for the parameters, a process called binding. By default, Web API uses the following rules to bind parameters: If the parameter is a "simple" type, Web API tries to get the value from the URI.

What is FromBody attribute in Web API?

The [FromBody] attribute which inherits ParameterBindingAttribute class is used to populate a parameter and its properties from the body of an HTTP request. The ASP.NET runtime delegates the responsibility of reading the body to an input formatter.

Can we return view from WebAPI?

You can return one or the other, not both. Frankly, a WebAPI controller returns nothing but data, never a view page. A MVC controller returns view pages. Yes, your MVC code can be a consumer of a WebAPI, but not the other way around.


2 Answers

I am having this same issue. The query parameter, "id" is null and the object "contact" is filled in. I think this is a model binding issue. If you put a break point in the controller, look at this expression:

this.ControllerContext.RouteData.Values["id"]

You will see that the value is there in the route data; its just not getting set on the model. I have an ActionFilter and if I put a break point in there as well, I see that the actionContext's ActionArgument has a key for it, but a null value.

Im still researching...

like image 132
craig.tadlock Avatar answered Jan 04 '23 07:01

craig.tadlock


I am unable to reproduce the issue you are describing.

Model:

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public DateTime LastModified { get; set; }
}

Controller:

public class ContactsController : ApiController
{
    public Contact Put(int id, Contact contact)
    {
        return contact;
    }
}

Client:

class Program
{
    static void Main()
    {
        using (var client = new WebClient())
        {
            client.Headers[HttpRequestHeader.ContentType] = "application/json";
            var data = Encoding.UTF8.GetBytes(@"{""Id"":3,""Name"":""mmm"",""Phone"":""000 000 0000"",""Email"":""[email protected]"",""LastModified"":""2012-03-08T23:42:13.8681395+08:00""}");
            var result = client.UploadData("http://localhost:1405/api/contacts/4", "PUT", data);
            Console.WriteLine(Encoding.UTF8.GetString(result));
        }
    }
}

When I run the client, the following request is being sent:

PUT /api/contacts/4 HTTP/1.1
Content-Type: application/json
Host: localhost:1405
Content-Length: 119
Expect: 100-continue
Connection: Keep-Alive

{"Id":3,"Name":"mmm","Phone":"000 000 0000","Email":"[email protected]","LastModified":"2012-03-08T23:42:13.8681395+08:00"}

and I get the correct result from the server. So I guess that the request you are showing is not the actual request that's being sent to the server.

like image 31
Darin Dimitrov Avatar answered Jan 04 '23 08:01

Darin Dimitrov