WebApi POST method not found but GET works - c#

I tried many time today to call a web api function with POST (HttpClient.PostAsync) method . But unfortunately I can't.
Only the call with GET (HttpClient.GetAsync) method working with success.
I try to follow many sample on the net, but always the same error. ("Not Found")
Thank you so much if somebody can help me
Here is the C# Web API:
[RoutePrefix("NewAreaMap")]
public class NewAreaMapController: ApiController
{
[HttpPost]
[ActionName("PostCreateAreaTemp")]
public AreaTemp PostCreateAreaTemp(double southLatitude, double westLongitude, double northLatitude, double eastLongitude, int countryId, int worldId)
{
AreaTemp newTempMap = new AreaTemp();
//.....
* * Here is the C# code from client side: * *
using(var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["SrvWebApiPath"].ToString());
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var values = new Dictionary < string,
string > ()
{
{
"southLatitude", southLatitude.ToString()
},
{
"westLongitude", westLongitude.ToString()
},
{
"northLatitude", northLatitude.ToString()
},
{
"eastLongitude", eastLongitude.ToString()
},
{
"countryId", countryId.ToString()
},
{
"worldId", worldId.ToString()
}
};
var content = new FormUrlEncodedContent(values);
HttpResponseMessage response = await client.PostAsync("api/NewAreaMap/PostCreateAreaTemp", content)
if (response.IsSuccessStatusCode)
{
string jsonData = response.Content.ReadAsStringAsync().Result;
newAreTemp = JsonConvert.DeserializeObject < AreaTemp > (jsonData);
}
}
The GET call work well with the following Url :
HttpResponseMessage response = await client.GetAsync("api/NewAreaMap/GetAreaTemp/?latitudeAreaCenter=7.02&longitudeAreaCenter=9.05");

Since you're posting a JSON, you might as well send it as an object. Or if you still want to keep the dictionary and the signature for the method you could try:
var content = new StringContent(JsonConvert.SerializeObject(values),
Encoding.UTF8, "application/json");
Instead of
var content = new FormUrlEncodedContent(values);
Here's an example with an object.
public class SampleObject
{
public double SouthLatitude { get; set; }
public double WestLongitude { get; set; }
public double NorthLatitude { get; set; }
public double EastLongitude { get; set; }
public int CountryId { get; set; }
public int WorldId { get; set; }
}
And change your request.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["SrvWebApiPath"].ToString());
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var obj = new SampleObject
{
SouthLatitude = southLatitude,
WestLongitude = westLongitude,
NorthLatitude = northLatitude,
EastLongitude = eastLongitude,
CountryId = countryId,
WorldId = worldId
};
// Send it as StringContent.
var request = new StringContent(JsonConvert.SerializeObject(obj),
Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("api/NewAreaMap/PostCreateAreaTemp", request)
if (response.IsSuccessStatusCode)
{
string jsonData = response.Content.ReadAsStringAsync().Result;
newAreTemp = JsonConvert.DeserializeObject<AreaTemp>(jsonData);
}
}
And the signature on the server.
public AreaTemp PostCreateAreaTemp(SampleObject sampleObject)
Or if needed:
public AreaTemp PostCreateAreaTemp([FromBody]SampleObject sampleObject)

replace your method parameter with object because you are passing full object
"content" from the httpclient so in that case you need to use same object here also with [frombody] attribute
methodname([FromBody] Content content)
define all the properties in one class and use . Hope it will helpful for you.

Please try to use FromBody attribute with your action parameter.

Related

I am trying to submit an object that contains some data and a file from the client app to the API app using ASP.CORE 5

I have tried to submit an object from client app to an API which contains some data and a file, but I failed to do so.
Here is the code:
(1) The model:
public class ABC
{
public int Id { get; set; }
public string Image { get; set; }
public string Name { get; set; }
[NotMapped]
public IFormFile File { get; set; }
}
(2) The client app controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ABC aBC)
{
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(JsonConvert.SerializeObject(aBC), Encoding.UTF8, "application/json");
using (var response = httpClient.PostAsync(BaseURLManager.BaseUrl + "ABCs", content))
{
var apiResponse = response.Result.Content.ReadAsStringAsync();
aBC = JsonConvert.DeserializeObject<ABC>(apiResponse.Result);
}
}
return View(aBC);
}
(3) The API controller
// POST: api/ABCs
[HttpPost]
public async Task<ActionResult<ABC>> PostABC([FromForm] ABC aBC)
{
_context.ABC.Add(aBC);
await _context.SaveChangesAsync();
return CreatedAtAction("GetABC", new { id = aBC.Id }, aBC);
}
Could any one provide me a working code, I am using ASP.NET Core 5.
Thank you in advance
Since you use the FromForm attribute inside the api method, you should send request in formdata instead of json format.
More details, you could refer to below codes:
var client = new HttpClient
{
BaseAddress = new("https://localhost:7105/api/")
};
var path = $"{_hostEnvironment.ContentRootPath}test.json";
var stream = System.IO.File.OpenRead(path);
var request = new HttpRequestMessage(HttpMethod.Post, "PostABC");
var content = new MultipartFormDataContent
{
// file
{ new StreamContent(stream), "File", "test.json" },
// payload
{ new StringContent("1"), "Id" },
{ new StringContent("bbbb"), "Image" },
{ new StringContent("ccc"), "Name" }
};
request.Content = content;
var re = client.SendAsync(request).Result;
Result:

Compare a string within the API response and get a value

I have a REST API endpoint that we need to query to get the data within the response I need to filter for a value. Below is my code for querying the endpoint
public async Task<RmRoom> GetRoomsDeatil()
{
RmRoom retRoom = new RmRoom();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_iconfiguration.GetSection("RM").GetSection("BaseAddress").Value);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/rooms").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
retRoom = JsonConvert.DeserializeObject<RmRoom>(result);
}
return retRoom;
}
}
RmRoom Model class is like
public partial class RmRoom
{
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
The JSON response is like
[
{
"id": 1,
"name": "A2 SA",
"description": "Blu"
},
{
"id": 2,
"name": "A5 PA",
"description": "Red"
}
]
With in my logic I need to call the above GetRoomsDeatil() method and get all the details and check if my String updatedName matches the name field (string before the first space like A2 or A5) in the response and get just its ID
public IQueryable<Inventory> GetInventories(InventorySearch inventorySearch, string rmName)
{
string updatedName = rmName.Substring(0, rmName.IndexOf(' '));
RmRoom rmDetail = GetRoomsDeatil();
string rmID = "";
I am not sure how to check that with the response object and get only its ID.. Any help is greatly appreciated
First off, get rid of the .result in your async method please
Anyway, looks like your response is List and not RmRoom (based on the Json)
so why not just go
public async Task<RmRoom> GetRoomsDetail(string roomName)
{
RmRoom retRoom = new RmRoom();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_iconfiguration.GetSection("RM").GetSection("BaseAddress").Value);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/rooms").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
var retRooms = JsonConvert.DeserializeObject<List<RmRoom>>(result);
foreach(var room in retRooms)
if(RoomNamesMatch(room.name, roomName))
return room;
throw new Exception($"No room found with name {roomName}");
}
else //format this with whatever info you wanna share
throw new Exception($"Request to get rooms failed with message {response.Message}");
}
}
private bool RoomNamesMatch(string name1, string name2){
//put matching logic here, or make this a method on the room object, up to you
}

PostAsJsonAsync returns 500 Internal Error

I have been searching solution for few hours and I can't find answer to my problem.
I want to send a post method to a web api and I've tried it first on postman using these json content and it is working.
{
"ETickets": [
{
"TicketName": "Weekend - Regular Day Pass",
"TicketAccessType": "PA",
"TicketGuest": "RDP",
"IsWeekday": true
},
{
"TicketName": "Weekend - Regular Day Pass",
"TicketAccessType": "PA",
"TicketGuest": "RDP",
"IsWeekday": true
}
],
"TransactDetails": {
"CompanyCode": "ONLINE",
"Surname": "Dela Cruz",
"FirstName": "Juan",
"BookingReference": "1113",
"BookingDate": "2018-08-16T11:31:20:04"
}
}
However, when I try it in coding style, I can't make it to work. It says 500 internal server error upon debugging.
Here's the error screenshot:
Here's my few codes related to my issue:
TransactionDetailsViewModel finale = new TransactionDetailsViewModel();
finale.TransacDetails = transacDetail;
finale.ETickets = lsTickets.ToArray();
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", System.Web.HttpContext.Current.Session["WebApiAccessToken"].ToString());
HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url + "api/Transaction/SendTransaction/", finale);
And here's the model I'ved used:
public class TransactionDetailsViewModel
{
public TransactionDetails TransacDetails { get; set; }
public TicketDetailsModel[] ETickets { get; set; }
}
public class TransactionDetails
{
public string CompanyCode { get; set; }
public string Surname { get; set; }
public string FirstName { get; set; }
public string BookingReference { get; set; }
public DateTime? BookingDate { get; set; }
}
public class TicketDetailsModel
{
public string TicketAccessType { get; set; }
public string TicketGuest { get; set; }
public string TicketName { get; set; }
public bool IsWeekday { get; set; }
}
Do I send the data with the correct format or something to adjust to make it work on sending to a PostAsJsonAsync?
Any help will be much appreciated. Thanks.
Please, modify your code just like as
var data = new StringContent(JsonConvert.SerializeObject(finale, Encoding.UTF8, "application/json"));
HttpResponseMessage responseMessage = await client.PostAsJsonAsync("api/Transaction/SendTransaction/", data);
OR You can make request and then send like as
HttpResponseMessage response = null;
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Post, url+"/api/Transaction/SendTransaction"))
{
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", System.Web.HttpContext.Current.Session["WebApiAccessToken"].ToString());
var data = new StringContent(JsonConvert.SerializeObject(finale, Encoding.UTF8, "application/json"));
request.Content = data;
response = await client.SendAsync(request);
}
}
Please try below line to post data
httpClient.PostAsync(url + "/api /Transaction/SendTransaction/", new StringContent(JsonConvert.SerializeObject(finale).ToString(), Encoding.UTF8, "application/json")).Result;

Deserializing Json list of objects returns null

I'm trying to deserialize some Json data to a list, however the list returns no data.
An example of the Json string I am using is
{
"sequence":82334,
"bids":
[
["7660","10.02477743",11],
["7600","0.01",1],
["7500","0.01",1]
],
"asks":
[
["7672.57","0.63979186",1],
["7673.64","1",1],
["7678.95","1",1]
]
}
I used json2csharp to generate the object class which gave me
public class ProductOrderBook
{
public int sequence { get; set; }
public List<List<object>> bids { get; set; }
public List<List<object>> asks { get; set; }
}
and this is my method I'm using to deserialize the json
public static async Task<List<ProductOrderBook>> GetProductOrderBook()
{
string ts = GetNonce();
string method = "/products/BTC-USD/book?level=2";
string sig = GetSignature(ts, "GET", method, string.Empty);
List<ProductOrderBook> productOrderBooks;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseURL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("CB-ACCESS-KEY", apiKey);
client.DefaultRequestHeaders.Add("CB-ACCESS-SIGN", sig);
client.DefaultRequestHeaders.Add("CB-ACCESS-TIMESTAMP", ts);
client.DefaultRequestHeaders.Add("CB-ACCESS-PASSPHRASE", passphrase);
client.DefaultRequestHeaders.Add("User-Agent", userAgent);
HttpResponseMessage response = client.GetAsync(method).Result;
string json = await response.Content.ReadAsStringAsync();
productOrderBooks = JsonConvert.DeserializeObject<List<ProductOrderBook>>(json);
}
return await Task.Run(() => productOrderBooks);
}
I am getting valid Json returned in the response string, not sure why the productOrderBooks list has no data. Do I have to create two more object classes to hold the bid and ask data and pass these into
public List<List<object>> bids { get; set; }
public List<List<object>> asks { get; set; }
As per your posted json, it is not list of ProductOrderBook. It's just single instance of ProductOrderBook.
So, your code should be :
public static async Task<ProductOrderBook> GetProductOrderBook()
{
string ts = GetNonce();
string method = "/products/BTC-USD/book?level=2";
string sig = GetSignature(ts, "GET", method, string.Empty);
ProductOrderBook productOrderBooks;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseURL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("CB-ACCESS-KEY", apiKey);
client.DefaultRequestHeaders.Add("CB-ACCESS-SIGN", sig);
client.DefaultRequestHeaders.Add("CB-ACCESS-TIMESTAMP", ts);
client.DefaultRequestHeaders.Add("CB-ACCESS-PASSPHRASE", passphrase);
client.DefaultRequestHeaders.Add("User-Agent", userAgent);
HttpResponseMessage response = client.GetAsync(method).Result;
string json = await response.Content.ReadAsStringAsync();
productOrderBooks = JsonConvert.DeserializeObject<ProductOrderBook>(json);
}
return await Task.Run(() => productOrderBooks);
}

Call HttpPut with parameter C#

So I create an HttpPut method in an ASP.NET web api.
[Route("api/Account/Save")]
[HttpPut]
public IHttpActionResult SaveAccount(Account acc) {
// do stuff
}
I pass in an instant of the Account class.
class Account
{
public int AccountID { get; set; }
public string AccountName { get; set; }
}
Now I want to call this from a console application. I am trying to do this but it's not working. It's not throwing any exception either.
var acc = new Account() { AccountID = 1234, AccountName = "zzzzP" };
string json = JsonConvert.SerializeObject(acc);
HttpContent content = new StringContent(json);
response = await client.PutAsync("api/Account/Save", content);
Json returned:
"{\"AccountID\":1234,\"AccountName\":\"zzzzP\"}"
You probably want something like this
static async Task PutAccount()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://yourWebSite.com");
var acc = new Account() { AccountID = 1234, AccountName = "zzzzP" };
string json = JsonConvert.SerializeObject(acc);
using (HttpResponseMessage response = await client.PutAsync("api/Account/Save", new StringContent(json)))
{
return response.EnsureSuccessStatusCode();
}
}
}

Categories