I'm writing a windows service. I have a timer method (private void OnTimer(object sender, ElapsedEventArgs args)) which calls business logic and eventually gets to this method:
public ServiceHelperResponse CallService(HttpMethod httpMethod, string uri, HttpContent content, string expectedResultcontent)
{
try
{
using (var client = new HttpClient())
{
Task<HttpResponseMessage> response;
switch (httpMethod)
{
case HttpMethod.Get:
response = client.GetAsync(uri);
break;
case HttpMethod.Post:
response = client.PostAsync(uri, content);
break;
default:
return ServiceHelperResponse.UnhandledError;
}
if (response.Result.StatusCode == HttpStatusCode.OK)
{
var responseContent = response.Result.Content.ReadAsStringAsync().Result;
if (!responseContent.Equals(expectedResultcontent))
{
return ServiceHelperResponse.ExpectedResultNotMatching;
}
return ServiceHelperResponse.Ok;
}
if (response.Result.StatusCode == HttpStatusCode.NoContent)
{
return ServiceHelperResponse.Ok;
}
return ServiceHelperResponse.WrongResponsecode;
}
}
catch (Exception ex)
{
ServiceMonitor.EventLogger.WriteEntry(
string.Format("Exception while tyring to send http request.\r\n\r\nUri: {0}\r\nContent:\r\n{1}\r\n\r\n{2}",
uri, content.ReadAsStringAsync(), ex.Message
),
EventLogEntryType.Error
);
return ServiceHelperResponse.UnhandledError;
}
}
As you can see the http content is passed in as a parameter. The problem is when an exception occurs because content is disposed ("Cannot access a disposed object.
Object name: 'System.Net.Http.StringContent'.")
I found some posts which suggested to use "using" block so I've wrapped entire method (effectively my try...catch block) in using(content) however that doesn't solve the problem. What does work however is adding a reference to content at the very beginning of the method (before try) - var contentForException = content.ReadAsStringAsync().Result; and then using contentForException in the catch block instead of content.
What I'd like to understand is why does it behave this way (i.e. why is content disposed before 'catch' block even though it is needed there). Especially why does it ignore "using" block when wrapping the content of the method in it.
In case it matters, this is how I call this method from my business logic:
var uri = ServiceMonitor.Config.Services.BankDetailsValidationService.Uri;
var content = new StringContent(
JsonConvert.SerializeObject(
new
{
sortCode = "...",
accountNumber = "..."
}
), Encoding.UTF8, "application/json");
var expectedResultcontent = "...";
return _restfulServiceHelper.CallService(HttpMethod.Post, uri, content, expectedResultcontent);
A using block will just force a dispose at the end of the using block, it doesn't prevent a dispose half way through. Once you've accessed the body of the response at the top of the method it doesn't matter if content is disposed because you've already retrieved the body of the response and stored it in contentForException
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With