I have two ASP.NET Core 2.1 apps and I'm trying to make a simple POST call from one app to the other using HttpClient.
For some reason, when I use [FromBody] to get the simple text I'm trying receive, I get a BadRequest error.
Here's my code on the sender. First, this is what's in my ConfigureServices method. I'm using the new HttpClientFactory feature in ASP.NET Core 2.1. I also created a client class named myApiCallerClient that handles my API calls:
services.AddHttpClient("myNamedClient", client =>
{
client.BaseAddress = new Uri("http://localhost:50625/api/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json");
});
services.AddScoped(x => {
var httpClientFactory = x.GetRequiredService<System.Net.Http.IHttpClientFactory>();
var myApiCallerClient = httpClientFactory.CreateClient("myNamedClient");
return new Clients.ApiCaller.ApiCallerClient(myApiCallerClient);
});
Here's the code in myApiCallerClient:
public async Task SayHello()
{
var response = await _httpClient.PostAsync("test", new StringContent("Saying hello!", System.Text.Encoding.UTF8, "text/plain"));
}
And here's my code on the receiving end which is the POST() API method in TestController:
[HttpPost]
public async Task Post([FromBody]string input)
{
// Some logic
}
My call doesn't hit this method if I use [FromBody] and I get BadRequest error on the sender. If I use [FromHeader] my request hits this API method but I'm getting a null value.
What am I doing wrong here?
ASP.NET Core doesn't support a Content-Type of text/plain out of the box, so the server is rejecting your request as it's not something that it can parse when using the [FromBody] attribute.
In the comments, you said:
Ultimately I won't be sending text. My main concern here is that I'm not hitting my API method. [...] Once I make sure everything is working, I'll be sending JSON data which will get deserialized on the receiving end.
In order to test whether the problem is due to the text/plain Content-Type, you can update your PostAsync line to something like this:
var response = await _httpClient.PostAsync(
"test",
new StringContent("\"Saying hello!\"", System.Text.Encoding.UTF8, "application/json"));
As application/json is a supported Content-Type by default, the code above uses that and wraps the value you were sending with "s in order to make it a valid JSON value.
Related
I have the following endpoint:
[Route("{id}/copy")]
[HttpPost]
public ActionResult<CollectionView> Copy(long id, CollectionView? collectionView = null)
{
And I want to be able to call this endpoint by either providing a value for collectionView or null.
However, in my integration tests that call this endpoint, if I do not provide a body, the server returns 415 Unsupported Media Type.
//works
var copy = await PostAsync<CollectionView>($"{ApiBase}/{retValue.Id}/copy", new CollectionView { Name = "New Name" });
//415 unsupported media type
var copy = await PostAsync<CollectionView>($"{ApiBase}/{retValue.Id}/copy");
I tried specifying [FromForm] on the CollectionView? parameter as I've seen elsewhere, but then it was unable to parse the view I provided in the first integration test, all values came in as null.
How can I correctly configure my API endpoint to have an optional body parameter?
You have to use [FromBody] instead of [FromForm]
[Route("{id}/copy")]
[HttpPost]
public ActionResult<CollectionView> Copy(long id, [FromBody]CollectionView? collectionView = null)
[FromForm] only work when sending multipart/form-data
As far as I know, the asp.net core web api support null parameter. But the reason why your codes doesn't work is related with the your postasnyc method.
Since the Copy method require application/json as the request type, your postasny method doesn't set the right request type, this is the reason why you get the 415 error.
To solve this issue, I suggest you could try to modify the PostAsync method which not include the CollectionView to also send the application/json request.
More details, you could refer to below codes:
Since I don't know your postasync method, I used rest client instead.
var client = new RestClient("https://localhost:5001/api/values/22/copy");
var request = new RestRequest(Method.POST);
request.AddHeader("Cache-Control", "no-cache");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("undefined", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
I am trying to build a web api that returns true but when i send my response through a HttpResponseMessage, Postman reads it as the structure of the HttpResponseMessage. Instead of sending the result in a string with the word true it returns the entire structure of the HttpResponseMessage. I have used the exact same method with other APIs that I have created So I don´t know why it is suddenly returning the wrong answer in postman.
I´ve tried switching methods to the Request method, I´ve also tried returning Mediatypeformater but that haven´t helped. Anyone have any ideas?
The code:
[HttpGet]
public HttpResponseMessage Exportreport(string imei) //tristis est, valet doctrina
{
try
{
//bunches of code
return new HttpResponseMessage((HttpStatusCode)200)
{
Content = new ObjectContent(typeof(bool), true, new JsonMediaTypeFormatter())
};
}
Response in postman:
I have a Web API that I need to convert to API Core 2. I have one issue I cannot seem to resolve. There is a redirect in the controller that uses Request.CreateResponse which does not appear to be available in .Net Core?
public HttpResponseMessage Get() {
var response = Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Location = new Uri("https://xxx.xxxx.com");
return response;
}
Any idea how I can modify this to work? Basically if a user does not pass any parameters, we just send them to a web page.
The syntax has changed in ASP.Net-Core. HttpResponseMessage is no longer used in action results. They will serialized like any other model returned object.
Use instead, the Controller.Redirect method which returns a RedirectResult
public IActionResult Get() {
return Redirect("https://xxx.xxxx.com");
}
RedirectResult
RedirectResult will redirect us to the provided URL, it doesn’t matter if the URL is relative or absolute, it just redirect, very simple. Other thing to note is that it can redirect us temporarily which we’ll get 302 status code or redirect us permanently which we’ll get 301 status code. If we call the Redirect method, it redirect us temporarily...
Reference Asp.Net Core Action Results Explained
That's what the Redirect() method exactly does:
return Redirect("https://xxx.xxx.com");
But if you want more control, you can return a ContentResult:
response.Headers.Location = new Uri("https://xxx.xxx.com");
return new ContentResult {
StatusCode = (int)HttpStatusCode.Redirect,
Content = "Check this URL"
};
I don't see any benefit for doing this, though. Well, unless if you use some client that will not follow the redirect and you want to provide some instructions or content in the Content property, which the client will see as the body of the returned page.
You can use HttpResponseMessage instead, something like:
var response = new HttpResponseMessage(HttpStatusCode.Redirect);
response.Headers.Location = new Uri("https://insight.xxx.com");
Currently I have 3rd party WebApi which has the following external call using Flurl builder.
await _client.Url.ToString().PostJsonAsync(data);
And I'm trying to handle the response with such endpoint:
[HttpPost]
public void HandleResponse(HttpResponseMessage response)
{
}
The response message is with status OK but has Content and Headers = null
How can I handle this properly?
This API endpoint doesn't make any sense to me:
[HttpPost]
public void HandleResponse(HttpResponseMessage response)
{
//...
}
The endpoint would be handling a request and returning a response, not the other way around. Something more like this:
[HttpPost]
public HttpResponseMessage HandleResponse(HttpRequestMessage request)
{
//...
}
When something contacts an API (or server of any kind, really), it's sending a request to that API. That API receives the request and returns a response. The semantics of these two words pretty much describe the process, it's very important to keep them straight.
Consider it like this... If someone asks you a question, what you receive is a question. Not an answer. What you send back to that person is the answer.
A quick update, So it turns out somewhere during my troubleshooting process this started working if I do the post from my application, but if I take the exact same data and try to post it via fiddler the oject is null. It was so much "easier" to try after changes in fiddler that I stuck to it but it looks like it burned me and wasted hours. I also tried posting this data via chromes rest client and it doesnt work. I wish I knew why because if I cant get this to work via fiddler or chrome its really going to increase my troublshooting time in the future.
Thank you for trying to help.
I am trying to post data from a winforms app to Web API. I had this problem initially but setting content type to application/json fixed it but now I am having the same behavior. I dont remember changing anything but I must have. This occurs even when I post the data from fiddler. I removed everything from my viemodel but 1 string key value to try to eliminate format issues in the data itself but at the controller side the viewmodel is still null. Not the values but the viewmodel itself. The controller is being reached but like I said the object is null
The controller looks like this
[HttpPost]
public HttpResponseMessage LogValidation([FromBody]ValidationViewModel validationviewmodel)
{
//Do something
}
The Model
public class ValidationViewModel
{
public string AssetName { get; set; }
}
The data being posted
{
\"AssetName\":\"testname\"
}
In the interest of providing as much info as possible when I do the post from the client I am doing the following. This is also how I generated the test data to use in fiddler
`public Task SubmitValidation()
{
ReportValidaton reportvalidation = new ReportValidaton();
var serializedReportValidation = JsonConvert.SerializeObject(reportvalidation);
var client = new HttpClient();
client.BaseAddress = new Uri("MyURI");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeader("application/json"));
MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
HttpContent content = new ObjectContent<ReportValidaton>(reportvalidation, jsonFormatter);
HttpResponseMessage response = client.PostAsync("api/LogValidation/", content).Result;
}`
When posting from fiddler, ensure:
that the Content-Type header is set to application/json
that the data doesn't contain escaped strings: {"AssetName":"testname"} and NOT {\"AssetName\":\"testname\"}
that the method is set to POST