C# 如何使用异步调用检查Web服务是否可用
我正在创建一个小的测试应用程序,它将运行几个测试用例来检查系统各个组件的状态。该应用程序被创建为一个.NET Windows窗体应用程序,其中有几个复选框,这些复选框针对通过的每个测试用例进行签入(如果失败,则不选中) 测试之一是检查简单Web服务的可用性。如果webservice可用,则测试用例将成功,否则将失败。我首先尝试通过使用System.Net.HttpWebRequest类来实现这一点,将超时设置为1500毫秒并调用GetResponse。现在,如果webservice不可用,请求应该超时,测试用例失败。然而,事实证明,超时是在来自webservice的实际响应上设置的。也就是说,超时从与Web服务建立连接时开始计数。如果Web服务根本无法访问,则不会发生超时,因此至少需要30秒,直到testcase失败 为了解决这个问题,有人建议我使用BeginGetResponse进行异步调用,并在请求完成时进行回调。现在,这里也出现了同样的问题,因为如果webservice不可用,则至少需要30秒才能发生回调 现在我想我可以使用System.Timers.Timer,将超时设置为1500毫秒,并在计时器超时时设置一个事件。问题是,计时器将独立于webservice是否可访问而超时,因此事件将独立于webservice是否可访问而触发 现在我没有主意了。我意识到这一定是一个相当容易解决的问题。有人对我如何做到这一点有什么建议吗 我得到了用自己的思路打电话的建议。所以现在我在它自己的线程中执行请求。但是,如果请求没有响应,当我试图将测试状态设置为失败时,应用程序将锁定。但是如果它有响应,我可以将测试状态设置为successed,而不会出现任何问题。此操作的代码:C# 如何使用异步调用检查Web服务是否可用,c#,.net,web-services,C#,.net,Web Services,我正在创建一个小的测试应用程序,它将运行几个测试用例来检查系统各个组件的状态。该应用程序被创建为一个.NET Windows窗体应用程序,其中有几个复选框,这些复选框针对通过的每个测试用例进行签入(如果失败,则不选中) 测试之一是检查简单Web服务的可用性。如果webservice可用,则测试用例将成功,否则将失败。我首先尝试通过使用System.Net.HttpWebRequest类来实现这一点,将超时设置为1500毫秒并调用GetResponse。现在,如果webservice不可用,请求应
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();
关于我为什么会有这种行为有什么建议吗?塔克斯 为什么不在新线程中执行调用本身?“计时器将超时,与Web服务是否可访问无关,因此事件将被触发,与Web服务是否可访问无关。” 一旦可以访问Web服务,就可以停止计时器。
如果计时器调用设置为2000毫秒,Web服务调用需要小于2000毫秒完成,则禁用计时器,否则计时器事件将通知Web服务 出错,您还可以考虑使用BuffTeWork对象以更线程安全的方式执行这些调用。它能够执行异步服务并向父窗体/对象报告。然后,您可以将您认为必要的任何时间长度和规则附加到web请求,而无需担心线程异常 嗯。。设置超时的方式真的很奇怪。为什么不使用HttpWebRequest对象的timeout属性?然后用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});
});
或者类似的:)我试图解决你的问题,但没有完成。也许其他人可以修复其中的bug:
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;
}
* */
}
}
}
我试着听从你的建议。所以我把电话放在了它自己的线程中。当然,当我试图设置表单中复选框的状态时,我会得到异常(跨线程调用)。为了解决这个问题,我试着让它线程安全。但是,如果请求没有响应,当我试图将测试状态设置为失败时,应用程序将锁定。我在问题中发布了上面的代码。我听从了你的建议,在一个单独的线程上打了电话。调用thread.start()后,我让应用程序休眠大约一秒钟。如果未收到响应,则测试默认为失败。谢谢你的帮助!