【发布时间】:2016-04-18 09:09:27
【问题描述】:
我正在编写一个 Windows 服务。我有一个计时器方法(private void OnTimer(object sender, ElapsedEventArgs args)),它调用业务逻辑并最终得到这个方法:
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;
}
}
如您所见,http 内容是作为参数传入的。问题是当因为 content 被释放而发生异常时(“无法访问已释放的对象。
对象名称:'System.Net.Http.StringContent'。")
我发现了一些建议使用“使用”块的帖子,因此我将整个方法(实际上是我的 try...catch 块)包装在 using(content) 中,但这并不能解决问题。然而,有效的是在方法的最开始(尝试之前)添加对内容的引用 - var contentForException = content.ReadAsStringAsync().Result;,然后在 catch 块中使用 contentForException 而不是 content。
我想了解的是为什么它会以这种方式运行(即 为什么 在 'catch' 块之前是 content disposed ,即使那里需要它)。特别是为什么它在将方法的内容包装在其中时会忽略“使用”块。
如果它很重要,这就是我从业务逻辑中调用此方法的方式:
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);
【问题讨论】:
-
using块不会阻止对象被释放 - 它确保对象被释放。 -
如果您告诉我们哪个错误发生在哪一行,这可能会有所帮助。有些东西正在处理您的内容。看起来 PostAsync 过于热心了。
-
@HenkHolterman 尝试 WriteEntry 时在“catch”块中发生错误 - 我正在使用
content的块中唯一的一个位置。多一点解释(关于 PostAsync)将不胜感激。 -
为什么会遇到问题?我的意思是原来的错误。
-
@HenkHolterman 在这条线上很受欢迎:
if (response.Result.StatusCode == HttpStatusCode.OK)。这是聚合异常,但最里面的异常是 System.Net.Sockets.SocketException - 无法建立连接,因为目标机器主动拒绝它(因为我要检查的服务没有运行)跨度>
标签: c# timer windows-services