I'm making a call using HttpClient.
var serializedRequest= JsonConvert.SerializeObject(searchRequest);
var stringContent = new StringContent(serializedRequest, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(url, stringContent);
The object is null in the API controller:
[HttpPost]
public List<string> GetSearchResults([System.Web.Http.FromBody]SearchRequest searchRequest)
However, if I make the same call from Postman (I copied the serialized object within Visual Studio while debugging), it works. Why would that be the case? I'm trying to figure out how to send the content length with the request, but apparently that's supposed to be happening already by using StringContent.
The caller is .NET Core 2.2 and the API is .NET Framework 4.7.2.
EDIT:
This was the original call:
var response = await _httpClient.PostAsJsonAsync(url, searchRequest);
That does NOT work even when the API method isn't using [FromBody]. Looks like I need to use the above code (StringContent) along with the API method not using [FromBody]. What's weird is that a coworker isn't having this issue. It's just on my machine. Go figure.
Related
Is there any way at all that I can send a GET request with a JSON body using c#? I am making a call to an API to retrieve a list of items using a GET request, but I have to pass the customer_id in JSON. I am able to do this successfully in Postman and Python. However, the legacy app that I am working with is built as c# .NET winform. I am able to make other calls using HttpClient, but after some research I am finding that this class does not allow GET request with body except when using CORE. Are there any other alternatives?
According to Ian Kemp's answer to this question,
This can be done in .NET Framework projects using the System.Net.Http.WinHttpHandler Library. (I'll just add the relevant part of the answer here, but I recommend to go check his full answer)
First, Install the System.Net.Http.WinHttpHandler Library from Nuget and then use it as your http client handler as described below:
var handler = new WinHttpHandler();
var client = new HttpClient(handler);
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("some url"),
Content = new StringContent("some json", Encoding.UTF8, ContentType.Json),
};
var response = await client.SendAsync(request).ConfigureAwait(false);
//Handle the response as you see fit
With the HTTP method GET, the body has no meaning. It will be ignored according to the HTTP specs. When getting resources from your API using the GET http verb, you have the option to pass a query string (http://somedomain.com/api/getValues?key=1) or pass the parameter directly in the url (http://somedomain.com/api/getValues/1)
To receive it in your controller, you would have to expect either the parameter or the query string like this:
If the parameter is in the URL:
[HttpGet("/api/getValues/{id}")]
public async Task<IActionResult> GetValues(int id){}
(Make sure that your parameter name in the function matches the name that you gave to it in the route)
If the parameter is a query string:
[HttpGet("/api/getValues")]
public async Task<IActionResult> GetValues(string key){}
(Make sure that the query string key name matches the parameter name in your function)
The best practice is to use the parameter in the URL. Query strings are very useful, but you have to know when to use it, for example, if you want to narrow down the results given certain values, you could the query string to send them.
So quick background on what is currently going on in my solution. I'm writing pretty basic API web tests in c# using the XUnit framework and some json validation helpers I created to validate response messages and payloads received back from the API. I've been banging my head against a wall trying to figure out why my PostAsync() call is passing null once it reaches the API since I can see the request body is a valid json request when debugging my ApiTests solution. Below are some snippets of the test I'm currently debugging.
OrderControllerTests.cs
[Theory]
[MemberData(nameof(OrderControllerData.postCancelOrder), MemberType = typeof(OrderControllerData))]
public async Task PostValidCancelOrder(string jsonBody, string expectedResponseBody)
{
var postObject = "api/Order/cancel";
var request = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(postObject, request);
var content = await response.Content.ReadAsStringAsync();
ValidationHelper.ValidateNoErrors(response);
ValidationHelper.ValidateJson(content, expectedResponseBody);
}
A few things are happening in this test. All of which seem to be working fine and as intended (except for maybe #3 below).
Create my requestUri with postObject.
Create my HttpContent. XUnit is passing my jsonBody param by way of the MemberData attribute. Which looks into my data layer class for the postCancelOrder public static IEnumerable.
Posting the request to the API.
Reading the payload returned back in string format.
Validation Helper checks for HTTP response messages. The ValidateNoErrors method is simply just looking for a 200 response code. The second one doesn't matter for this question since my test blows up at the first ValidationHelper.
Right now this is currently what I am posting to the api.
"{\"orderId\": \"c701b60a-4fb1-4f79-9e17-0172a9a17bbc\",\"test1Fee\":\"5}\",\"test2Fee\":\"10\"}"
Here is the HttpPost within the Api/OrderController.
OrderController.cs
[HttpPost("cancel")]
public async Task<IActionResult> Cancel([FromBody]CancelOrderViewModel model)
{
var command = new CancelOrderCommand(model.OrderId, model.Test1Fee, model.Test2Fee);
var order = await _mediator.Send(command);
return Ok(order);
}
Essentially this HttpPost is passing a few parameters and then running a multiple methods and checks on those objects to determine if the order is eligible to be cancelled. What happens within the post doesn't matter right now. When debugging my test and it hits the entry point of the HttpPost method of the api, the 'command' and 'model' are both null. Naturally the Api will reject the request and responds with a 500 error.
{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:{ Date: Mon, 22 Jan 2018 19:38:55 GMT Transfer-Encoding: chunked Server: Kestrel Request-Context: appId=cid-v1:93254013-d606-465f-8cee-12e422316f31 X-SourceFiles: =?UTF-8?B?RDpcUUFccWFWZW5kb3JcQWJzdHJhY3Rvck9tc0FwaVxzb3VyY2VcQXBpXGFwaVxPcmRlclxjYW5jZWw=?= X-Powered-By: ASP.NET Content-Type: application/json; charset=utf-8}}
Also the message is indicating that Object reference not set to an instance of an object since everything is null apparently.
So the problem has to be with how I'm constructing the request within my XUnit test. But I'm confused because I believe I'm serializing the json correctly. Even when the Api is running locally in my browser using swagger, the indicated example is
{
"orderId": "string",
"test1Fee": 0,
"test2Fee": 0
}
Could the escapes being created within my post object be the problem? If so, how do I go about fixing that? I tried using PostAsJsonAsync() instead of just PostAsync() but it continues to yield the same results.
What am I doing wrong here? I'm sure it's something pretty simple and I'm just missing it. Let me know if I need to provide anymore information. Any help would be greatly appreciated. Thanks.
I have an MVC 6 application and a separate MVC 6 WebAPI service.
I send an object from the application using this code:
This is the View part of it:
The client sends it to the WebAPI service:
Where the parameter is null:
In the Fiddler log I get 0 as Content-Length:
What else should I set?
It is very important to set the encoding and media type of the StringContent. If I could use PostAsJsonAsync that would probably take care of this part - unfortunately I can't use it in DNX.
So this is the proper code of the client:
string content = Newtonsoft.Json.JsonConvert.SerializeObject(blog);
HttpResponseMessage response = await client.PostAsync("api/values", new StringContent(content, Encoding.UTF8,"application/json"));
Is it somehow possible to make a Web api that calls another web api?
I am using the code below to access a web api from my web api, but it never return from the call. If I use the code from a console app, it is working fine.
public void DoStuff(){
RunAsync().Wait();
}
public static async Task RunAsync(){
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:53452/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync("umbraco/api/Member/Get?username=test");
if (response.IsSuccessStatusCode)
{
string user = await response.Content.ReadAsAsync<string>();
}
}
I also went through the same problem, after much research I discovered that the await operator does not stop the work if the HttpClient returns error 500. To work around the problem I used Task.Wait().
var response = client.GetAsync ("umbraco/api/Member/Get?username=test");
response.Wait ();
I hope this helps others.
Yes you can make a call to a remote web api within the action method of a web api controller.
Lets eliminate the obvious first.
If you set a breakpoint at the start of this action method it is getting hit right? If not then the issue lies in the routing not the action method.
If you set a breakpoint at the if statement does it get hit or is the client.GetAsync() call never returning?
If you haven't done already you may wish to use a tool like fiddler (http://www.telerik.com/fiddler) to compare the request & response from a working use of the api and this broken one. I know you said it is identical to a working implementation but I have found fiddler invaluable to verify exactly what is being sent "on the wire".
What I'm trying to do:
I'm trying to practise making HTTP calls (...if that is what it's called) from a simple ASP.NET MVC web application. To do this, I am attempting to get weather details from OpenWeatherMap. You can do this by:
Add the following parameter to the GET request: APPID=APIKEY
Example: api.openweathermap.org/data/2.5/forecast/city?id=524901&APPID=1111111111
My understanding, from my learning:
The controller is the one to make the above HTTP call.
My question:
How do I actually make that HTTP GET request, in ASP.NET MVC?
Use System.Net.Http.HttpClient.
You can do some basic reading from a website using something like the following:
using (var client = new HttpClient())
{
var uri = new Uri("http://www.google.com/");
var response = await client.GetAsync(uri);
string textResult = await response.Content.ReadAsStringAsync();
}
You may want to make sure to test response.IsSuccessStatusCode (checks for an HTTP 200 result) to make sure the result is what you expect before you parse it.