我正在创建一个小型测试应用程序,它将运行几个测试用例来检查系统各个组件的状态。该应用程序是作为.NET Windows窗体应用程序创建的,其中包含一些复选框,这些复选框将为每个传递的测试用例签入(如果失败则不会检查)。
其中一项测试是检查简单Web服务的可用性。如果Web服务可用,则测试用例将成功,否则将失败。我首先尝试使用System.Net.HttpWebRequest类,将超时设置为1500毫秒并调用GetResponse来实现此目的。现在,如果Web服务不可用,请求应该超时并且测试用例失败。但是,事实证明,超时是根据Web服务的实际响应设置的。也就是说,超时从第一次建立与web服务的连接开始计时。如果Web服务根本无法访问,则不会发生超时,因此在测试用例失败之前至少需要30秒。
为了解决这个问题,我建议使用BeginGetResponse进行异步调用,并在请求完成时进行回调。现在,同样的问题发生在这里,因为如果Web服务不可用,则在回调发生之前至少需要30秒。
现在我在想我可以使用System.Timers.Timer,将超时设置为1500毫秒,并在计时器超时时发生事件。问题是,计时器将独立于Web服务是否可访问而超时,因此将独立于Web服务是否可访问而触发事件。
现在我没有想法。我意识到这必须是一个相当容易解决的问题。有没有人对如何做到这一点有任何建议?
我得到了在自己的线程中进行调用的建议。所以现在我在自己的线程中执行请求。但是,如果请求没有响应,则在我尝试将测试状态设置为失败时应用程序会锁定。但如果它有响应,我可以将测试状态设置为成功,但不存在任何问题。代码:
private void TestWebServiceConnection()
{
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create(Url);
request.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
System.Threading.Thread.Sleep(1500);
SetStatusDelegate d = new SetStatusDelegate(SetTestStatus);
if (request.HaveResponse)
{
if (ConnectionTestCase.InvokeRequired)
{
this.Invoke(d, new object[] { TestStatus.Success});
}
}
else
{
if (ConnectionTestCase.InvokeRequired)
{
this.Invoke(d, new object[] { TestStatus.Failure });
}
}
}
private delegate void SetStatusDelegate(TestStatus t);
private void SetTestStatus(TestStatus t)
{
ConnectionTestCase.Status = t;
}
ThreadStart ts = new ThreadStart(TestWebServiceConnection);
Thread t = new Thread(ts);
t.Start();
有关我为什么会出现此行为的任何建议?感谢名单!
答案 0 :(得分:2)
嗯..非常奇怪的方法来设置超时。为什么不使用HttpWebRequest对象的超时属性?然后用try..catch(TimeoutException)包围HttpWebRequest.GetResponse()。它根本不应该是异步的。
此超时是确定获得工作连接所需时间的超时。如果您以后想要控制最大GetResponse()时间,您应该使用MemoryStream来读取响应流,它还具有readtimeout属性。就是这样。
如果你仍然希望它在单独的线程中运行,请执行以下操作:
Thread testThread = new Thread( () => {
SetStatusDelegate d = new SetStatusDelegate(SetTestStatus);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("yoururl");
request.Timeout = new TimeSpan( 0, 1, 30 );
try
{
request.GetResponse();
}
catch( TimeoutException )
{
this.Invoke(d, new object[] { TestStatus.Failure});
}
this.Invoke(d, new object[] { TestStatus.Success});
});
或类似的东西:)
答案 1 :(得分:0)
为什么不在新线程中进行调用呢?
答案 2 :(得分:0)
“计时器将超时,无论Web服务是否可访问,因此将根据Web服务是否可访问而触发事件。”
一旦可以访问Web服务,您就可以停止计时器。 如果定时器调用设置为2000ms并且Web服务调用完成时间小于2000ms则禁用定时器,否则定时器事件将通知Web服务有问题
答案 3 :(得分:0)
您还可以考虑使用BackgroundWorker对象以更线程安全的方式执行这些调用。它具有执行异步服务和向父表单/对象报告的功能。然后,您可以将任何时间长度和规则附加到您认为必要的Web请求,而不必担心线程异常。
答案 4 :(得分:0)
我尝试解决你的问题,但我没有完成它。也许其他人可以解决其中的错误:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Threading;
namespace winformapp
{
public partial class Form1 : Form
{
private bool completedInTime = false;
private HttpWebRequest request = null;
public delegate void RequestCompletedDelegate(bool completedSuccessfully);
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
private System.Threading.Timer timer = null;
private static readonly object lockOperation = new object();
public Form1()
{
InitializeComponent();
urlTextBox.Text = "http://twitter.com";
millisecondsTextBox.Text = "10000";
}
private void handleUIUpdateRequest(bool completedSuccessfully)
{
resultCheckbox.Checked = completedSuccessfully;
startTestButton.Enabled = true;
completedInTime = false;
}
private void button1_Click(object sender, EventArgs e)
{
startTestButton.Enabled = false;
try
{
TestWebServiceConnection(urlTextBox.Text,
Convert.ToInt32(millisecondsTextBox.Text));
resetEvent.WaitOne();
resultCheckbox.BeginInvoke(new RequestCompletedDelegate(handleUIUpdateRequest), completedInTime);
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
catch (Exception ex)
{
}
}
private void TestWebServiceConnection(string url, int timeoutMilliseconds)
{
request = (HttpWebRequest)WebRequest.Create(url);
request.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
timer = new System.Threading.Timer(new TimerCallback(abortRequest), null, timeoutMilliseconds, Timeout.Infinite);
}
private void FinishWebRequest(IAsyncResult iar)
{
lock (lockOperation)
{
completedInTime = true;
resetEvent.Set();
}
/*
if (timer != null)
{
timer.Dispose();
try
{
if (request != null)
{
request.Abort();
}
}
catch { }
}
timer = null;
request = null;
}
* */
}
private void abortRequest(object state)
{
lock (lockOperation)
{
resetEvent.Set();
}
try
{
Thread.CurrentThread.Abort();
}
catch {}
/*
lock (lockOperation)
{
if (!completedInTime)
{
resetEvent.Set();
}
}
if (completedInTime == false)
{
lock (lockOperation)
{
completedInTime = false;
}
try
{
if (request != null)
{
request.Abort();
}
}
catch { }
try
{
if (timer != null)
{
timer.Dispose();
}
}
catch { }
finally
{
resetEvent.Set();
}
request = null;
timer = null;
}
* */
}
}
}