I have an ASP.NET Core Web API service built using .NET 6 that makes http requests using C# HttpClientFactory to external services.
The issue I am facing is that the second request with different arguments returns same result as for the previous request.
I tried clearing default headers at the start of every request no luck.
What worked for me:
RestSharp: https://restsharp.dev/
Using new HttpClient() instance instead of httpClientFactory.CreateClient()
I would like to make it work with httpClientFactory as this is the recommended way. Any thoughts why much appreciated.
// Each request has different access token but same body
public async Task<MyResponse> GetXyz(object requestBody, string accessToken)
{
var uri = "...";
return await this.httpClientFactory.CreateClient("GetXyz").PostAsync<MyResponse>(uri, requestBody, GetHeaders(accessToken));
}
private static IList<(string, string)> GetHeaders(string accessToken)
{
var headers = new List<(string, string)>
{
(HeaderNames.Accept, "application/json"),
};
if (!string.IsNullOrWhiteSpace(accessToken))
{
headers.Add((HeaderNames.Authorization, "Bearer " + accessToken));
}
return headers;
}
public static async Task<T> PostAsync<T>(this HttpClient httpClient, string uri, object data, IList<(string, string)> headers = null)
where T : class
{
// httpClient.DefaultRequestHeaders.Clear();
var body = data.Serialise(); // convert to JSON string
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
{
request.AddRequestHeaders(headers);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using (var httpResponse = await httpClient.SendAsync(request))
{
var jsonResponse = await httpResponse.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(jsonResponse);
}
}
}
EDIT 2: NETWORK TRAFFIC DIFF
Using Fiddler Classic with basic client httpclientfactory.CreateClient() here are the diffs between 2 requests headers that suffer from the issue:
Related
I'm writing a simple dotnet core API, under search controller which like below :
[HttpGet("order")]
public async Task <Order> SearchOrder(string ordername, int siteid) {
return await service.getorder(ordername,siteid)
}
The swagger UI where the path https://devehost/search/order test pretty work, but when I use another client to call this api by below
client = new HttpClient {
BaseAddress = new Uri("https://devehost")
};
var request = new HttpRequestMessage(HttpMethod.Get, "Search/order") {
Content = new FormUrlEncodedContent(
new List<KeyValuePair<string, string>> {
new("ordername", "pizza-1"),
new("siteid", "1"),
})
};
var response = await client.SendAsync(request);
The status code always return bad request. But the postman is work, can I know the problem inside?
Thank you
For a GET request, the parameters should be sent in the querystring, not the request body.
GET - HTTP | MDN
Note: Sending body/payload in a GET request may cause some existing implementations to reject the request — while not prohibited by the specification, the semantics are undefined.
For .NET Core, you can use the Microsoft.AspNetCore.WebUtilities.QueryHelpers class to append the parameters to the URL:
Dictionary<string, string> parameters = new()
{
["ordername"] = "pizza-1",
["siteid"] = "1",
};
string url = QueryHelpers.AppendQueryString("Search/order", parameters);
using var request = new HttpRequestMessage(HttpMethod.Get, url);
using var response = await client.SendAsync(request);
I need to send a Patch request to a backend API via SendRequestAsync func. This is regarding a UWP C# app.
Backend expected to like this:
On the app this is the code I wrote. But doesn't work
if (requestMehtod == ApplicationConstants.RequestType.PATCH)
{
Uri uri = new Uri(requestUrl);
HttpRequestMessage requestMessage = null;
if (postData != null)
{
var itemAsJson = JsonConvert.SerializeObject(postData);
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri)
{
Content = new HttpStringContent(itemAsJson, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json-patch+json")
};
}
else
{
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri);
}
response = await httpClient.SendRequestAsync(requestMessage).AsTask(cancellationTokenSource.Token);
var rdModel = ProcessResponseData(response);
return await Handle401Error(rdModel, response, postData, url, requestMehtod, isDownloadSite, OnSendRequestProgress, requestData);
}
The above code fine to send JSON data to the same API and works fine. But I need to know how to send just a string in the body. Thank for the consideration
NOTE: App uses HttpClient from Windows.Web.Http and will not be able to use anything inside System.Net.Http namespace.
The answer is given by the #gusman and #Simon Wilson. Just to amend to their answer, in order to be able to send a string in the request body, the string needs to be within double-quotes.
var requestData = "\"hello world\"";
var request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Content = new HttpStringContent(requestData, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json")
};
response = await httpClient.SendRequestAsync(request);
This worked in my scenario.
I am building a simple proxy for sending two get requests to a data provider OpenWeatherMap. According to its documentation, if I want to get a current weather, I need to send a request with a parameter q. Currently I make my requests from a frontend part using Axios library and I indicate this q parameter there. But I want to make it more readable and send requests with a parameter cityName. How do I change the parameter name in my NET Core part of the application?
Here is what I do in my HttpClient:
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync( "http://api.openweathermap.org/data/2.5/weather" + pathAndQuery.Replace( apiEndpoint, "" ) + "&appid=ggggg" );
var result = await response.Content.ReadAsStringAsync();
context.Response.StatusCode = (int)response.StatusCode;
await context.Response.WriteAsync( result );
}
You could write a method like that:
public const string Endpoint = "api.openweathermap.org/data/2.5/weather";
public async void GetWeatherBytCityName(string cityName)
{
using (var httpClient = new HttpClient())
{
var query = $"?q={cityName}";
var response = await httpClient.GetAsync( $"{Endpoint}{query}");
}
}
I am currently developing a REST-ful C# application that works with an external service. I have gotten basic 'GET', 'POST', 'PUT', and 'DELETE' requests to work, however whenever I attempt to send a PATCH request to the same service, it does not work. I get a 200 message (meaning it was successful), but doing a GET on the subject that I am trying to attempt the PATCH request on shows that no change occurred.
Additionally, whenever I use Fiddler to form PATCH requests, using the same URL and content string, it works as expected.
I am attempting to ensure that it isn't something I am doing wrong in regards to how I am sending the HTTP request.
My call that interacts with all of the different above REST functions is as follows:
public async Task<T> GetResultFromService<T>(string requesttype, string url, string request = "")
{
HttpRequestMessage message;
switch (requesttype)
{
case "Post":
message = PostRequest(url, client, request);
break;
case "Put":
message = PutRequest(url, client, request);
break;
case "Patch":
message = PatchRequest(url, client, request);
break;
case "Delete":
message = DeleteRequest(url, client);
break;
default:
message = GetRequest(url, client);
break;
}
var response = await client.SendAsync(message);
var responseString = await response.Content.ReadAsStringAsync();
return IModel.FromJson<T>(responseString);
}
My function for forming the PATCH request:
public HttpRequestMessage PatchRequest(string url, HttpClient client, string content = "")
{
var request = new HttpRequestMessage(new HttpMethod("PATCH"), url);
return request;
}
Adding a GET request for comparison:
public HttpRequestMessage GetRequest(string url, HttpClient client)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
return request;
}
And my Httpclient code (if it is at all relevant...):
var proxy = new WebProxy
{
Address = ServerEnv.ProxyUri
};
var httpHandler = new HttpClientHandler
{
Proxy = proxy,
UseProxy = true
};
client = new HttpClient(httpHandler, true);
Any sort of direction you can point me in would be greatly appreciated.
Thanks a ton!
edit: I realized my mistake due to the answerer's reply. Basically I accidentally left out the body on my PATCH, but it was on my POST and PUT and I had overlooked that detail. POST code for detail:
public HttpRequestMessage PostRequest(string url, HttpClient client, string content)
{
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new StringContent(content,
Encoding.UTF8,
"application/json")
};
return request;
}
and the revised PATCH:
public HttpRequestMessage PatchRequest(string url, HttpClient client, string content = "")
{
var request = new HttpRequestMessage(new HttpMethod("PATCH"), url)
{
Content = new StringContent(content,
Encoding.UTF8,
"application/json")
};
return request;
}
If any lesson can be learned from this, it would be that you should double and triple check copy and pasted code. Thanks again!
Your POST, PUT and PATCH requests are missing a body. How should the service handing the request know what you want to change on the resource? You need to set the Content property on the HttpRequestMessage.
See this answer for an example.
I'm trying to invoke a PATCH operation on our organization's Salesforce API.
The url is correct (format - https://xxxx.salesforce.com/services/data/v43.0/sobjects/Classification__c/objectid?_HttpMethod=PATCH) and so is the JSON content, though you possibly can't guage that from the code below.
public async Task PatchSalesforceObjectAsync(string objectToPost, string objectid, HttpContent content)
{
SetupHttpClient();
using (_response = await _httpClient.PostAsync($"{_sfObjectPartialURL}{objectToPost}{objectid}?_HttpMethod=PATCH", content))
{
if (_response.IsSuccessStatusCode)
{
var x = _response.Content;
}
}
}
void SetupHttpClient()
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _sfAccesstoken);
_httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.BaseAddress = _baseURI;
}
Response - StatusCode:400, ReasonPhrase:Bad Request
I've made the exact same request through POSTMAN and it goes through fine, so I'm guessing that the issue lies with how I'm making the call in the .Net framework.
I've also tried using a HttpRequestMessage object and then call SendAsync on the HttpClient object, but that leads to the same result.
HttpRequestMessage message = new HttpRequestMessage()
{
Method = new HttpMethod("PATCH"),
RequestUri = new Uri(_baseURI, $"{_sfObjectPartialURL}{objectToPost}{objectid}"),
Content = content,
};
using (_response = await _httpClient.SendAsync(message))
{
Rookie Mistake - There was a field in the Patch that I'm not allowed to update and since I was dealing with the same object and switching between a POST and a PATCH based on whether the object already existed I was not aware of this field level restriction.