Web API Post won't bind data to method parameters - asp.net-web-api2

I hate to ask because there are many questions dealing with this issue, but I haven't gotten any to post any data to an ASP.NET Web API 2 method. This is all coming and going to the same host and port.
Here's my server side code:
[RoutePrefix("api/help")]
public class HelpAPIController : ApiController
...
public class Item {
public string name { get; set; }
public string position { get; set; }
}
[Route]
[HttpPost]
public void Post([FromBody] Item[] stuff)
; // we get here but data is always null or zero items in array
}
Javascript:
"use strict";
var a = [{ "name": "me", "position": "here" },
{ "name": "me", "position": "here" },
{ "name": "me", "position": "here" }];
jQuery.ajax({
type: "POST",
datatype: "application/json",
url: "/api/help/",
data: { "stuff": JSON.stringify(a) },
success: function (data) { alert(data); },
error: function (error) {
...
}
});
Actual request content (no hard returns):
stuff:[{"name":"me","position":"here"},
{"name":"me","position":"here"},
{"name":"me","position":"here"}]

You are not passing a content type to the server. datatype is what response type you expect from the server. contentType is what you are sending. The default contentType in jQuery is application/x-www-form-urlencoded; charset=UTF-8. You need to add/edit:
dataType: "json",
contentType: "application/json",
You don't need to wrap the data array with an object. This will do:
data: JSON.stringify(a),

Try adding contentType: "application/json" in your Ajax POST.
You have dataType, which I think is what you expect back from server whereas contentType is what you are sending.

Related

How can I pass the Session ID in API Request via Apps Script?

I am trying to access the API of our CRM Documentation through Google Sheets / Apps Script.
When accessing the API through Postman I have no issues and get the desired results using the following setup:
POST: https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}
BODY:
{
"id":"12345678912345678999",
"method": "getOpportunities",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
Now, when I try to replicate the same in Apps Script I get the following result:
{ result: null,
error: { code: 102, message: 'Header missing request ID', data: [] },
id: null }
The function that I am running is as below:
function myFunction() {
var URL = "https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}"
var body = {
"method": "POST",
"body": raw,
"headers": {"Content-Type": "application/json"},
"redirect": "follow"
}
var raw = {
"method": "getOpportunities",
"id": "12345678912345678999",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
var results = UrlFetchApp.fetch(URL, body).getContentText();
var data = JSON.parse(results);
console.log(data);
}
In both I am passing a random session ID "12345678912345678999". I tried finding a session ID in the cookie but that didn't work and I assume that I am on the wrong path there. Passing the id in the header directly didn't work either.
Any ideas? Thanks a lot in advance!

return Page() in ASP.NET Core Razor Pages doesn't render the page after calling by RedirectToPage

I'm new to ASP.NET Core Razor Pages.
In the index page I get the customers data and show them in a jQuery data table by ajax from the CustomerController. In the last column there are delete buttons. By these buttons I call delete method in the CustomerController.
JS Ajax file
$(document).ready(function() {
$("#customerDataTable").dataTable({
"processing": true,
"serverSide": true,
"filter": true,
"ajax": {
"url": "/api/customer",
"type": "post",
"datatype": "json"
},
"columnDefs":[
{
"targets": [0],
"visible": false,
"searchable": false
}],
"columns":[
{ "data": "id", "name": "Id", "autoWidth": true },
{ "data": "firstName", "name": "First Name", "autoWidth": true },
{ "data": "lastName", "name": "Last Name", "autoWidth": true },
{ "data": "contact", "name": "Contact", "autoWidth": true },
{ "data": "email", "name": "Email", "autoWidth": true },
{ "data": "dateOfBirth", "name": "Date Of Birth", "autoWidth": true },
{
"render": function(data,type, row) {
return "<a href='#' class='btn btn-danger' onclick=deleteCustomer('" + row.id + "');
>Delete</a>"; }
}]
});
});
function deleteCustomer(id) {
$.ajax({
url: "/api/customer",
type: "GET",
data: id
});
}
In the CustomerContoller I want to redirect to DeleteCustomer razor page with a parameter.
[HttpGet]
public IActionResult DeleteCustomer()
{
var id = Request.Query.Keys.ToList()[0];
return RedirectToPage("/DeleteCustomer", new{id});
}
In the DeleteCustomer Page there is a simple get method.
[BindProperty]
public int CustomerId { get; set; }
public IActionResult OnGet(string id)
{
CustomerId = int.Parse(id);
return Page();
}
When I debug the app line by line CustomerControll redirect to DeleteCustomer page properly, and the OnGet method in the page return the Page() method, but browser doesn't render the HTML part of the page without any errors. Just Index page still showed with the table of data.
If I call DeleteCustomer page in address bar DeleteCustomer page will rendered.
Why return Page() doesn't render and show the page after calling by RedirectToPage in the browser?
Why return Page() doesn't render and show the page after calling by RedirectToPage in the browser?
You make Ajax request from your client side, which does not automatically reload/refresh page. To display returned page content, you can try to dynamically write it in success callback function, like below.
$.ajax({
url: "/api/customer",
type: "GET",
data: id,
success: function (res) {
//console.log(res);
document.write(res);
}
});
Besides, you can also try to modify the approach to make your API action DeleteCustomer return an id, then do redirection on client side, like below.
[HttpGet]
public IActionResult DeleteCustomer()
{
//your code logic here
//var id = Request.Query["id"];
//return RedirectToPage("/DeleteCustomer", new { id });
return Ok(new { id });
}
On client side
success: function (res) {
console.log(res.id[0]);
window.location.assign("/DeleteCustomer?id=" + res.id[0]);
//document.write(res);
}

Return string from Web API .NET Core get operation

I have a get operation that I want to return a string from. An example would be
"000875"
When I return this string from a controller in my Web API Controller in full .NET, it formats it like this:
{
"Property": "000875"
}
When I return the string in my converted .NET Core Controller it returns this:
{
"$id": "1",
"$type": "System.Net.Http.HttpResponseMessage, System.Net.Http",
"Version": "1.1",
"Content": {
"$id": "2",
"$type": "System.Net.Http.StringContent, System.Net.Http",
"Headers": [
{
"Key": "Content-Type",
"Value": [
"application/json; charset=utf-8"
]
}
]
},
"StatusCode": "OK",
"ReasonPhrase": "OK",
"Headers": [],
"TrailingHeaders": [],
"RequestMessage": null,
"IsSuccessStatusCode": true
}
It is interesting to note that the value is not even in there!
I am running some interesting JSON Serialization to make BreezeJs work with .NET Core. It is possible that it is the cause of this weirdness:
.AddNewtonsoftJson(opt =>
{
// Let Breeze say how we serialize. This adds in the Type and Id options the way breeze expects
var jsonSerializerSettings = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings);
......
I am hoping for a way to get strings through without all this mess. Can that be done?
I get the impression that the subject action definition returns HttpResponseMessage.
public HttpResponseMessage MyAction(....
HttpRequestMessage is no longer a first class citizen in asp.net-core framework and will be treated as a normal model and serialized.
That explains the JSON you are seeing with your controller
The syntax needs to be updated to return IActionResult derived responses
public IActionResult MyAction() {
//...
return Ok("000875");
}
ActionResult<T>
public ActionResult<string> MyAction() {
//...
if(somecondition)
return NotFound();
return "000875";
}
or the model itself.
public string MyAction() {
//...
return "000875";
}
Reference Controller action return types in ASP.NET Core Web API

Custom ASP.Net Core JSON model binder

My posted JSON object is this:
{{
"emails": [
{
"To": "info#gmail.com",
"Subject": "Subject",
"Body": "Body",
"ID": "d3d13242-6eff-4c57-b718-ef5ad49fe301"
},
{
"To": "hr#gmail.com",
"Subject": "Subject",
"Body": "Body",
"ID": "101edaf0-fcb4-48fc-9e9e-0d7492b591b0"
}
]
}}
By default ASP.NET model binder will not bind this JSON object and as you can see here I get always null when I send post request to the API:
[HttpPost, Route("Send")]
public async Task<IActionResult> Send(Email[] emails)
{
var toSave = from email in emails
select new EmailQueueItem
{
Html = true,
To = email.To,
Subject = email.Subject,
Body = email.Body
};
await Database.BulkInsert(toSave.ToArray());
return Ok();
}
emails property is always null. I would appreciate any help for creating custom model binder that handel this kind of JSON objects.
The issue is that you are actually sending an object containing one property named emails, not an array, to the controller
Option one:
The client object needs to contain just the array
[
{
"To": "info#gmail.com",
"Subject": "Subject",
"Body": "Body",
"ID": "d3d13242-6eff-4c57-b718-ef5ad49fe301"
},
{
"To": "hr#gmail.com",
"Subject": "Subject",
"Body": "Body",
"ID": "101edaf0-fcb4-48fc-9e9e-0d7492b591b0"
}
]
Then read the array from the request body
public async Task<IActionResult> Send([FromBody]Email[] emails)
Option 2:
When you define the array like this in the client
{
"emails":...
}
You need to match that object setup on the controller by defining a model which contains a property called emails
public class RequestModel
{
public Email[] emails { get; set; }
}
Then in the controller method, use the model and read it from the body
public async Task<IActionResult> Send([FromBody]RequestModel emails)

How to create a webhook on a repository on the GitHub web api using AJAX?

I am experimenting with Webhooks in the GitHub api. I got one working by doing it manually as in going into my repository and clicking into the setting and enabling a web hook. But now I want to do this in AJAX and I am getting problems. Anytime I try to send a POST to the web api it fails with a 400 (Bad Request). I am not sure where I am going wrong with my code.
function createWebHooksOnRepos(token){
const webhookURL = "https://api.github.com/repos/DanoBuck/AlgorithmsAndDataStructures/hooks";
const json = {
"name": "WebHook",
"active": true,
"events": [
"issue_comment",
"issues"
],
"config": {
"url": "http://39a40427.ngrok.io/api/webhooks/incoming/github",
"content_type": "json"
}
};
$.ajax({
headers: {
"Authorization": "Token " + token
},
url: webhookURL,
data: json,
type: "POST",
dataType: "json",
success: function(data){
console.log(data);
}
});
}
Thank you
From github Webhook API doc :
name - string - Required. Use "web" for a webhook or use the name of a valid
service. (See /hooks for the list of valid service names.)
So in your case, just rename Webhook to web :
const json = {
"name": "web",
"active": true,
"events": [
"issue_comment",
"issues"
],
"config": {
"url": "http://39a40427.ngrok.io/api/webhooks/incoming/github",
"content_type": "json"
}
};
Also JSON.stringify your data before sending :
$.ajax({
headers: {
"Authorization": "Token " + token
},
url: webhookURL,
data: JSON.stringify(json),
type: "POST",
dataType: "json",
success: function(data) {
console.log(data);
}
});