1

This is the default webapi method with [FromBody] attribute added:

// PUT api/Pedidos/5
    public async Task<IHttpActionResult> PutPedido(Guid id,[FromBody]Job pedido)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != pedido.Id)
        {
            return BadRequest();
        }

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

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

        return StatusCode(HttpStatusCode.NoContent);
    }

this is the jquery request:

self.update = function () {                
            $.ajax({
                type: "PUT",
                url: baseUri + '@Model.Id',
                data: ko.toJSON(updatableData),                    
                dataType: "json",
                contentType: "application/json"
            })
                .done(function (data) {

                    alert('Magic');
                })
                .error(function (jqXHR, textStatus, errorThrown) {
                    alert(errorThrown);
                    alert("fail");
                });
        }

This is the data:

var updatableData = {
            Id : '@Model.Id',
            Name : '@Model.Name',
            AbreviaNome: self.AbreviaNome(),
            AbreviaFantasia: self.AbreviaFantasia,
            AbreviaLogradouro: self.AbreviaLogradouro,
            AbreviaComplemento: self.AbreviaComplemento,
            AbreviaBairro: self.AbreviaBairro,
            AbreviaCidade: self.AbreviaCidade,
            AbreviaExtra: self.AbreviaExtra,
        };

this is partial c# model, I have removed about 7 fields where 2 are dates and the rest are strings:

public class Job
{       
    public Guid Id { get; set; } 
    [Required]   
    public string Name {get;set;}    
    public int TotalItems { get; set; }        
    public bool AbreviaNome { get; set; }
    public bool AbreviaFantasia { get; set; }
    public bool AbreviaLogradouro { get; set; }
    public bool AbreviaComplemento { get; set; }
    public bool AbreviaBairro { get; set; }
    public bool AbreviaCidade { get; set; }
    public bool AbreviaExtra { get; set; }
    public virtual ICollection<Item> Items { get; set; }        
}

I using ASP.NET with knockout.js thats why you see 'self' on the data. the request comes through, and I get to the PUT method just fine. But pedido instance has all false values and no Id at all (only on the first parameter), and all values were supposed to come as true, with the exception of the last one, on the attempt I had, see the Request Body content:

{"Id":"c47f0ad2-0783-e311-8289-88532ee08d00", "Name":"Test 1","AbreviaNome":true,"AbreviaFantasia":true,"AbreviaLogradouro":true,"AbreviaComplemento":true,"AbreviaBairro":true,"AbreviaCidade":true,"AbreviaExtra":false}

What might be happening here? Do I have to have all fields on the "updatableData" object? Is there another way of achieving what I need?

EDIT: I have added a field to model that was missing but its important "Name" is a required field and there is an error somewhere that it thinks that the Name value is not on the request, when it actually is, after the correction.

EDIT: Found an error in the ModelBinding, related to the Required Name:

{"$id":"1","Message":"The request is invalid.","ModelState":{"$id":"2","pedido.Name":["The Name field is required."]}}

I have removed the [Required] attribute from the Name property, then it stopped working worse, in the ModelBinding I was getting only one parameter, which was the Id. When I put required back it goes back to working but with the above error.

7
  • Do you really need the [FromBody] attribute. It is only needed for scalar parameters. What happens if you remove it? Commented Jan 24, 2014 at 5:48
  • 3
    Your code should work, however I see something strange: in your $.ajax the contenttype should be contentType the Type should start with a capital T. Commented Jan 24, 2014 at 5:54
  • I have removed the attribute and also corrected the contentType spelling (Nice Catch), but the behavior still the same... Commented Jan 24, 2014 at 6:01
  • Check Chrome Net console and see what error your receive, then post that here. Commented Jan 24, 2014 at 6:40
  • 1
    Try Postman. It's a chrome extension that lets you "manually" send requests. You can use it to make sure there is nothing wrong with what's going in the wire. The contentype is wrong for sure though, it's contentType Commented Jan 24, 2014 at 10:08

1 Answer 1

2

Try to use JSON.stringify instead of ko.ToJSON:

self.update = function () {                
            $.ajax({
                type: "PUT",
                url: baseUri + '@Model.Id',
                data: JSON.stringify(updatableData),                    
                datatype: "json",
                contenttype: "application/json"
            })
                .done(function (data) {
                alert('Magic');
            })
            .error(function (jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
                alert("fail");
            });
    }

Also, you appear to be passing one object over but expecting 2 parameters, so you shouldn't need the Guid id on the method signature as it's in the Job object already:

public async Task<IHttpActionResult> PutPedido([FromBody]Job pedido)
Sign up to request clarification or add additional context in comments.

3 Comments

His approach is valid, the guid will be loaded implicit FromURI and the complex Object explicit [FromBody]. But I suspect that he has an error when posting in browser console.
Tanner, I did try the stringify approach and it generated a different JSON then before {"Id":"96ed3a0f-fb84-e311-8289-88532ee08d00","Name":"Test 2","AbreviaNome":true}, its missing all the other things, and it still did not work.
About the 2 parameters: I believe this is the correct way since a proper REST implementation would return a resource URL (http:\\test.com\api\pedido\some-big-key), and when you make the call to apply changes to that resource, you use the that whole URL, and passes in the body the changes, just like Floradu88 describes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.