I am looking for c# HTTP client that doesn't throw when it gets an HTTP error (404 for example).
This is not just a style issue; its perfectly valid for a non 2xx reply to have a body but I cant get at it if the HTTP stack throws when doing a GetResponse()
All the System.Net.Http.HTTPClient methods that return Task<HttpResponseMessage> do NOT throw on any HttpStatusCode. They only throw on timeouts, cancellations or inability to connect to a gateway.
If you are using the HttpClient in System.Net.Http, you can do something like this:
using (var client = new HttpClient())
using (var response = await client.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStreamAsync();
// You can do whatever you want with the resulting stream, or you can ReadAsStringAsync, or just remove "Async" to use the blocking methods.
}
else
{
var statusCode = response.StatusCode;
// You can do some stuff with the status code to decide what to do.
}
}
Since almost all methods on HttpClient are thread safe, I suggest you actually create a static client to use elsewhere in your code, that way you aren't wasting memory if you make a lot of requests by constantly creating a destroying clients for just one request when they can make thousands.
What about implementing a class that is wrapping the HttpClient?
Let it implement the desired methods which are delegated to the client object and try/catch the exceptions in these delegating methods.
class MyClient
{
HttpClient client;
[...]
public String WrappedMethodA()
{
try {
return client.MethodA();
} catch(Exception x) {
return ""; // or do some other stuff.
}
}
}
After implementing your own client, you'll get rid of these exceptions.
If you need a HttpClient instance, inherit from HttpClient and override it's methods it like this:
public String WrappedMethodA()
{
try {
return base.MethodA(); // using 'base' as the client object.
} catch(Exception x) {
return ""; // or do some other stuff.
}
}
Related
I have a problem with my app. In my computer everything work good. I have problem with app on my notebook. I must debug app but my response doesn't work, this is Exception The operation was canceled. Api work, because i tested in PostMan. My code:
if (httpClient != null)
{
Task<string> response = httpClient.GetStringAsync($"myUrl");
string res = response.GetAwaiter().GetResult();
if (!string.IsNullOrEmpty(res))
{
myModel = JsonConvert.DeserializeObject<Model>(res);
}
}
somebody know why i have a problem on notebook?
Change your code to the following:
if (httpClient != null)
{
string response = await httpClient.GetStringAsync($"myUrl");
if (!string.IsNullOrEmpty(response ))
{
myModel = JsonConvert.DeserializeObject<Model>(response);
}
}
No need to use GetAwaiter()
This method is intended for compiler use rather than for use in application code.
You need to await in async calls, in order to execute the actual call.
I'm posting a bytearray from an Android App in Xamarin.Forms to an .NET Core 2.0 WebAPI. However, I'm getting an exception saying that the NetworkStream already is disposed;
Code making the request;
public async Task PostImageAsync(ImageDTO image)
{
var content = new MultipartFormDataContent();
var byteArrayContent = new ByteArrayContent(image.Content);
content.Add(byteArrayContent, image.FileTile, image.FileName);
try
{
using (var httpClient = GetNewHttpClient())
{
SetBearerToken(httpClient);
var response = await httpClient.PostAsync($"{_apiUrl}/api/images/upload", content);
if (response.IsSuccessStatusCode)
{
}
else
{
}
}
}
catch (Exception e)
{
//Exception occurs here
var msg = e.GetBaseException().Message;
throw;
}
}
Code to get the HttpClient
private HttpClient GetNewHttpClient()
{
//HttpClientHandler is a global variable
var httpClient = new HttpClient(HttpClientHandler, false) {BaseAddress = new Uri(_apiUrl)};
return httpClient;
}
API Endpoint
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file == null || file.Length == 0) return BadRequest();
return Ok();
}
EDIT - SetBearerToken Method
private static void SetBearerToken(HttpClient client)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", App.StoredToken);
}
The Exception:
cannot access a disposed object. Object name: 'System.Net.Sockets.NetworkStream'.
It feels like a really obvious mistake I'm making here, but I can't get my head around it. Anybody has any ideas?
Don't dispose objects inside async functions
A using statement in an async method is "odd" in that the Dispose
call may execute in a different thread to the one which acquired the
resource (depending on synchronization context etc) but it will still
happen... assuming the thing you're waiting for ever shows up or
fail, of course. (Just like you won't end up calling Dispose in
non-async code if your using statement contains a call to a method
which never returns.)
#jon-skeet https://stackoverflow.com/a/16566605/2228916
Don’t dispose of the HttpClient:
https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
Also noticed that you set _apiUrl as the BaseAddress and prefix the url in the post. Pick one or the other.
I'm using HttpClient to make request to WebApi.
I have written this code
public async Task<string> ExecuteGetHttp(string url, Dictionary<string, string> headers = null)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (headers != null)
{
foreach (var header in headers)
{
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
}
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
Now I'm calling this method from my action.
public async Task<ActionResult> Index()
{
try
{
RestWebRequest RestWebRequest = new RestWebRequest();
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Authorization", "bearer _AxE9GWUO__8iIGS8stK1GrXuCXuz0xJ8Ba_nR1W2AhhOWy9r98e2_YquUmjFsAv1RcI94ROKEbiEjFVGmoiqmUU7qB5_Rjw1Z3FWMtzEc8BeM60WuIuF2fx_Y2FNTE_6XRhXce75MNf4-i0HbygnClzqDdrdG_B0hK6u2H7rtpBFV0BYZIUqFuJpkg4Aus85P8_Rd2KTCC5o6mHPiGxRl_yGFFTTL4_GvSuBQH39RoMqNj94A84KlE0hm99Yk-8jY6AKdxGRoEhtW_Ddow9FKWiViSuetcegzs_YWiPMN6kBFhY401ON_M_aH067ciIu6nZ7TiIkD5GHgndMvF-dYt3nAD95uLaqX6t8MS-WS2E80h7_AuaN5JZMOEOJCUi7z3zWMD2MoSwDtiB644XdmQ5DcJUXy_lli3KKaXgArJzKj85BWTAQ8xGXz3PyVo6W8swRaY5ojfnPUmUibm4A2lkRUvu7mHLGExgZ9rOsW_BbCDJq6LlYHM1BnAQ_W6LAE5P-DxMNZj7PNmEP1LKptr2RWwYt17JPRdN27OcSvZZdam6YMlBW00Dz2T2dgWqv7LvKpVhMpOtjOSdMhDzWEcf6yqr4ldVUszCQrPfjfBBtUdN_5nqcpiWlPx3JTkx438i08Ni8ph3gDQQvl3YL5psDcdwh0-QtNjEAGvBdQCwABvkbUhnIQQo_vwA68ITg07sEYgCl7Sql5IV7bD_x-yrlHyaVNtCn9C4zVr5ALIfj0YCuCyF_l1Z1MTRE7nb");
var getCategories = await RestWebRequest.ExecuteGetHttp("http://localhost:53646/api/Job/GetAllCategories?isIncludeChild=true", headers);
}
catch (HttpRequestException ex)
{
return View();
}
return View();
}
Now It is said that HttpClient has been designed to be re-used for multiple calls.
How Can I use same httpClient object for multiple calls.
Let's suppose
First I'm calling
http://localhost:53646/api/Job/GetAllCategories?isIncludeChild=true
Now In same controller I have to call another Api with diffrent header and diffrent url.
http://localhost:53646/api/Job/category/10
Should I make the global object of HttpClient and Use the same object for all API calls.
The challenge in using just one HttpClient across your application is when you want to use different credentials or you try to vary the default headers for your requests (or anything in the HttpClientHandler passed in). In this case you will need a set of purpose specific HttpClients to re-use since using just one will be problematic.
I suggest creating a HttpClient per the "type" of request you wish to make and re-use those. E.g. one for each credential you need - and maybe if you have a few sets of default headers, one per each of those.
It can be a bit of a juggling act between the HttpClient properties (which are not thread safe) and need their own instance if being varied:
- BaseAddress
- DefaultRequestHeaders
- MaxResponseContentBufferSize
- Timeout
And what you can pass in to the "VERB" methods (get, put, post etc). For example, using HttpClient.PostAsync Method (String, HttpContent) you can specify your headers for the [HttpContent][3] (and not have to put them in the HttpClient DefaultHeaders).
All of the Async methods off the HttpClient are thread safe (PostAsync) etc.
Just because you can, doesn't mean you should.
You don't have to, but you can reuse the HttpClient, for example when you want to issue many HTTP requests in a tight loop. This saves a tiny fraction of time it takes to instantiate the object.
Your MVC controller is instantiated for every request. So it won't harm any significant amount of time to instantiate a HttpClient at the same time. Remember you're going to issue an HTTP request with it, which will take many orders more time than the instantiation ever will.
If you do insist you want to reuse one instance, because you have benchmarked it and evaluated the instantiation of HttpClient to be your greatest bottleneck, then you can take a look at dependency injection and inject a single instance into every controller that needs it.
in .net core you can do the same with HttpClientFactory something like this:
public interface IBuyService
{
Task<Buy> GetBuyItems();
}
public class BuyService: IBuyService
{
private readonly HttpClient _httpClient;
public BuyService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Buy> GetBuyItems()
{
var uri = "Uri";
var responseString = await _httpClient.GetStringAsync(uri);
var buy = JsonConvert.DeserializeObject<Buy>(responseString);
return buy;
}
}
ConfigureServices
services.AddHttpClient<IBuyService, BuyService>(client =>
{
client.BaseAddress = new Uri(Configuration["BaseUrl"]);
});
documentation and example at here and here
I am using HttpClient class in my asp.net web api 2 application to post some information to a endpoint. I just want to post the information without waiting for a response. Is this the right syntax
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var gizmo = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" };
var response = await client.PostAsJsonAsync("api/products", gizmo);
}
I just want to post the information without waiting for a response
Not awaiting an async method in WebAPI will result in a runtime exception, as the AspNetSynchronizationContext is aware of any triggered asynchronous operations. If it notices a controller action completes before the async operation has, it will trigger the said exception. More on that in ASP.NET Controller: An asynchronous module or handler completed while an asynchronous operation was still pending
If you want to use a fire and forget semantics, you need to queue the delegate via HostingEnvironment.QueueBackgroundWorkItem if you're using .NET 4.5.2 and above. If not, you can defer to using BackgroundTaskManager
Keep in mind this kind of design isn't really suitable for WebAPI. It doesn't scale if you're triggering this action call frequently. If this style happens often, consider using something more suitable such as a message broker.
To implement the async Task in ASP.NET refer to the following sample syntax:
protected void Page_Load(object sender, EventArgs e)
{
try
{
RegisterAsyncTask(new PageAsyncTask(LoadUrlContent));
}
catch {}
}
protected async Task LoadUrlContent()
{
try
{
// Add your code here, for example read the content using HttpClient:
string _content = await ReadTextAsync(YourUrl, 10);
}
catch { throw; }
}
Also, set <%# Page ... Async="true" %> at page level.
Following sample code snippet shows the use of HttpClient (call this sample function from LoadUrlContent():
protected async Task<string> ReadTextAsync(string Url, int TimeOutSec)
{
try
{
using (HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(TimeOutSec) })
{
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/html"));
using (HttpResponseMessage _responseMsg = await _client.GetAsync(Url))
{
using (HttpContent content = _responseMsg.Content)
{
return await content.ReadAsStringAsync();
}
}
}
}
catch { throw; }
}
You can modify this code base pertinent to your particular task.
Hope this may help.
I am calling a soap service asynchronously but stuck at a point where I need to close a soap client connection. Not much help from previous post either: How to close Client Proxy with Async Call WCF
Below is my code so far.
Method below (GetFieldList(....) calls generic method ApiClient.GetResponse(....) with request parameters and what service to invoke
public async Task<ServiceReference.GetFieldListResponse> GetFieldList(string identifier)
{
var request = new GetFieldListRequest
{
Header = new Header {Username = ApiSettings.Instance.ApiToken},
AGroup = "",
IdType = "",
Id = ""
};
var response = await ApiClient.GetResponse(request, (c) => c.GetFieldListAsync(request.Header, request.Id, request.IdType, request.AGroup));
return response;
}
In the method below, I have commented out finally block because the connection was being closed before a response was returned to the calling method.
public class ApiClient
{
public static TResponse GetResponse<TResponse, TRequest>(TRequest request,
Func<SoapClient, TResponse> handler,
string apiMethodName = "")
where TResponse : class
{
Debug.WriteLine("Calling: " + typeof(TRequest).Name);
if (string.IsNullOrEmpty(apiMethodName))
{
apiMethodName = typeof(TRequest).Name.Replace("Request", string.Empty);
}
// creates a soap connection
var client = WebServiceClient.CreateServiceInstance();
TResponse response = null;
try
{
//webservice call is invoked here
response = handler(client);
}
catch (FaultException exception)
{
throw new ApiException(string.Format("Api error on {0}.", apiMethodName), exception);
}
//if this finally block is not commented, connection is closed before a response was returned to the calling method.
//finally
//{
// client.Close();
//}
return response;
}
}
Any idea what am I missing?
Thanks
I would suggest to have a global WebServiceClient or ApiClient, and do GetResponse and CloseClient in two threads. That way, even you are waiting for response, you can force trigger client close in CloseClient thread.