Is there a way to specify the success return code for a method in Web API controller?
My initial controller was structured like below
public HttpResponseMessage PostProduct(string id, Product product)
{
var product= service.CreateProduct(product);
return Request.CreateResponse(HttpStatusCode.Created, product);
}
However, there is drawback to the above approach when you generate Web API help pages. The Web API Help page API cannot automatically decode that the strongly typed Product is the response and hence generate a sample response object in its documentation.
So I go with the below approach, but here the success code is OK (200) and not Created (201). Anyway I can control the success code of the method using some attribute style syntax? Plus, I would also like to set the Location header to the URL where the created resource is available - again, this was easy to do when I was dealing with HttpResponseMesage.
public Product PostProduct(string id, Product product)
{
var product= service.CreateProduct(product);
return product;
}
Regarding your observation below:
However, there is drawback to the above approach when you generate Web API help pages. The Web API Help page API cannot automatically decode that the strongly typed Product is the response and hence generate a sample response object in its documentation.
You can take a look at HelpPageConfig.cs file that gets installed with HelpPage package. It has an example exactly for a scenario like yours where you can set the actual type of the response.
In latest version (5.0 - currently RC) of Web API we have introduced an attribute called ResponseType which you can use to decorate the action with the actual type. You would be able to use this attribute for your scenario.
I do this:
[HttpGet]
public MyObject MyMethod()
{
try
{
return mysService.GetMyObject()
}
catch (SomeException)
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content =
new StringContent("Something went wrong.")
});
}
}
If you don't get what you expected, throw a HttpResponseException.
Related
I am creating a c# .net core 2.2 web API for my next project. My question is when returning data should I return the object or IActionResult OK(returnObject)?
The reason I ask is I am using swagger and swagger studio to create my models for an Angular front end. If I return an IActionResult from the API the returned view models are not detailed in the swagger.json file so I would have to code these in the angular application. If I return whatever object is created the model is created in the swagger.json.
What practice should I follow to return data from an API in this case?
You do want to return IActionResult(object) but you are not quite done.
Annotate your controller with the ProducesAttribute and annotate your method with the ProducesResponseTypeAttribute:
[Produces("application/json")]
public class SomethingController
{
[ProducesResponseType(typeof(YourObject), (int)HttpStatusCode.OK)]
public IActionResult GetThing(int id)
{ ... }
}
This allows Swagger UI to know what to expect and document it appropriately. Shown above is for a synchronous method; it works for asynchronous as well.
You can return
- Specific Type
- IActionResult
- ActionResult
For more details, please refer MSDN article at : https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.2
I've got an ASP.NET Web API project that I'm working on. I've got an APIController called SpellbookController that has basic CRUD operations to an EntityFramework repository.
However, when I try to add a method that takes a parameter that's not an id, I can't seem to get it to route correctly.
Here's what it looks like:
// GET: api/Spellbooks/user#email.com
[ResponseType(typeof(List<Spellbook>))]
[Route("api/Spellbooks/{username}")]
public IHttpActionResult GetSpellbook(string username)
{
List<Spellbook> spellbooks = db.Spellbooks.Where(x=>x.Username == username).ToList();
if (spellbooks == null)
{
return NotFound();
}
return Ok(spellbooks);
}
So I'm trying to hit http://localhost:xxxx/api/Spellbooks/emailaddress,
but I get a 404 every time.
It's definitely an APIController, and I have config.MapHttpAttributeRoutes(); turned on.
What am I missing?
Where is your username parameter?
Your call should looks like this-
http://localhost:xxxx/api/Spellbooks/emailaddress/David
Update
Try to declare the parameter as string {username:string}
Update 2
The problem is with your '.' as you can see in this link.
You can send the email without the point in the parameter and then replace ite back to you regular mode or you can use all the good advice that the link provide.
If you step through it, do you get a value when looking at username? Or is it always null?
If your route is not working, a simple way to debug the route is to make a request to http://localhost:xxxx/api/Spellbooks/?emailaddress=thisemailaddress and see if you can get a response. In fact, from a REST standard, it can be argues that it's a cleaner route, since you will be returning a collection of elements, rather than a single object.
Working on some little task I have some troubles with the Web API controller.
There are 2 methods in my API:
[HttpGet]
public IHttpActionResult FetchAll()
[HttpPost]
public IHttpActionResult CreateNew(int? taskType, string taskName = null)
Which, I'm using for managing tasks in db.
The 1st one (FetchAll) works fine as from special utilities like Postman and bringing some results to the browser console.
But! If to use the 2nd one (CreateNew) there are some problems.
As I have tested in Postman, it works fine:
But if to use my frontend part of application (JS):
var App = function () {
this.init();
};
App.prototype.init = function () {
var self = this;
$.post(
'/api/task/createNew',
{ taskName: "smth new", taskType: 0 }
);
$.get(
'/api/task/fetchAll',
function ( sender ) {
console.log(sender);
}
);
};
window.onload = function () {
var app = new App();
};
There is a problem with the POST method. Firstly I think I'm using jQuery not correctly, but reading the following links I understand that all is correct with jQuery use:
http://api.jquery.com/jquery.post/
http://api.jquery.com/jquery.get/
Also I've checked in browser the failed request details:
As you're able to see, the POST data have been transferred correctly with my jQuery use,
but I have also admit one detail: it's form data.
So... Form data is a type of data, which is send with application/x-www-form-urlencoded and isn't presented as URL part.
If to use in JS-part the next code:
$.post( '/api/task/createNew?taskName=smth new&taskType=0' );
All begins to work.
And Web API seems to be not supporting operations with the Forms data and that's why the Postman test works well (if to look again at old screenshot), because it uses URL parameters, nor forms one.
But I think to send POST data with using URL parameters is rather ugly as for REST architecture and as for using it in JavaScript code (you will generate a string and not normally using Object representation for data, which can be reviews as bad OO-structure).
I have read about forms handling in WebAPI here:
Is there a way to handle form post data in a Web Api controller?
So do exist some ways to solve my problem with more pretty code-style etc (it's meant not to generate URL strings and etc)?
PS
Projects files which were described here are available:
C#/WebAPI controller: http://pastebin.com/AeE2Lb2a
JS part: http://pastebin.com/XcBPs6SD
As explained in the question you linked to your web api post action should take a object containing the fields you want:
public IHttpActionResult CreateNew(NewTask task)
{
// do something with task.TaskType and task.TaskName here
}
public class NewTask
{
public int? TaskType { get;set; }
public string TaskName { get; set; }
}
I'm trying to understand how or what options are available for publishing the model class that is passed to my ASP.NET Web API CRUD methods. Here is an example of my POST method.
public HttpResponseMessage PostMaterial(Material material)
{
try
{
repository.Add(material);
}
catch (ArgumentNullException)
{
var exceptionResponse = Request.CreateResponse("Material object was null.");
return exceptionResponse;
}
var response = Request.CreateResponse("Material " + material.MaterialName + " created.");
string uri = Url.Link("DefaultApi", new { materialName = material.MaterialName });
response.Headers.Location = new Uri(uri);
return response;
}
In this example a material object is passed as a parameter when the method is called by an external API user. That caller would need a definition of the material class, so then could correctly build the object they will need to pass. If anyone has some details or a better explanation, then please let me know. I haven't had much luck finding an answer which leads me to believe I'm asking the wrong question.
I had the same situation and had two approaches:
Approach 1:
Use help pages for web API
Approach 2:
I can create a simple GET method which returns my model(blank or default values) in response. so they (caller) will know that what parameters/objects needs to send to consume the web api in their application.(but for this also i need to inform them about that method :) )
So, I choose the first approach as it is really helpful for external application developer to understand your web api properly. You can properly document your API also by using Web API help pages.
Assume i have this model
public partial class Todo
{
public int id { get; set; }
public string content { get; set; }
public bool done { get; set; }
}
And i send this as json data to my controller as a patch request.
This is mearly the action of toggeling a checkbox.
I think it makes sence that i only want to sent that to my server, and not the entire model.
{ "id":1, "done" : true }
What does my WebApi controller need to look like in order to correctly process this, simple, json patch request ? Should i be using web api for this, or should i use a more rpc styled approach with mvc ?
It seems like a very basic thing to do, but i can't seem to get it right !
I think i might need to use a different parameter in my controller method, but i'm not sure.
Thank you for your time.
You can find PATCH feature in the OData pre-release Nuget package: Microsoft.AspNet.WebApi.OData.
Information how you can use it to create an action for handling PATCH can be found in the Partial Updates (PATCH requests) section of the blog post about OData support in ASP.NET Web API.
Changing the method to PATCH doesn't change Web API behaviour in any way. There is no built in mechanism for doing partial updates. One of the reasons there was no PATCH method for so long is that there is no ubiquitous media type for applying patches to resources.
Secondly, you are asking Web API to do object serialization for you so there just is no such concept of applying a partially updated object. There would be so many conventions to agree on, what does a null value mean, what about an empty value, how do I say "don't update this DateTime". What about related objects, child items? How do you cause a child item to be deleted? Unless the CLR team implements some concept of a type that only contains a subset of members from another type, partial updates and object serialization are not going to go well together.
Aliostad mentions UpdateModel and that is possible when updating from a HTML form because the media type application/x-www-form-urlencoded explicitly allows for an arbitrary set of name value pairs. There is no "object serialization" going on. It is just a match of names from the form being matched to names on the Model object.
For myself, I created a new media type I use to do partial updates that works like a form but is more advanced in that it can handle hierarchial data and it maintains an order to the updates.
ASP.NET Web API seems to be missing UpdateModel, TryUpdateModel, etc.
In ASP.NET MVC, you could use them to achieve the desired effect. I have created a work item in ASP.NET Web Stack which you can vote for and if it gets enough votes, it will be implemented.
I used Microsoft.AspNet.WebApi.OData for my project and I had some problems working with JSON (working with numbers in my case). Also, the OData package has some dependencies which, from my point of view, are too big for a single feature (~7MB with all dependecies).
So I developed a simple library which do what you are asking for: SimplePatch.
How to use
Install the package using:
Install-Package SimplePatch
Then in your controller:
[HttpPatch]
public IHttpActionResult PatchOne(Delta<Todo> todo)
{
if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) {
// Entity to update (from your datasource)
var todoToPatch = Todos.FirstOrDefault(x => x.id == id);
if (todoToPatch == null) return BadRequest("Todo not found");
todo.Patch(todoToPatch);
// Now todoToPatch is updated with new values
} else {
return BadRequest();
}
return Ok();
}
The library support massive patch too:
[HttpPatch]
public IHttpActionResult PatchMultiple(DeltaCollection<Todo> todos)
{
foreach (var todo in todos)
{
if (todo.TryGetPropertyValue(nameof(Todo.id), out int id))
{
// Entity to update (from your datasource)
var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id));
if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")");
person.Patch(entityToPatch);
}
else
{
return BadRequest("Id property not found for a todo");
}
}
return Ok();
}
If you use Entity Framework, you have to add only two lines of code after the call to the Patch method:
entity.Patch(entityToPatch);
dbContext.Entry(entityToPatch).State = EntityState.Modified;
dbContext.SaveChanges();
Furthermore, you can exclude some properties to be updated when the Patch method is called.
Global.asax or Startup.cs
DeltaConfig.Init((cfg) =>
{
cfg.ExcludeProperties<Todo>(x => x.id);
});
This is usefull when you are working with an entity and you don't want to create a model.