I am looking to optimize my codeā¦
I have number of API with early same structure for client and handler.
But I have some questions about disposing.
I have read the using statement automatically dispose resources (here HttpClient and HttpClientHandler).
Could I rewrite my code here:
public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues
{
var httpClientHandler = new HttpClientHandler
{
Proxy = new WebProxy(proxy, true),
UseProxy = IsProxySelected
};
using (var client = new HttpClient(httpClientHandler))
{
client.BaseAddress = new Uri(URI);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(Head.key, Head.apikey);
var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
var result = await Task.WhenAll(tasks).ConfigureAwait(false);
return result!;
}
async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues
{
var statusCode = -1;
var json = "_";
var isSuccess = false;
try
{
using (HttpResponseMessage response = await client.DeleteAsync(url).ConfigureAwait(false))
{
statusCode = (Int32)response.StatusCode;
json = await response.Content.ReadAsStringAsync();
isSuccess = response.IsSuccessStatusCode;
}
}
catch (Exception ex)
{
//something to catch
}
:
return record;
}
}
To this piece of code without problem? Disposing resource is always done?
public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues
{
using (var client = SetClientSettings())
{
var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
var result = await Task.WhenAll(tasks).ConfigureAwait(false);
return result!;
}
async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues
{
:
:
return record;
}
}
public static Httpclient SetClientSettings()
{
var httpClientHandler = new HttpClientHandler
{
Proxy = new WebProxy(proxy, true),
UseProxy = IsProxySelected
};
var client = new HttpClient(httpClientHandler);
client.BaseAddress = new Uri(URI);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(Head.key, Head.apikey);
return client;
}
So I have created a method SetClientSettings and this method create the client, the clienthandler, add some headers to client and return client.
so
var httpClientHandler = new HttpClientHandler
{
Proxy = new WebProxy(proxy, true),
UseProxy = IsProxySelected
};
using (var client = new HttpClient(httpClientHandler))
{
client.BaseAddress = new Uri(URI);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(Head.key, Head.apikey);
var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
var result = await Task.WhenAll(tasks).ConfigureAwait(false);
return result!;
}
is really equivalent to??:
using (var client = SetClientSettings())
{
var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
var result = await Task.WhenAll(tasks).ConfigureAwait(false);
return result!;
}
Your two pieces of code are not equivalent. There is a small difference, that with the first snippet you will dispose the client even when the following lines (e.g. client.BaseAddress = new Uri(URI); or client.DefaultRequestHeaders.Clear();) fail. Which is better. To achieve this with SetClientSettings you would need to wrap everything into try except and .Dispose() on exception.
I have read the using statement automatically dispose resources (here HttpClient and HttpClientHandler).
The using statement turns this:
using (var instance = something)
{
// body
}
into this
var instance = something;
try
{
// body
}
finally
{
if (instance != null)
{
instance.Dispose();
}
}
That's all it does. It is a syntactic sugar.
And so in your particular case the using statement will ensure that .Dispose() is called on HttpClient, regardless of whether exception is thrown or not.
Now, do we have to dispose HttpClient? Well, they say we have to, there's no reason not to believe it. In reality the HttpClient holds sockets under the hood, which have to be closed manually when done with. And so, yes, you should always dispose HttpClient when done with.
That being said, the best thing you can do is to have a singleton HttpClient for the duration of your app, and reuse it. You can tweak it to your needs (e.g. configure it to use pooled connections) for maximal efficiency. In such scenario you don't dispose it at all.
Note: you don't have to worry about disposing HttpClientHandler. By default HttpClient will dispose it when it is disposed itself. This behaviour can be modified by using different constructor.
Yes, the code you wrote is equivalent to each other. There's an option in HttpClient contructor to not to dispose message handler - by default, it's set to true. Anyway, as already suggested, you don't have to dispose HTTP client at all. There are reasons for that.
There's alot of nice articles about best practices of using HttpClient.
Try to search for IHttpClientFactory.
Related
I'm trying to implement a rest api client in c#. I've created every requests roughly like so:
public async Task<string> CallCreateJob()
{
HttpRequestMessage requestMessage =
new HttpRequestMessage(HttpMethod.Post, URL))
requestMessage.Content = new StringContent("some content");
var getRequestResponse = await RunCallWithAuth(requestMessage);
string rawResponse = await getRequestResponse.Content.ReadAsStringAsync();
return rawResponse;
}
But the important thing is that I would like to wrap around the call with authentication like so:
public async Task<HttpResponseMessage> RunCallWithAuth(HttpRequestMessage requestMessage)
{
requestMessage.Headers.Add("token", getToken()); //Token assumed to be available.
HttpResponseMessage firstResponse= await client.SendAsync(requestMessage);
if(firstResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized) {
if (Refresh()) { //updates token in getToken() call.
requestMessage.Headers.Add("token", getToken());
HttpResponseMessage secondResponse = await client.SendAsync(requestMessage);
if(secondResponse .StatusCode != System.Net.HttpStatusCode.Unauthorized)
return secondResponse;
else
throw new IOException("Could not authenticate");
}
else
throw new IOException("Could not authenticate");
} else{
return firstResponse;
}
}
The part that I'm nervous about is when I pass a HttpRequestMessage in a function and return a HttpResponseMessage object from my function. Since reading up on HttpResponseMessage it seems good practice to use either a using statement or use Dispose when I don't need it anymore. But I don't know what standard c# does when returning an object. Will it move? Or copy? Is there a way to be sure all resources in HttpResponseMessage are properly handled? Same questions apply for passing an object into a function. Are there standard practices on how to do this with http messages?
You can just dispose it in the calling function when you're done with it
using (var request = new HttpRequestMessage(HttpMethod.Post, URL))
using (var response = await RunCallWithAuth(request))
{
// do stuff with the response here
}
Once you return an IDisposable from a function, it then becomes the responsibility of the caller really
Sorry for the name of my post but I am going to try to explain my problem.
I am building a client library to request an external API and I try to figure out how to make the methods of my library safe-threaded.
Basically the main class of my library looks like this :
public class MyCompanyApiClient
{
private readonly HttpClient _httpClient;
public MyCompanyApiClient(string baseUrl)
{
_httpClient = new HttpClient() {BaseAddress = new Uri(baseUrl)};
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<MyClassB> PostData(int id, MyClassA dataToPost)
{
var request = new HttpRequestMessage(HttpMethod.Post, $"objects/{id}");
request.Content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8,
"application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var stringContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyClassB>(stringContent);
}
public async Task<MyClassA > GetById(int id)
{
...
}
}
I'd like to ensure that any instance members of my client class are safe-threaded.
For the moment I plan to wrap the code inside each method into a Task.Run:
public async Task<MyClassB> PostData(int id, MyClassA dataToPost)
{
return await Task.Run(async () =>
{
var request = new HttpRequestMessage(HttpMethod.Post, $"objects/{id}");
request.Content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8,
"application/json");
var response = await _httpClient.SendAsync(request);
var stringContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyClassB>(stringContent);
});
}
By the way I don't even know if it is going to ensure this method to be safe-threaded.
Any help aprreciated ^^
Thread-safe doesn't mean multi-threading.
It means that some code is aware that it'll be used in multi-threaded cases, and they won't get corrupted, won't produce deadlocks and other threading-related issues.
Sometimes there's code that it's thread-safe per se, while sometimes you need to use thread-synchronization approaches like monitors, mutexes, reset events, semaphores and others, to protect critical code sections from being executed by one, two or n threads at once in order to avoid, again, deadlocks, corruptions and, basically, unexpected behaviors.
In your case, it seems like you consider thread-safe launching your PostDataas a thread in the thread pool. This is a bad choice, you don't need a new thread for this.
I have a functioning async Task that calls a web service:
private async Task GetResult()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Username", _username);
client.DefaultRequestHeaders.Add("Action", "GET");
/* etc */
var response = await client.GetAsync(client.BaseAddress);
}
}
I would like to separate out the creation of the HttpClient object so it can be parameterized and reused:
private async Task GetResult()
{
using (var client = GetClient(_baseAddress, _username))
{
var response = await client.GetAsync(client.BaseAddress);
}
}
private static HttpClient GetClient(string Address, string Username)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(Address);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Username", Username);
client.DefaultRequestHeaders.Add("Action", "GET");
/* etc */
return client;
}
}
While this appears functionally identical to me, the latter throws an AggregateException error with inner exception
Cannot Access a disposed object. Object name: 'System.Net.Http.HttpClient'.
Perhaps there is some async subtlety that I don't understand?
Get rid of the using inside of GetClient. You only use using for things that remain "in your ownership", you are "giving up ownership to the caller" when you return client;.
It is now the caller's resposability to use a using statement (which you do already correctly do in GetResult).
This has nothing to do with asnyc and is simply standard IDisposable behavior.
I am using HttpClient PCL Class library. But When First Time I Get the JSON result It return correct data. After that HttpClient returns the same JSON result again and again for one URL till I close the application and start it again. My code looks like that
public class HttpService : IHttpService
{
public async Task<TResponseType> GetAsync<TResponseType>(string method, string parameters = null) where TResponseType : class
{
var uri = new Uri(string.Format(Constants.ServerUrl + method + parameters));
using (var client=new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
"c2Rzb2w6c2Rzb2w5OQ==");
var response = await client.GetAsync(uri);
var result = response.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<TResponseType>(result);
}
}
}
As stated in an answer for a different question, the solution is to set the IfModifiedSince property to prevent the default caching behaviour like this:
httpClient.DefaultRequestHeaders.IfModifiedSince = DateTime.Now;
You could also check on MSDN for more information.
I use codes below to send POST request to a server:
string url = "http://myserver/method?param1=1¶m2=2"
HttpClientHandler handler = new HttpClientHandler();
HttpClient httpClient = new HttpClient(handler);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
HttpResponseMessage response = await httpClient.SendAsync(request);
I don't have access to the server to debug but I want to know, is this request sent as POST or GET?
If it is GET, How can I change my code to send param1 & param2 as POST data (not in the URL)?
A cleaner alternative would be to use a Dictionary to handle parameters. They are key-value pairs after all.
private static readonly HttpClient httpclient;
static MyClassName()
{
// HttpClient is intended to be instantiated once and re-used throughout the life of an application.
// Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads.
// This will result in SocketException errors.
// https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.7.1
httpclient = new HttpClient();
}
var url = "http://myserver/method";
var parameters = new Dictionary<string, string> { { "param1", "1" }, { "param2", "2" } };
var encodedContent = new FormUrlEncodedContent (parameters);
var response = await httpclient.PostAsync (url, encodedContent).ConfigureAwait (false);
if (response.StatusCode == HttpStatusCode.OK) {
// Do something with response. Example get content:
// var responseContent = await response.Content.ReadAsStringAsync ().ConfigureAwait (false);
}
Also dont forget to Dispose() httpclient, if you dont use the keyword using
As stated in the Remarks section of the HttpClient class in the Microsoft docs, HttpClient should be instantiated once and re-used.
Edit:
You may want to look into response.EnsureSuccessStatusCode(); instead of if (response.StatusCode == HttpStatusCode.OK).
You may want to keep your httpclient and dont Dispose() it. See: Do HttpClient and HttpClientHandler have to be disposed?
Edit:
Do not worry about using .ConfigureAwait(false) in .NET Core. For more details look at https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html
This is how I use it for DI:
using HttpClient httpClient = clientFactory.CreateClient("name set in builder host");
// httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", $"Token {token}");
HttpResponseMessage? res = await httpClient!.PostAsync(url, content);
try
{
res.EnsureSuccessStatusCode();
return res;
}
catch (Exception)
{
// Add error handling
}
content is:
List<KeyValuePair<string, string>> values = new()
{
new KeyValuePair<string, string>("data", "value")
};
FormUrlEncodedContent requestContent = new(values);
and clientFactory is the interface:
IHttpClientFactory
msdn interface
As Ben said, you are POSTing your request ( HttpMethod.Post specified in your code )
The querystring (get) parameters included in your url probably will not do anything.
Try this:
string url = "http://myserver/method";
string content = "param1=1¶m2=2";
HttpClientHandler handler = new HttpClientHandler();
HttpClient httpClient = new HttpClient(handler);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
HttpResponseMessage response = await httpClient.SendAsync(request,content);
HTH,
bovako