This is a migrated thread and some comments may be shown as answers.

WebApi Delete Fails

3 Answers 156 Views
Grid
This is a migrated thread and some comments may be shown as answers.
King Wilder
Top achievements
Rank 2
King Wilder asked on 13 Feb 2014, 09:06 AM
I have a Grid that has Popup Editing and it all works using WebApi except for the Delete action.  I can't figure out what I'm missing.

Here's my HTML code:

01.@(Html.Kendo().Grid(Model.ReceiptDocumentsList).Name("list")
02.            .Columns(columns =>
03.            {
04.                columns.Bound(c => c.DocumentName);
05.                columns.Bound(c => c.Title);
06.                columns.Bound(c => c.Userid);
07.                columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
08.            })
09.        .ToolBar(toolbar => toolbar.Create())
10.        .Editable(editable => editable.Mode(GridEditMode.PopUp))
11.        .Pageable()
12.        .Sortable()
13.        .Scrollable()
14.        .DataSource(ds => ds
15.            .Ajax()
16.            .PageSize(20)
17.            .Events(events => events.Error("error_handler"))
18.            .Model(model => {
19.                model.Id(r => r.Id);
20.            })
21.            .Read(read => read.Url("/api/receiptdocuments").Type(HttpVerbs.Get))
22.            .Update(update => update.Url("/api/receiptdocuments/put").Type(HttpVerbs.Put))
23.            .Create(create => create.Url("/api/receiptdocuments/post").Type(HttpVerbs.Post))
24.            .Destroy(destroy => destroy.Url("/api/receiptdocuments/delete").Type(HttpVerbs.Delete))
25.            )
26.)
27. 
28. 
29.<script type="text/javascript">
30.    function error_handler(e) {
31.        if (e.errors) {
32.            var message = "Errors:\n";
33.            $.each(e.errors, function (key, value) {
34.                if ('errors' in value) {
35.                    $.each(value.errors, function () {
36.                        message += this + "\n";
37.                    });
38.                }
39.            });
40.            alert(message);
41.        }
42.    }
43.</script>

Here's my WebApi controller (with a base class):

01.public class ReceiptDocumentsController : BaseController<ReceiptDocuments>
02.{
03.    #region ctors
04. 
05.    private readonly IReceiptDocumentsService _receiptDocumentsService;
06. 
07.    private readonly IUnitOfWork _unitOfWork;
08. 
09.    public ReceiptDocumentsController(IReceiptDocumentsService receiptDocumentsService, IUnitOfWork unitOfWork) : base(receiptDocumentsService, unitOfWork)
10.    {
11.        this._receiptDocumentsService = receiptDocumentsService;
12.        this._unitOfWork = unitOfWork;
13.    }
14. 
15.    #endregion
16. 
17.}


Here's the WebApi Base Class that contains the HTTP CRUD operations:

001./// <summary>
002./// This is the common base ApiController used for all controllers.
003./// This class handles all the basic CRUD operations for the WebApi functions.
004./// </summary>
005./// <typeparam name="T"></typeparam>
006.public class BaseController<T> : ApiController where T : Entity
007.{
008.    #region ctors
009.    protected readonly IService<T> _service;
010. 
011.    private readonly IUnitOfWork _unitOfWork;
012. 
013.    public BaseController(IService<T> service, IUnitOfWork unitOfWork)
014.    {
015.        this._service = service;
016.        this._unitOfWork = unitOfWork;
017.    }
018. 
019.    #endregion
020. 
021.    #region Basic CRUD
022. 
023.    /// <summary>
024.    /// Get all the Products in the repository.
025.    /// </summary>
026.    /// <returns></returns>
027.    public IEnumerable<T> Get()
028.    {
029.        return _service.Get();
030.    }
031. 
032.    /// <summary>
033.    /// Get the selected Product.
034.    /// </summary>
035.    /// <param name="id">Id</param>
036.    /// <returns></returns>
037.    public T Get(int id)
038.    {
039.        T model = _service.GetById(id);
040.        if (model == null)
041.            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
042. 
043.        return model;
044.    }
045. 
046.    /// <summary>
047.    /// Insert a new Product into the repository.
048.    /// </summary>
049.    /// <param name="model">Product</param>
050.    /// <returns></returns>
051.    public HttpResponseMessage Post(T model)
052.    {
053.        if (ModelState.IsValid)
054.        {
055.            _service.Insert(model);
056.            _unitOfWork.Commit();
057. 
058.            var response = Request.CreateResponse(HttpStatusCode.Created, model);
059.            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = model.Id }));
060. 
061.            return response;
062.        }
063.        else
064.        {
065.            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
066.        }
067.    }
068. 
069.    /// <summary>
070.    /// Update the selected Product.
071.    /// </summary>
072.    /// <param name="id">Id</param>
073.    /// <param name="model">Product</param>
074.    /// <returns></returns>
075.    public HttpResponseMessage Put(T model)
076.    {
077.        if (ModelState.IsValid)
078.        {
079.            try
080.            {
081.                _service.Update(model);
082.                _unitOfWork.Commit();
083.            }
084.            catch (Exception)
085.            {
086.                return Request.CreateResponse(HttpStatusCode.NotFound);
087.            }
088.            return Request.CreateResponse(HttpStatusCode.OK, model);
089.        }
090.        else
091.        {
092.            return Request.CreateResponse(HttpStatusCode.BadRequest);
093.        }
094.    }
095. 
096.    /// <summary>
097.    /// Delete the selected Product.
098.    /// </summary>
099.    /// <param name="id">Id</param>
100.    /// <returns></returns>
101.    public HttpResponseMessage Delete(int id)
102.    {
103.        T model = _service.GetById(id);
104.        if (model == null)
105.        {
106.            return Request.CreateResponse(HttpStatusCode.NotFound);
107.        }
108. 
109.        try
110.        {
111.            _service.Delete(model);
112.            _unitOfWork.Commit();
113.        }
114.        catch (Exception)
115.        {
116.            return Request.CreateResponse(HttpStatusCode.NotFound);
117.        }
118. 
119.        return Request.CreateResponse(HttpStatusCode.OK, model);
120.    }
121.    #endregion
122. 
123.}


And here's my WebApi Route configuration:

01.public static class WebApiConfig
02.{
03.    public static void Register(HttpConfiguration config)
04.    {
05.        config.Routes.MapHttpRoute(name: "ReceiptDocuments",
06.            routeTemplate: "api/receiptdocuments/{action}/{id}",
07.            defaults: new { controller = "ReceiptDocuments", action = "Get", id = RouteParameter.Optional });
08. 
09. 
10.        config.Routes.MapHttpRoute(
11.            name: "DefaultApi",
12.            routeTemplate: "api/{controller}/{id}",
13.            defaults: new { id = RouteParameter.Optional }
14.        );
15.    }
16.}


Here's the 404 message response:

1.{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:59723/api/receiptdocuments/delete'.","MessageDetail":"No action was found on the controller 'ReceiptDocuments' that matches the request."}

It seems the "id" isn't getting into the route. When I tested this in Fiddler, it worked as long as I added the "id" as in:

http://localhost:port/api/receiptdocuments/delete/7

But the error message doesn't seem to be passing the "id" along with the request.  It kind of looks like a route issue but I'm just not seeing it if it is.  Any help here is appreciated.

Thanks.

3 Answers, 1 is accepted

Sort by
0
King Wilder
Top achievements
Rank 2
answered on 14 Feb 2014, 02:12 AM
Ok, I found the answer.  I found out how to pass the Id to the destroy method.

$(function () {
    var grid = $("#Grid").data("kendoGrid");
 
    // WebAPI needs the ID of the entity to be part of the URL e.g. PUT /api/Product/80
    grid.dataSource.transport.options.update.url = function (data) {
        return "/api/receiptdocuments/put/" + data.Id;
    }
 
    // WebAPI needs the ID of the entity to be part of the URL e.g. DELETE /api/Product/80
    grid.dataSource.transport.options.destroy.url = function (data) {
        return "/api/receiptdocuments/delete/" + data.Id;
    }
});

Now I have one more little problem, in the Popup form, the Primary Key field appears as a textbox.  How can I make that not display?

I've attached a screenshot of the form.

Thanks.
0
King Wilder
Top achievements
Rank 2
answered on 14 Feb 2014, 02:14 AM
For some reason the screenshot upload failed the first time.  I'm trying it again here.
0
Nikolay Rusev
Telerik team
answered on 17 Feb 2014, 07:47 AM
Hello King Wilder,

In order to hide the `Id` field from the popup editor is to mark the field with the [ScaffoldColumn(false)] attribute in the model.

Here is an example from our code-base used to demonstrate Grid popup editing in MVC:
namespace Kendo.Mvc.Examples.Models
{
    public class ProductViewModel
    {
        [ScaffoldColumn(false)]
        public int ProductID
        {
            get;
            set;
        }
 
        [Required]
        [DisplayName("Product name")]
        public string ProductName
        {
            get;
            set;
        }
 ....
 }
}


Regards,
Nikolay Rusev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
Grid
Asked by
King Wilder
Top achievements
Rank 2
Answers by
King Wilder
Top achievements
Rank 2
Nikolay Rusev
Telerik team
Share this question
or