I am making an ASP.net core 2.0 Web API and have a method in my controller called
[HttpPost("Create")]
public void Create()
{
// var d = employee;
}
Does the HttpPost act as the same the [Route] attribute or do I need both?
For Asp.Net Core Web API you do not need both.
It acts the same as Route and is the advised approach. When using MVC with views you use Route and Http{Verb} together.
Documentation states...
When building a REST API, it's rare that you will want to use [Route(...)] on an action method. It's better to use the more specific Http*Verb*Attributes to be precise about what your API supports. Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.
Reference Routing to Controller Actions in ASP.NET Core
I would also advise having your actions return IActionResult to allow the proper HTTP Verb to be returned from the action.
[HttpPost("Create")]
public IActionResult Create() {
// var d = employee;
return Ok();
}
void actions always return 200 OK unless an exception is thrown. This limits the possible response from the action.
Related
I have a controller at .Net Core 2.2 Web API.
There is a POST method which is responsible for creation of an entity.
A current need is to add another POST method to be able to create many.
Here is the sample code I have (no other routing is used):
[Route("api/[controller]")]
public class SampleController: BaseController
{
[HttpPost]
public Task<IActionResult> Create([FromBody] SampleModel model) {...}
[HttpPost]
public Task<IActionResult> CreateMany([FromBody] IEnumerable<SampleModel> models) {...}
}
As far as exception message says these two are ambiguous routes. But for me it seems not quiet clear. In fact actions' arguments are different types. Might be I am missing something or it is a natural restriction?
In HTTP there are no "actions" and "arguments".
When your app receives POST request to api/Sample, app infrastructure must dispatch request somewhere. Create and CreateMany serves the same route, so it's impossible to choose one of them.
You can either modify route for one of these actions, e.g. using HttpPost("CreateMany")], or remove the first action, since it is superfluous.
I have an application developed in ASP.NET Core MVC with a set of controllers for normal view responses and Web API.
I am trying to figure a correct way to wrap all Web API responses with a consistent class.
My first question is what would be a correct approach to wrap the responses coming from Web API controllers. Since I have two controller types, I would need to distinguish between them as the responses should only be wrapped for API controller, and not view controllers.
As I understand there are two choices a middleware or an action filter.
At first I thought the middleware would be the best choice, but then I realized that I would still need to figure out what kind of request is being processed which would add more potential headache with maintenance?
Then I looked at an action filter and it seems that it would be a better choice to plugin the wrapping handling.
For example an action filter can be added to a base controller just for Web API and not controllers handling the views.
So the question is whether the action filters are best approach to achieve this?
I would recommend you to look at result filters for this. Result filters run after a controller action has produced a result, and it allows you to look at that result and then perform some action.
For example, when you return View in a controller action, then what gets returned is a ViewResult which makes it easy to identify results that would cause a Razor view to be rendered.
Within an API controller, you would usually return a ActionResult<T>, some model object directly, or an ObjectResult. The former two will be automatically converted into an ObjectResult as the action gets executed. So you can just look for ObjectResults and then change the result to have some wrapper object instead. This would look something like this:
public class WrapApiResponseResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ObjectResult)
{
// wrap the inner object
var newValue = new WrapperObject(result.Value);
// replace the result
context.Result = new ObjectResult(newValue)
{
// copy the status code
StatusCode = result.StatusCode,
};
}
}
public void OnResultExecuted(ResultExecutedContext context)
{ }
}
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
This is my controller:
[Route("api/[controller]")]
public class SaveRecordController : XivicControllerBase
{
#region REST Calls
[HttpPost]
public SaveRecordResponse Post([FromBody] SaveRecordRequest saveRecordRequest)
{
var retVal = new SaveRecordResponse();
try
{
ValidateRequest(saveRecordRequest);
//Save logic here [...]
}
catch (Exception ex)
{
Logger.Log(ex);
retVal.Errors.Add(new XivicError(ex.Message));
}
return retVal;
}
#endregion
}
It takes any entity, attempts to save it, and then returns the Id of the entity saved, or a collection of errors. Swashbuckle serves up the Swagger UI like so:
This works fine, but this is not what I want to expose to 3rd party integrators. I want to create multiple endpoints that are generated dynamically based on the configuration in the system of what Record types (Entities) are exposed externally). So, for example, if client x has an entity called "Job", there would be an action called SaveJob, and this would show up in the Swagger documentation.
If I add a new HttpPost attributes, I can get the new endpoint like so:
[HttpPost]
[HttpPost("SaveJob")]
public SaveRecordResponse Post([FromBody] SaveRecordRequest saveRecordRequest)
{
}
This does show up in Swagger as I would expect it to, but here comes the rub...
I cannot add attributes to the class SaveRecordController because it is a core type inside our core application assembly. External entities(record types) are defined at runtime. They are not actual types inside the application. So I don't know how to add the endpoints dynamically at runtime. I guess there are some routing options in ASP.NET Core 2.0, but the Swashbuckle documentation explicitly says
Additionally, if you are using conventional routing (as opposed to
attribute routing), any controllers and the actions on those
controllers that use conventional routing will not be represented in
ApiExplorer, which means Swashbuckle won't be able to find those
controllers and generate Swagger documents from them.
So the doco would not get generated properly. I'm stuck. What should I do?
I'm trying to follow the article Build RESTful API's with ASP.NET Web API to learn how to create a RESTful API.
I created the first project and controller, Contact.
public class ContactController : Controller
{
// GET: Contact
public string[] Index()
{
return new string[]
{
"Hello",
"World"
};
}
}
But when I load the URL in a browser, instead of getting the response described in the article (["Hello","World"]). The response I get is System.String[].
I don't understand what I'm missing.
BTW, the article is from 2013. Does anyone know of a good article that is perhaps a little newer?
What you have now is simple ASP.NET MVC controller. For Web API controller you should inherit your controller from ApiController instead of Controller:
public class ContactController : ApiController
Also action names should start with HTTP verb. If you'll send GET request to /api/contact endpoint you'll get error
The requested resource does not support http method 'GET'.
By default action name is not used in route for Web API controllers. If you'll check default route configuration, it will be api/{controller}/id. Correct action is selected via HTTP method of request. In your case it should be GetXXX or simply Get
You cannot Return regular primitives from the Web Apis. At least if not if you are using a regular MVC Web API from .net. So, if this is the case you could do something like
public class ContactController : Controller
{
// GET: Contact
public JsonResult Index()
{
return Json(new { value1: "Hello", value2: "world" }, JsonRequestBehavior.AllowGet);
}
}
Hope this helps