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"));
Related
I am pretty new to Asp.Net Core and I managed to create a mvc project. In This project I have created an API and it is secured with token based authorization. I am trying to consume this api and make a post request to save data to database. To achieve this I have created one API controller and one MVC controller. These two controllers are used with different purposes. In order to consume the api I have to generate a JWT token and attach token to request header. I use MVC controller for that purpose and after attach authorization header, I consume API post endpoint by sending request from MVC controller to API controller. Here is the process.
I have a form to collect product data in view. Data is send to the MVC controller through ajax. Ajax coding part is successfully working and I can see all the data have passed to controller.
MVC Controller
[HttpPost]
public async Task<IActionResult> stockIn([FromBody] Products products)
{
var user = await _userManager.GetUserAsync(User);
var token = getToken(user);
var json = JsonConvert.SerializeObject(products);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var httpClient = _clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post,
"https://localhost:7015/api/stocks/stockIn/");
request.Headers.Add("Authorization", "Bearer " + token);
request.Content = content;
HttpResponseMessage response = await httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var apiData = await response.Content.ReadAsStringAsync();
return Ok(apiData);
}
return StatusCode(StatusCodes.Status500InternalServerError);
}
This code(MVC controller) also works fine, when I debug this just before the request is sent, I can see token and content also have generated and request is attached with them. Request method is also set to POST.
Then I put a breakpoint on API controller and once the request is sent, the Request Uri - Api endpoint is hiiting and I can see that request method has become GET and the content become Null
API Controller
[HttpPost]
[Route("StockIn")]
public async Task<IActionResult> StockAdd(HttpRequestMessage httpRequestMessage)
{
var content = httpRequestMessage.Content;
string jsonContent = content.ReadAsStringAsync().Result;
Products products = new Products();
products = JsonConvert.DeserializeObject<Products>(jsonContent);
await _context.StoresProducts.AddAsync(products);
await _context.SaveChangesAsync();
return Ok(new { success = "Stock updated successfully" });
}
When I am hovering over the received httpRequestMessage on API controller :
When I am debuging line by line API controller, A null exception is thrown When request message content access.
I found that there are many posts regarding this issue. I have tried almost every solution mentioned on them.
Tried fixes: None of them work
var httpClient = _clientFactory.CreateClient();
httpClient.DefaultRequestHeaders.ExpectContinue = false;
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
I also tried changing request Url by adding '/' to end of it, does not work either. Some of the posts has guessed that there must be a redirection but I can not find a redirection also. I think sometime this caused because I am calling the api endpoint via MVC controller action. Since I want to attach token to request header before api calling, I can not find a way to call api endpoint directly without MVC controller action. Please help me to find the issue here or show me how to achieve this task correctly. Thank you.
Any particula reason you're expecting the body to bind to the HttpRequestMessage?
Have you tried changing the post action to bind to the correct object?
[HttpPost]
[Route("StockIn")]
public async Task<IActionResult> StockAdd(IEnumerable<Products> products)
{
await _context.StoresProducts.AddAsync(products);
await _context.SaveChangesAsync();
return Ok(new { success = "Stock updated successfully" });
}
Most likely, this problem is related to redirect.
When you send request with some method and method changes after sending request, it will be about redirect.
Redirect occures in diffrent scenario:
Wrong api address
Authentication needed
As you said, sometimes url's that does not end with '/' cause to redirect
So send request with postman and check postman log (bottom-left) for better detail.
check if Redirect occoured or not,
if redirect occured, so check for reason. also check if WWW_Authenticate exist in headers.
I currently have a Blazor Client (Wasm) with a ASP.NET Core Web API. (Both deployed to Azure)
The ASP.NET Core Web API returns a IActionResult, which converts into a HttpResponseMessage in my BlazorClient.
I wanted to swap out my ASP.NET Core Web API with a Azure Function HTTP Trigged.
The Azure Function is .Net 5. (I had to do this since all of my other projects in the solution is .Net 5).
Since the function is written in .Net 5, a HttpResponseData Object is returned.
In my HttpResponseData object I have Status Code which I want to test in my Client, Header Data, which I need to access (Total Count), plus the Body that has my list of data.
When I call the Azure Function from my Blazor Client, I can't access the Header data.
I was also having issues getting the Body data as well when I use the _httpClient.GetAsync method.
The best I could do was use the _httpClient.GetStringAsync method. That get me my data from the body.
But, I want the Status Code and Header Data as well.
See the code below.
public async Task<string> GetVpbDelegatesAsync2(int? pageNo, int? pageSize, string searchText)
{
var requestUri = $"{RequestUri.VpbDelegates}?pageNo={pageNo}&pageSize={pageSize}&searchText={searchText}";
var response = await _httpClient.GetAsync(requestUri);
//This line throws an exception. If I comment it out. I get my Body data
var total = response.Headers.GetValues("X-TotalCount").First();
return await _httpClient.GetStringAsync(requestUri);
}
So my questions are:
How can I get that Status Code?
How can I get my Body Data?
How can I get my Header Data
Does anyone know of any demos / code examples with a client that calls a Azure Function that returns HttpResponseData. (I can't find any examples.)
Thanks for your help.
Edit: Just for those keep track at home:
I am able to get the Status Code, but I still can't get the Header Data. I made the same call in PostMan and Header data is there.
Edit 2: I figured out how to get my data out of the Body / Content. But still not getting Header data.
The HttpResponseData object is only in the context of the function code. Your HttpClient object would still return HttpResponseMessage like #Greg mentioned.
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.
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.
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.