如何使用异步调用检查Web服务是否可用

时间:2010-01-15 08:16:52

标签: c# .net web-services

我正在创建一个小型测试应用程序,它将运行几个测试用例来检查系统各个组件的状态。该应用程序是作为.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();

有关我为什么会出现此行为的任何建议?感谢名单!

5 个答案:

答案 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;

            }
             * */
        }
    }
}