Use process of elimination...if one statement succeeds, but the method doesn't return after that, then what could it be? I'm guessing your CreatedAtRoute is throwing the 500 since your item was added to your database, but the method did not execute successfully.
Perhaps do as this answer suggests and try:
var data = CreatedAtRoute("DefaultApi", new { controller = "controllername", id = item.Id }, item);
return data;
Obviously, replace "controllername"
with the name of your controller. However route attributes don't interact with the whole "DefaultApi"
thing very well since I believe they are added under a different route name. You may actually want to try something like this and add a Name
property to your RouteAttribute
. This will create an explicit routeName
that you can use in CreatedAtRoute
as the first argument.
There is, however, a problem. Based on your naming convention (you called your route "Postitem", you are not getting the point of CreatedAtRoute
. This function is meant to facilitate RESTful services. Your service is not restful. You should instead name your route "item"
and have a corresponding GetItem
method with the same route. One of them accepts an HTTP POST (your PostItem) and one accepts an HTTP GET. CreatedAtRoute
is meant to help the calling function know the URL it should call in order to
If you don't want to go the restful route, you can ditch CreatedAtRoute
altogether and just do this:
[Route("Postitem")]
[ResponseType(typeof(Item))]
public async Task<IHttpActionResult> PostItem(Item item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.items.Add(item);
await db.SaveChangesAsync();
return this.Ok(new { id = item.Id });
}
General debugging note
You likely could solve this problem yourself if you actually look at the response from the controller. Use something like this or this. Your message you posted says its 1174 bytes long. What do you want to bet that it contains a JSON-formatted exception that would tell you exactly what went wrong?
General API note
I noticed that you are directly passing entities around (you add your item
directly to your database). This is very bad, especially with navigation properties (they cause infinite loops in serializers). I would suggest having a separate model for your API and your DB. Make the thing that your method takes in able to transform itself into a database item and vice versa.
EDIT: An example of reading JSON
First, declare a class somewhere that looks like this:
[DataContract] //found in System.Runtime.Serializatino
public class ItemResult
{
[DataMember(Name = "id")] //Same place as DataContractAttribute
public int Id { get; set; }
}
This class represents the response from your service. Next, in your client class (the place where you declare PostItem
...not the action method, the client method), declare the following:
private static readonly JsonSerializer serializer = new JsonSerializer();
This is from the very popular JSON.Net library. Install it via nuget if you don't have it already.
Next, this is what your PostItem needs to look like:
public async Task<ItemResult> PostItem()
{
var item = new Item(1, 0, "Posted Item Name 6", "Posted Item Data");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var response = await client.PostAsJsonAsync("api/Postitem", item))
using (var rs = await response.Content.ReadAsStreamAsync())
using (var sr = new StreamRead(rs))
using (var jr = new JsonTextReader(sr))
{
if (response.IsSuccessStatusCode)
{
return serializer.Deserialize<ItemResult>(jr);
}
else
{
//deserialize as something else...an error message perhaps?
}
}
}
}
Here is an explanation of what happens:
- Make the request via POST by calling PostAsJsonAsync
- Use the content from the response and get a stream which will contain the content the server sends back. This is
response.Content.ReadAsStreamAsync
.
- Wrap that stream in a stream reader (part of System.IO)
- Wrap that stream in a json text reader (part of Newtonsoft.JSON (JSON.Net's namespace))
- Check to see if the status code was a success (if you want to automatically throw an exception if there's an error, then call
response.EnsureSuccessStatusCode
instead.
- Use the previously declared
serializer
object to deserialize the JSON object returned by the server into the ItemResponse
class.