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 }
);
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.
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.
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.
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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With