WebApi Delete Fails

4 posts, 0 answers
  1. King Wilder
    King Wilder avatar
    240 posts
    Member since:
    Oct 2007

    Posted 13 Feb 2014 Link to this post

    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.
  2. King Wilder
    King Wilder avatar
    240 posts
    Member since:
    Oct 2007

    Posted 13 Feb 2014 in reply to King Wilder Link to this post

    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.
  3. Kendo UI is VS 2017 Ready
  4. King Wilder
    King Wilder avatar
    240 posts
    Member since:
    Oct 2007

    Posted 13 Feb 2014 in reply to King Wilder Link to this post

    For some reason the screenshot upload failed the first time.  I'm trying it again here.
  5. Nikolay Rusev
    Admin
    Nikolay Rusev avatar
    2285 posts

    Posted 17 Feb 2014 Link to this post

    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!
Back to Top
Kendo UI is VS 2017 Ready