ApiController model binding properties not binding - c#

I'm currently trying out the new ApiController available with WebAPI - namely the POST method as I'm having no luck with binding the properties for the model.
This is my code for the ApiController:
public class GameController : ApiController
{
public void Post([FromBody]GameVMTest gameVM)
{
}
}
In this example, I'm able to make a HTTP Post to this method. The GameVM property is initialised but none of the properties bind.
So I thought this might be caused by my method of HTTP Post and so I wrote another Post method but this time, using just a class that inherits a Controller class:
public class TestController : Controller
{
[HttpPost]
public void Post(GameVMTest gameVM)
{
}
}
I used the same HTTP Post to this TestController Post method and everything works just fine.
Any idea on why the property binding works for a class inheriting the Controller class but not the ApiController class?
Note: I have tried removing the [FromBody] attribute and this does nothing.
Note: GameVM property contains simple String & Int variables - nothing complex.
Thanks in advance.
Note:
The http post call is from an iOS app using Alamofire.
Below is the JSON String passed to the two methods above:
"{\"isDirty\":1,\"courtName\":\"Court 1\",\"id\":11418,\"team1\":\"Kenja Hurricane\",\"team2\":\"Sons of Asia\",\"roundId\":528}"

After reading this
https://lbadri.wordpress.com/2014/11/23/web-api-model-binding-in-asp-net-mvc-6-asp-net-5/
Turns out the body of the request has to be very specific for WebAPI!!!

Related

Is there an OOTB component to get routes from controller names and their methods?

I would like to list all the available endpoints a controller provides.
Is it possible to access the component(s) .NET uses to generate these routes (by, for instance providing it a type or controller name (string))?
The methods/verbs (so, POST, GET) are not even that important for my scenario, just the routes themselves.
Example
Please, take a look on the below ASP.NET Core code.
[ApiController]
[Route("[controller]")
public class HomeController : ControllerBase
{
[HttpGet("additional")]
public async Task<IActionResult> Whatever()
{
// ...
}
}
So, the method will be exposed as a GET endpoint on the URL of Home/additional.

Problem sending model to HttpPost method in a .net core 3.1 web api application

I'm trying to hit my HttpPost method in a .net core 3.1 application.
When i try to hit it, the model object is created but none of the properties are set.
The behaviour is same when i try to invoke using Swagger as well as postman.
I tried to add a model as simple as :
public class Student{
public string Name{get; set;}
}
[HttpPost]
[Route("TestMethod")]
public void TestMethod(Student stu) {}
public void TestMethod(string name) {}
The strange behaviour is, if i pass it as query string, it works, but somehow it doesn't work with json (using postman). Also, if i create a demo app, it works perfectly fine, but not with my existing application
i used FromBody attribute as well.
Can someone help me with this?
you have to use this action
[HttpPost]
[Route("TestMethod")]
public IActionResult TestMethod([FromBody]Student stu) { return Ok(stu.Name)}
For a Post acton using Postman you have to select Body, raw, JSON in Postman menus. Your json should be
{ "Name":"Doe" }

Why derive from ControllerBase vs Controller for ASP.NET Core Web API?

I am following this tutorial for creating an ASP.NET Core Web API, and in the section on adding a controller, the tutorial gives code to replace the template code for a controller. One of the things that really caught my eye was that in the template code, I get:
TodoController : Controller
Then in the tutorial code I'm supposed to use instead of that, I find:
[Route("api/[controller]")]
[ApiController]
TodoController : ControllerBase
I'm very interested to know why it is necessary to derive from ControllerBase instead of Controller for a Web API controller. Why is this done?
why it is necessary to derive from ControllerBase instead of Controller for a Web API controller.
It is not strictly necessary, just more to the point. The Controller class derives from ControllerBase and adds some members that are only needed to support Views.
Basically:
public abstract class Controller : ControllerBase
{
public dynamic ViewBag { get; }
public virtual ViewResult View(object model) { }
// more View support stuff
}
When you write an API then ControllerBase matches your requirements better but both will work.
From the documentation (emphasis mine):
Don't create a web API controller by deriving from the Controller class. Controller derives from ControllerBase and adds support for views, so it's for handling web pages, not web API requests. There's an exception to this rule: if you plan to use the same controller for both views and web APIs, derive it from Controller.
I seem to remember that there was no ControllerBase in the first MVC iterations, it was inserted later. Hence the slightly odd naming/inheritance structure.
FROM https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.1
Don't create a web API controller by deriving from the Controller class. Controller derives from ControllerBase and adds support for views, so it's for handling web pages, not web API requests.
One other important difference is that ControllerBase is abstract class that's why it doesn't implement Dispose method. So you need to handle yourself. see this SO entry
ControllerBase abstract class
Controller abstract class derives from ControllerBase abstract class therefore supports to Create views ,API Not Advice to Create Views .
ControllerBase abstract class has Member[Properties,Methods] without Implementaion Like
public abstract class ControllerBase{
public HttpResponse Response { get; }
public HttpRequest Request { get; }
public HttpContext HttpContext { get; }
public virtual RedirectToActionResult RedirectToAction(string actionName);}
ControllerBase has all Request and Response between Client-side and
Server-side
Controller abstract class
Controller abstract class Enables us To Create Views to display Data
in client-side, it derives from ControllerBase abstract class.
public abstract class Controller : ControllerBase{
public dynamic ViewBag { get; }
public ViewDataDictionary ViewData { get; set; }
public ITempDataDictionary TempData { get; set; }
}
https://newbedev.com/why-derive-from-controllerbase-vs-controller-for-asp-net-core-web-api

MVC trying to do a Get request

I am trying to do a GET request on MVC 4.0 (WebServiceREST) that some method use POST and other use GET but I cant make it works
I used [System.Web.Mvc.AcceptVerbs(HttpVerbs.Get)] but It didnt work still getting "The requested resource does not support the HTTP 'GET' method"
My Controller:
public class RecuperarDatosAppController : ApiController
{
#region RecuperarClasesColectivas
[System.Web.Mvc.AcceptVerbs(HttpVerbs.Get)]
[ResponseType(typeof(List<ActividadesColectivas>))]
public IHttpActionResult RecuperarClasesColectivas(short idInstalacion, string secretKey = "NOSECRETKEY")
{
BsSecurity bSecurity = new BsSecurity(BsSecurity.Tipo.Publica);
if (bSecurity.comprobar(secretKey))
{
BsActividadesColectivas bsActividades = new BsActividadesColectivas();
return Ok(bsActividades.GetActividadesColectivas(idInstalacion));
}
return NotFound();
}
#endregion
}
Though you state this is MVC and tagged it as such, it's actually Web API, because you're inheriting from ApiController. So you should decorate the method with the [HttpGet] attribute from the System.Web.Http namespace. Note that renaming it to have Get prepended like Yoink is suggesting isn't necessary, although that is the common convention.
I believe you need to prepend "Get" to methods that you wish to expose by by GET requests.
So try GetRecuperarClasesColectivas instead of RecuperarClasesColectivas.
You'll still call it by /api/RecuperarClasesColectivas/id for example, the routing just needs the "Get" part adding.

POST data using RenderMvcController in Umbraco

I have set up a document type in Umbraco, and have created a custom controller & model for this document type.
The custom controller inherits from : RenderMvcController class and the views inherit the model through #inherits Umbraco.Web.Mvc.UmbracoViewPage<com.something.model>
This all works fine for any HttpGet requests. However as soon as I want to do a form post back to the controller using #using (Html.BeginUmbracoForm("SomeAction", "SomeController", null, new { #class = "some-class" }))
I get the following error message: Could not find a Surface controller route in the RouteTable for controller name SomeController
From all the documentation that I was able to find it always refers to SurfaceControllers when it comes to form posts. Is there a way to change the routing so that it would post to my custom controller, rather then another controller that inherits from the SurfaceController class?
If you are going to post the form in this way, you need two controllers. One for the Document Type that inherits from MvcRenderController (as you already have) and a second which inherits from the SurfaceController.
The surface controller just needs a single POST action that does one of the following things:
// e.g. if modelstate is invalid
return CurrentUmbracoPage();
// redirecting back to original page after a successful post
return RedirectToCurrentUmbracoPage();
// Redirecting to another page after a successful post
return RedirectToUmbracoPage(12345)
This has been taken from the documentation here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/forms
Strictly speaking the initial document type controller is not necessary in this scenario as it does not play a part in the post of the form.
If you want to post directly to the custom controller then you should not use Html.BeginUmbracoForm, you should just post directly to the current URL. The complication here is that it is then a little tricky to bind your model as a parameter of the post action. Your view model will have to inherit from RenderModel in the following way:
public class BaseModel : RenderModel
{
public BaseModel() :
base(UmbracoContext.Current.PublishedContentRequest.PublishedContent) { }
}
According to http://our.umbraco.org/forum/developers/api-questions/38662-(v6)-Could-not-find-a-Surface-controller-route-error?p=0,
SomeController Needs to inherit from SurfaceController, not RenderMvcController.
Alternatively, you could create a dedicate route and point it directly to your controller:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("someController", "some/someAction",
new { controller = "Some", action = "SomeAction" });
}
}

Categories