I have a WebAPI C# application. My GET method is defined as:
[HttpGet]
public HttpResponseMessage Get(string id)
This API retrieves some content from a database, based on a given id. Another parameter is required but it is so long that having it on the URL would not work, so I'm using the GET body to send such second parameter.
How can I retrieve it from inside the get method?
I tried
var dataOnBody = await Request.Content.ReadAsStringAsync();
but it doesn't work as the Get method is not async and I think it doesn't need to be that (I want a normal blocking function which reads the content of the body and outputs a string)
I just need a simple way to extract my string from the request body
Even if you somehow manage to do this, you will find that support is not universal. The HTTP specs say:
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI.
So the data returned relies only on the URI, not anything in the body. Many libraries won't even let you send a request body during a GET.
Related
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.
When writing a POST method for an API in Asp.NET Core there is the possibility to use CreatedAtAction
Following example from the documentation
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
The CreatedAtAction action result has following effects:
The Response Status Code will be 201
A "Location" response Header will be included with the URI of the new resource
The created object will be returned in the response body
The first two seem reasonable to me. However I wonder why the third effect would be desired? At first it seems to be an unnecessary increase of the response size, yet I am curious to understand why that pattern is presented in the documentation as it is, including the created object. What is the benefit of returning the created resource, which was sent as request anyway? Or could it be that the (only) reason for including the object in the response is to include values which are generated server side, as for example a create date or a primary key?
The server can generate new data that the client will not know about, such as an ID or timestamps for creation or modification. If the client requires this data after the initial request, you save an unnecessary round trip by including the created resource in the response body.
It's not always the best choice. You have weigh the benefit of having immediate access against the increased bandwidth use. Some consideration is warranted before returning large resources this way.
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.
How are you, people I need to change the response message of the return of BadRequest().
When I use the request like this, BadResquest("error: you can not pass these values")
I want to my api return something like this:
{"error: you can not pass these values"}
but the endpoint retuned this :
{"Message":"error: you can not pass these values"}
I don't want the word "Message" in my response, is there any form to overwrite or change the response?.
You're free to create what ever response message you like. see http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/action-results
The BadRequest() helper method is just that. It's a workload reduction method that takes care of boilerplate stuff.
I'm having an implementation of DelegatingHandler which basically take a request and address it to another server (http://localhost:9999/test/page.php --> http://otherSite.com/test/page.php ).
Following my question here, I now have to read the result of the page and edit it a little bit:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
string url = request.RequestUri.PathAndQuery;
UriBuilder forwardUri = new UriBuilder(_otherWebSiteBase);
forwardUri.Path = url;
HttpRequestMessage newRequest = request.Clone(forwardUri.Uri.ToString());
HttpResponseMessage responseMessage = await _client.SendAsync(newRequest);
//HERE: How to read the responseMessage.Content in string?
return responseMessage;
}
I'm trying to read the content of the message, change some parts of it(basically change all http://otherSite.com into http://localhost:9999 ) and then return it.
The issues that I'm facing:
string content =await responseMessage.Content.ReadAsStringAsync();
Doesn't returns me anything that is readeable(I'm not sure, but I've the impression it's maybe because of the compression?)
Is there a way to replace the content of the message?
I'm trying to understand this a little better. Are you simply looking to make all requests that go to that address get redirected to another address? Given that you're putting this in the delegating handler, I'm imagining this is being run for every incoming request.
If that's the case, I don't really believe this is the location to write this code. There are two other places that I think provide a cleaner solution.
In the web server:
You seem to be recreating the idea of a Reverse Proxy (https://en.wikipedia.org/wiki/Reverse_proxy) where you want one server to simply direct requests to another without the client knowing about the change. You can make this modification on the server itself. If you're using IIS, there are guides to use IIS plugins like Application Request Routing to achieve this ( http://www.iis.net/learn/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing ). Other web servers also have their own solutions but I have not personally tried them.
On the route itself
On whatever Web API route would be responding to this request, you can use http status codes to tell the browser to redirect the request elsewhere.
The 3xx series were specifically made to solve this kind of problem: http://www.restapitutorial.com/httpstatuscodes.html
That said, if you still want to use the approach in the original question, you need to ensure that there is a Media-Type Formatter for the data type that is being returned. By default, Web API will only attempt to use formatters for JSON, XML, and Form-url-encoded data. If you are returning anything else, you'll need to do a little more work ( http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters ) to get the data back to manipulate it.