1
votes

my project contains several WebApi controllers and each of them provides usually three actions: get(guid), post(data) and delete(guid),
A default route is described in the WebApiconfig for this requirement. (name: ControllerAndId)

Now I have to implement a controller which has to handle different post actions. For this requirement I tried to map another route with ActionNames. (name: ControllerAndActionAndId)

Since I have mapped the ControllerAndActionAndId route it is not possible to call the delete route of the "normal" controller (example: Contactscontroller).
All routes are working except the delete routes.

StatusCode: 404, ReasonPhrase: 'Not Found'

There is an example of an usually ApiController:

    public class ContactsController : ApiController
{
    public IEnumerable<Contact> Get()
    {
        return GetContacts();
    }

    public HttpResponseMessage Post(Contact contact)
    {            
        SaveContact(contact);

        return Request.CreateResponse<Guid>(_code, contact.Id);
    }

    public void Delete(Guid id)
    {
        DeleteContact(id);
    }
}

Controller with ActionName-Route:

    public class AttachmentsController : ApiController
{
    [HttpGet]
    public Attachment Get(Guid attachmentId)
    {
        return GetAttachment(attachmentId);
    }

    [HttpPost]
    [ActionName("save")]
    public HttpResponseMessage Save(AttachmentSaveData saveData)
    {
        SaveAttachment(saveData);
    }

    [HttpPost]
    [ActionName("remove")]
    public HttpResponseMessage Remove(AttachmentDeleteData deleteData)
    {
       DeleteAttachment(deleteData);            
    }
}

WebApiConfig:

            // Web API routes
        config.MapHttpAttributeRoutes();

        // Controller with ID
        // To handle routes like `/api/VTRouting/route/1`
        config.Routes.MapHttpRoute(
            name: "ControllerAndActionAndId",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new
            {
                id = RouteParameter.Optional,
                action = RouteParameter.Optional
            }
        );

        // Controller with ID
        // To handle routes like `/api/VTRouting/1`
        config.Routes.MapHttpRoute(
            name: "ControllerAndId",
            routeTemplate: "api/{controller}/{id}",
            defaults: new
            {
                id = RouteParameter.Optional
            }
        );

ClientAction delete function:

        private void Delete(string uri, int id)
    {
        using (HttpClient _client = new HttpClient())
        {
            _client.BaseAddress = BaseAddress;
            string _url = string.Format("{0}/{1}", uri, id);
            var _response = _client.DeleteAsync(_url).Result;

            if (!_response.IsSuccessStatusCode)
            {
                throw new Exception();
            }
        }
    }

I currently have no further idea how to solve this problem.

2
Try use [HttpDelete] instead of [HttpPost] for your "remove" action - TryingToImprove
DeleteAsync method sends DELETE request. But you have POST methods - Anton
The AttachmentController is working fine now. But the DELETE action of the ContactController is not working anymore. - flo
Add HttpDelete attribute to delete action - Anton

2 Answers

2
votes

If you use Web API, you need add HTTP verb to action.

For example, your code must be as below:

public class ContactsController : ApiController
{ 
    [HttpGet]
    public IEnumerable<Contact> Get()
    {
        return GetContacts();
    }

    [HttpPost]
    public HttpResponseMessage Post(Contact contact)
    {            
        SaveContact(contact);

        return Request.CreateResponse<Guid>(_code, contact.Id);
    }

    [HttpDelete]
    public void Delete(Guid id)
    {
        DeleteContact(id);
    }
}

Pay attention to Delete action.

  1. If you use HttpDelete verb on action, you must send delete request from your client httpClient.DeleteAsync(...).
  2. If you use HttpPost verb on action, you must send post request from your client httpClient.PostAsync(...).

AttachmentsController is similar to ContactsController.

0
votes

I was focused to much on actions and routes of the controller. But the solution was easy to find at client side:

        private void Delete<T>(string uri, T value)
    {
        using (HttpClient _client = new HttpClient())
        {
            _client.BaseAddress = BaseAddress;
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            string _url = string.Format("{0}/{1}", uri, value);
            var _response = _client.DeleteAsync(_url).Result;
        }
    }

This solution requires only one route in WebApiConfig:

            config.Routes.MapHttpRoute(
            name: "ControllerAndId",
            routeTemplate: "api/{controller}/{id}",
            defaults: new
            {
                id = RouteParameter.Optional
            }
        );

Soo easy.. thanks a lot !