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

3

6
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 }
        );
Yield answered 8/3, 2012 at 16:35 Comment(1)
I'm having this same problem. Did you figure it out?Stokes
C
1

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.

Chicoine answered 8/3, 2012 at 16:49 Comment(1)
I tried your code.but error is exits. I try in VS11 beta & mvc4 web api.Yield
M
2

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...

Modernize answered 3/4, 2012 at 19:40 Comment(3)
FYI, I also also using VS.NET 11 Beta.Modernize
I posted this as a bug to the Web API team. aspnetwebstack.codeplex.com/workitem/46Modernize
This is a confirmed bug in VS.NET 11 beta. It has already been fixed in the source of the codeplex link, but there isnt an official release yet.Modernize
C
1

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.

Chicoine answered 8/3, 2012 at 16:49 Comment(1)
I tried your code.but error is exits. I try in VS11 beta & mvc4 web api.Yield
V
0

craigtadlock, thanks for your help and sending the bug over to Microsoft. I was having the same problem with PUTs. None of them worked. As a workaround, I hacked POST to handle PUT. If the object I'm posting to the server already has it's ID, the POST code treats it as a PUT with that ID. Pseudo code is:

public HttpResponseMessage<MyClass> PostMyClass(MyClass myObject)
{
    if( myObject.ID != 0 ){
         //do PUT code
    }else{
         //do POST code
    }
}
Valdez answered 5/5, 2012 at 14:32 Comment(1)
Actually simply removing the ID parameter from teh server side PUT handler works better: public HttpResponseMessage<MyClass> PutMyClass(MyClass myObject) { if( myObject.ID == 0 ){ //return error }else{ if( myObject exists ) // do put code else // return NOT_FOUND code } }Valdez

© 2022 - 2024 — McMap. All rights reserved.