How to close a soap client while making async calls? - c#

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.

Related

Is there any way to stop the UI window instance of WPF

When I'm sending the data on a server and server is not up then I get an exception Unable to connect to the server and the UI window instance is closed while executing the line of code :
(response = await client.PostAsJsonAsync("windows/actions", data).ConfigureAwait(false);). How can I stop the UI window it should not be closed.
My code :
public static async void PostInfo(List<ElementProps> requestObj)
{
try
{
HttpResponseMessage response;
using (HttpClient client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri("http://126.1.1.1:8888/");
// Setting content type.
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
string list = JsonConvert.SerializeObject(requestObj);
object data = JsonConvert.DeserializeObject(list);
// HTTP POST ** Here is the error **
response = await client.PostAsJsonAsync("windows/actions", data).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
System.Windows.MessageBox.Show("Recording saved successfully!"); <br/>
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
ErrorLog.Log(ex);
}
}
My main thread exits before the http client async operation finishes.
I just add .Wait() to caller to maintain the main thread. So, I have this :
PostInfo(Records).Wait();

Difference between HttpClient PostAsync and SendAsync

Working on a project where a WPF front end, and trying to get a handle on async calls to HttpClient and I've been going around and around trying to get PostAsync to work, but it routinely appears to deadlock, or at least the post response times out, even with large values for timeout, and a visible response in fiddler.
So, after a while I decided to try out a few other methods on HttpClient, and they worked, first try. No idea why.
I'm clean all the way to my WPF button with awaits, asyncs, and .ConfigureAwait(false) (I think):
Button:
private async void Generate_Suite_BTN_Click(object sender, RoutedEventArgs e)
{
await suiteBuilder.SendStarWs().ConfigureAwait(false);
}
XmlDoc Load:
internal async Task SendStarWs()
{
var xmlDoc = new XmlDocument();
xmlDoc.Load("C:\\Temp\\file.xml");
await StarWSClient.SendStarMessage(xmlDoc).ConfigureAwait(false);
}
SendMessage:
private static readonly HttpClient Client = new HttpClient {MaxResponseContentBufferSize = 1000000};
public static async Task<STARResult> SendMessage(vars)
{
var response = await SendRequestAsync(url, contentNew, Client).ConfigureAwait(false);
return new STARResult(response, hash);
}
This call '500s' against my endpoint immediately, which I'd expect:
var response = await SendRequestAsync(url, contentNew, Client).ConfigureAwait(false);
private static async Task<HttpResponseMessage> SendRequestAsync(string adaptiveUri, StringContent content, HttpClient httpClient)
{
HttpResponseMessage responseMessage = null;
try
{
responseMessage = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Post, adaptiveUri)).ConfigureAwait(false);
}
catch (Exception ex)
{
if (responseMessage == null)
responseMessage = new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
ReasonPhrase = $"SendRequestAsync failed: {ex.Message}"
};
}
return responseMessage;
}
The Post variant returns a TaskCancellationException, with timeout message regardless of timeout value:
var response = await PostRequestAsync(url, contentNew, Client).ConfigureAwait(false);
private static async Task<HttpResponseMessage> PostRequestAsync(string adaptiveUri, StringContent content, HttpClient httpClient)
{
HttpResponseMessage responseMessage = null;
try
{
responseMessage = await httpClient.PostAsync(adaptiveUri, content).ConfigureAwait(false);
}
catch (Exception ex)
{
if (responseMessage == null)
responseMessage = new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
ReasonPhrase = $"PostRequestAsync failed: {ex.Message}"
};
}
return responseMessage;
}
My endpoint responds normally to our other software, so I'm pretty sure the endpoint is solid, I can't fathom why the post response is blocked, when the send isn't.
SendAsync can make any http verb request depending on how you set that property. PostAsync and similar are just convenience methods. Those convenience methods use SendAsync internally which is why when you derive a handler you only need to override SendAsync and not all of the send methods.
To your other question though:
When you use SendAsync you need to create the content and pass it. Your only sending an empty message. The 500 likely means that the api got null from the model binding and kicked you back. Just as #John commented.

Exception while posting to web API, HTTPClient already disposed

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.

http clients that dont throw on error

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.
}
}

how to modify object which is not in the same thread

I am working on a async web request. and need to depends on the response to do a message return.
was thinking to do sth like following
// creating request
string messageToReturn = string.empty;
request.BeginGetResponse(ar =>
{
HttpWebRequest req2 = (HttpWebRequest)ar.AsyncState;
var response = (HttpWebResponse)req2.EndGetResponse(ar);
// is it safe to do this?
messageToReturn = "base on respone, assign different message";
}, request);
// will i get any response message? i will always get empty right?
// since response is handle in another thread
return messageToReturn;
what is the best way to do that?
You are right, that variable will always be empty because you fired off an asyncronous request with the BeginGetResponse method. So really you have a few options here. You can either block the executing thread until the response comes back (probably a really bad idea unless you have a very strong argument for doing this), or you could use an event based asynchronous pattern to alert callers when your response returns...
Consider some of your code wrapped in a method
public void GetMessageAsync()
{
string messageToReturn = string.empty;
request.BeginGetResponse(ar =>
{
HttpWebRequest req2 = (HttpWebRequest)ar.AsyncState;
var response = (HttpWebResponse)req2.EndGetResponse(ar);
// is it safe to do this?
messageToReturn = "base on respone, assign different message";
}, request);
}
To wire up an event based pattern here. We define a custom EventArgs class and a custom event which callers can listen for and which we will fire when the response comes back.
public class StringEventArgs : EventArgs
{
public string Message { get; set; }
}
public event EventHandler<StringEventArgs> MessageReturned;
public void GetMessageAsync()
{
//string messageToReturn = string.empty;
request.BeginGetResponse(ar =>
{
HttpWebRequest req2 = (HttpWebRequest)ar.AsyncState;
var response = (HttpWebResponse)req2.EndGetResponse(ar);
//messageToReturn = "base on respone, assign different message";
this.MessageReturned(this, new StringEventArgs { Message = response.ToString() });
}, request);
}

Categories