Jakub Holovsky
Jakub Holovsky

Reputation: 6772

Web API - Multiple POST methods

I am writing a simple web api application. I came to a phase when I need to have two POST methods in my web api controller. One of these methods works and the other does not. My route table looks like this:

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

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

Then I have my methods defined like this:

    [HttpPost]
    public bool PostTaskAgain(My3TasksWebAPI.Data.Task task)
    {
        var oldTask = _db.Task.Where(t => t.Id == task.Id).SingleOrDefault();

        oldTask.DoAgain = true;
        oldTask.DateUpdated = task.DateUpdated;

        if (_db.SetOfTasks.Where(t => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(t.DateCreated, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday) == CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday)).Any())
        {
            int currentSetOfTasksId = _db.SetOfTasks.OrderBy(s => s.DateCreated).FirstOrDefault().Id;

            My3TasksWebAPI.Data.Task newTask = new Data.Task() { CreatedBy = oldTask.CreatedBy, DateCreated = oldTask.DateCreated, DateUpdated = null, DoAgain = false, Notes = string.Empty, SetOfTasksId = currentSetOfTasksId, Status = false, Title = oldTask.Title, UserId = oldTask.UserId };

            _db.Task.Add(newTask);
        }

        _db.SaveChanges();

        return true;
    }

    // Post api/values/PostSetOfTasks/{setOfTasks}
    [HttpPost]
    public bool PostSetOfTasks(My3TasksWebAPI.Data.SetOfTasks setOfTasks)
    {
        _db.SetOfTasks.Add(setOfTasks);

        _db.SaveChanges();

        return true;
    }

When I try to call PostTaskAgain I get an internal server error. I think that it might be the routing table but I am not sure how to handle two post methods. I call the web api from my asp.net mvc application like this:

HttpResponseMessage response = client.PostAsJsonAsync("api/values/PostSetOfTasks", model.SetOfTasks).Result;

and

HttpResponseMessage response = client.PostAsJsonAsync("api/values/PostTaskAgain", taskToPost).Result;

That means that I include the actions.

Upvotes: 3

Views: 7792

Answers (2)

Vaibhav
Vaibhav

Reputation: 2557

Working with POST in webapi can be tricky though conincidently, your issue turned out to be trivial. However, for those who may stumble upon this page:

I will focus specifically on POST as dealing with GET is trivial. I don't think many would be searching around for resolving an issue with GET with webapis. Anyways..

If your question is - In MVC Web Api, how to- - Use custom action method names other than the generic HTTP verbs? - Perform multiple posts? - Post multiple simple types? - Post complex types via jQuery?

Then the following solutions may help:

First, to use Custom Action Methods in Web API, add a web api route as:

public static void Register(HttpConfiguration config)
{
            config.Routes.MapHttpRoute(
                name: "ActionApi",
                routeTemplate: "api/{controller}/{action}");
}

And they you may create action methods like:

[HttpPost]
        public string TestMethod([FromBody]string value)
        {
            return "Hello from http post web api controller: " + value;
        }

Now, fire the following jQuery from your browser console

$.ajax({
            type: 'POST',
            url: 'http://localhost:33649/api/TestApi/TestMethod',
            data: {'':'hello'},
            contentType: 'application/x-www-form-urlencoded',
            dataType: 'json',
success: function(data){ console.log(data) }
        });

Second, to perform multiple posts, It is simple, create multiple action methods and decorate with the [HttpPost] attrib. Use the [ActionName("MyAction")] to assign custom names, etc. Will come to jQuery in the fourth point below

Third, First of all, posting multiple SIMPLE types in a single action is not possible and there is a special format to post a single simple type (except for passing the parameter in the query string or REST style). This was the point that had me banging my head with Rest Clients and hunting around the web for almost 5 hours and eventually, the following URL helped me. Will still quote the contents for the link may turn dead!

Content-Type: application/x-www-form-urlencoded
in the request header and add a = before the JSON statement:
={"Name":"Turbo Tina","Email":"[email protected]"}

http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api

Anyway, let us get over that story. Moving on:

Fourth, posting complex types via jQuery, ofcourse, $.ajax() is going to promptly come in the role:

Let us say the action method accepts a Person object which had an id and a name. So, from javascript:

var person = { PersonId:1, Name:"James" }
$.ajax({
            type: 'POST',
            url: 'http://mydomain/api/TestApi/TestMethod',
            data: JSON.stringify(person),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function(data){ console.log(data) }
        });

And the action will look like:

[HttpPost]
        public string TestMethod(Person person)
        {
            return "Hello from http post web api controller: " + person.Name;
        }

All of the above, worked for me!! Cheers!

Upvotes: 3

Jakub Holovsky
Jakub Holovsky

Reputation: 6772

There was a problem with my LINQ query.

The response from the server was: {"$id":"1","Message":"An error has occurred.","ExceptionMessage":"LINQ to Entities does not recognize the method 'Int32 GetWeekOfYear(System.DateTime, System.Globalization.CalendarWeekRule, System.DayOfWeek)' method, and this method cannot be translated into a store expression.","ExceptionType":"System.NotSupportedException","StackTrace":" at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTransl‌​ator.Translate(ExpressionConverter parent, MethodCall....

After correcting the linq query everything is working fine. Visual studio was fine about me doing the linq query wrong.

Upvotes: 0

Related Questions