Difference between HttpGet and HttpPost in Asp.Net Web Api - json

I am a beginner in web api asp.net MVC and I have a problem.
I have a class that I will use in web api HttpGet and HttpPost:
public class Credit
{
public string Log {get; set;}
public string Pas {get; set;}
}
In the example API controller I have:
[HttpGet]
public void Login (Credit credit)
{
}
[HttpPost]
public void Login (Credit credit)
{
}
Tests of these methods in RestConsole in Google Chrome, sending json data:
{"Log", "test", "Pas": "test"}
When debugging these methods, I see that HttpPost is working properly and parameter of "credit" is filled with properties.
However HttpGet is not working properly, the object is not filled property, it is NULL.
Can someone explain to me this situation and how can I get the complete object in the HttpGet?

This is because of how Web API creates parameter values from the HTTP request.
By default, if the parameter is a "complex" type (such as your Credit class), Web API gets the parameter value from the body of the request. If the parameter is a "simple" type (e.g., int or string), then Web API gets the value from the request URI.
However, HTTP GET requests cannot have a request body. So by default you can't pass a complex type to a Web API "GET" method.
You can read more here: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
In any case, for a Login method, you probably should use a POST request, not a GET request.

Related

Create new Web Service Endpoint in Acumatica

I am new with Acumatica Web Service Endpoints. I have used couple of examples of how I can get the data from certain tables, but the thing is that I want to make one new API link, which will be used as POST from one external app.
When the data is sent, my Graph would take the data, and use the existing DACs to save the sent data....I already have all the DACs so in general I would need to :
provide a link for external POST call
when called, to authenticate the user and in case that the authentication is ok
to receive the data, and convert it into my objects....
save the data and the attachments
logout
Is Acumatica that much flexible ? When the data is received, the easiest way is to use the Newtonsoft json to convert into object...but that is also not the case here....
I am pretty confused which approach I can use....any suggestions?
All of this methods I have used within simple console app...but Acumatica is much more complex....
You can implement the IWebhookHandler of Acumatica for the creation of the Incoming Webhooks.
Below is a demo implementation of that interface
using Newtonsoft.Json;
using PX.Data;
using PX.Data.Webhooks;
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Results;
namespace DemoIncomingWebhook
{
public class MyDemoWebhook : IWebhookHandler
{
[Serializable]
public class MyDemoWebhookResponse
{
public string Status { get; set; }
public string Mesage { get; set; }
}
public async Task<IHttpActionResult> ProcessRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// In this method, the developer needs to process a request from an external application,
// including the following:
// • Process authentication information in the request
// • Transform the data in external format to the data that can be saved in Acumatica ERP
// • Invoke graph methods that save the data in Acumatica ERP
return await Task.FromResult(new JsonResult<MyDemoWebhookResponse>(new MyDemoWebhookResponse
{
Status = "Success",
Mesage = "Demo webhook worked!"
}, new JsonSerializerSettings(),Encoding.ASCII,request));
}
}
}
Then you need to register your webhook on the Webhooks page, Acumatica will generate the URL when the record is saved.
After that, you can use webhook and send a POST request to it

Validate json values in response body before sending to spring controller to avoid response code 400

My Spring controller accepts application json response body as an object parameter. I don't see where I can intercept the json to validate the values before Spring controller receives it and complains when it doesn't cast.
Example: User sends json to endpoint - /createUser
Expecting: {"username":"johndoe", "pin": 1234}
Receives: {"username": 1234, "pin": "johndoe"}
If string is sent for int or vice versa, server will show status 400. I'd like to validate the data myself and provide a custom json that details the values that are incorrectly set.
Thanks in advance!
You could create your own class for the #RequestBody param in your controller and make a validation on them. You could use some supported annotations or create on your own. But don't forget to put the #Valid next to the #RequestBody, that's the key. E.g
#RestController
public class UserController {
#PostMapping("/users")
ResponseEntity<String> addUser(#Valid #RequestBody User user) {
// persisting the user
return ResponseEntity.ok("User is valid");
}
// standard constructors / other methods
}
For more information, you could find them here validation, create your own validator.

.Net Core 2.1 ModelBinding not working when posting JSON

I have a .net core 2.1 solution comprising a web app, an API and a bunch of libraries.
I am trying to post JSON into a controller in the web project and it is not working - it appears that the properties that I am setting in the JSON are just being set to their default values.
I have tried with and without the [FromBody] attribute and had no luck either way.
This is what I have in the controller
[HttpPost]
public async Task<JsonResult> Search([FromBody] int test)
{
Json(new
{
IThinkYouPassed=test,
});
}
Nothing out of the ordinary there.
I am posting to this using PostMan with the following body :
{
"test":"234"
}
If i put a breakpoint in the action and hit it and I can see that the value of test is 0.
I don't have this issue with the actions in the API project so there must be something missing from the web project - some setup that needs to be done in order for this to work?
I get the same result when using jquery to post the data so Im fairly sure that the issue is with the web app rather than something I am missing in postman.
I thought that maybe the InputFormatter might not be specified but Im told that should happen automatically as part of the UseMVC extension?
Any help with this appreciated.
Your json is an object that contains the test field. You should change
public async Task<JsonResult> Search([FromBody] int test)
to
public async Task<JsonResult> Search([FromBody] TestDto testDto)
where TestDto.cs contains the test field
public class TestDto {
public int Test { get; set; }
}

Error posting JSON to Web API 2 : The request entity's media type 'text/plain' is not supported for this resource

I have this class :
public class MyClass
{
public MyClass() { Secret = "Don't tell me"; }
public string Name { get; set; }
public int Age { get; set; }
public string Description { get; set; }
private string Secret { get; set; }
}
And this WEB API method :
// POST api/fixture
public HttpResponseMessage Post(MyClass value)
{
return new HttpResponseMessage(HttpStatusCode.Created);
}
I've set Web API to return JSON instead of XML and I haven't done any other change to the default config. I'm trying to test this method with the RESTClient extension of Firefox. Here is my request :
POST localhost:XXXX/api/fixture
Content-Type: application/json
Accept: application/json
Content-Length: 60
{
value : { "Name":"Cosby","Age":"13","Description":"OK" }
}
However I'm getting this error :
{"Message":"The request entity's media type 'text/plain' is not supported for this resource.","ExceptionMessage":"No MediaTypeFormatter is available to read an object of type 'MyClass' from content with media type 'text/plain'.","ExceptionType":"System.Net.Http.UnsupportedMediaTypeException","StackTrace":" at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)\r\n at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)"}
Edit:
I don't understand because it seems that the method is not even called. If I debug, I see that the constructor is called and then no other method is called. No exception is raised.
I've been on this issue for a lot of time now. I've found that this problem usually happens when Content-Type is not set properly but it doesn't seem to be my case since the request is not even processed.
Any idea ?
Thanks
Inside POSTMAN, you only need to change the setting to application/json. Refer image below.
You were sending the content-type of application/json in the body, rather than as a header. So your POST request was defaulting to text/plain. The RestClient extension has a separate place to enter the header.
If you ever have a question about what's being sent over the wire, check the Network tab in your browser's developer tools, or use a tool such as Fiddler to see the network traffic.
Probably you need to add following contents in your HTTP request header:
Content-Type: application/json
Use Postman to test your Web API, configure it to have header: content-type: application/json Since that is a POST request, you have to put the raw json data.
I got this problem when I had a controller that had two different models in the params. The Post method was using a model that was not specified in the builder.EntitySet The way I solved this is to create a separate read and write controllers. This is along the lines of CQRS. Although the API specs become more messy.. thank god for Swagger!

ASP.NET MVC: Specify value provider on a per-action or per-route basis?

I'm trying to set up an action in ASP.NET MVC 3 to handle the payload of a mercurial webhook request - in this case, generated by Kiln.
The payload is JSON, but unfortunately it is sent as a URL encoded form value with the content type application/x-www-form-urlencoded, because apparently using application/json and sending it unencoded with no parameter name would make it too easy and um... standard.
This means that I can't just use the new JsonValueProviderFactory because it only picks up requests using the standard application/json content type. And of course I can't just kludge the factory to also pick up application/x-www-form-urlencoded requests too, because I need those requests to use the form data value provider everywhere else in my app that's actually receiving form data and not JSON.
So, is there a way I can specify that a ValueProvider or ValueProviderFactory should only be used for a specific action or route?
If you create a specific controller to handle these webhook requests, you can assign your unique ValueProvider when you instantiate your controller.
public class KilnController : Controller
{
public KilnController()
{
this.ValueProvider = MyCustomValueProvider;
}
...
}
This should fulfill your need for a custom ValueProvider for these requests.
Turns out that IValueProvider was not the particular bit of extensibility I was looking for - I just needed to use a quick IModelBinder implementation I found courtesy of James Hughes. It needed a little tweaking to cover pulling something out of the form:
public class JsonFormModelBinder : IModelBinder
{
#region [ ModelBinder Members ]
Object IModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
var jsonStringData = request.Form[bindingContext.ModelName];
if (jsonStringData != null) return JsonConvert.DeserializeObject(jsonStringData, bindingContext.ModelType);
else return null;
}
#endregion
}
And the usage:
[HttpPost]
public ActionResult WebHook([ModelBinder(typeof(JsonFormModelBinder))] WebHookMessage payload)
{
return Content("OK");
}