简体   繁体   English

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

[英]How to check if a webservice is available using an asynchronous call

I'm creating a small test application that will run through a few test cases to check the status of various components of our system. 我正在创建一个小型测试应用程序,它将运行一些测试用例来检查系统各个组件的状态。 The application is created as a .NET Windows Forms application with a few checkboxes that gets checked in for each test case that passes (and not checked if failed). 该应用程序是作为.NET Windows窗体应用程序创建的,其中包含一些复选框,这些复选框将为每个传递的测试用例签入(如果失败则不会检查)。

One of the tests is to check the availability of a simple webservice. 其中一项测试是检查简单Web服务的可用性。 If the webservice is available, the test case is to succeed, otherwise fail. 如果Web服务可用,则测试用例将成功,否则将失败。 I first tried to accomplish this by using the System.Net.HttpWebRequest class, setting the timeout to 1500 ms and invoking GetResponse. 我首先尝试使用System.Net.HttpWebRequest类,将超时设置为1500毫秒并调用GetResponse来实现此目的。 Now, if the webservice is not available the request should timeout and the test case fails. 现在,如果Web服务不可用,请求应该超时并且测试用例失败。 However, as it turns out, the timeout is set on the actual response from the webservice. 但是,事实证明,超时是根据Web服务的实际响应设置的。 That is to say, the timeout starts counting from when a connection to the webservice has fist been established. 也就是说,超时从第一次建立与web服务的连接开始计时。 If the webservice is simply unreachable, the timeout does not occur, and consequently it will take at least 30 seconds until the testcase fails. 如果Web服务根本无法访问,则不会发生超时,因此在测试用例失败之前至少需要30秒。

To solve this problem, I was advised to make an asynchronous call using BeginGetResponse with a callback for when the request is finished. 为了解决这个问题,我建议使用BeginGetResponse进行异步调用,并在请求完成时进行回调。 Now, the same problem occurrs here, because if the webservice is not available, it will take at least 30 seconds until the callback occurs. 现在,这里出现同样的问题,因为如果Web服务不可用,则在回调发生之前至少需要30秒。

Now I was thinking that I could use a System.Timers.Timer, set timeout to 1500 ms and have an event for when the timer times out. 现在,我想我可以使用System.Timers.Timer,将超时设置为1500毫秒,并在计时器超时时发生事件。 The problem is, the timer will timeout independently of whether the webservice is accessible and consequently the event will be fired independently of whether the webservice is accessible. 问题是,计时器将独立于Web服务是否可访问而超时,因此将独立于Web服务是否可访问而触发事件。

Now I'm out of ideas. 现在我没有想法了。 I realize that this must be a fairly easy problem to solve. 我意识到这必须是一个相当容易解决的问题。 Do anyone have any advice on how I could accomplish this? 有人对我如何做到这一点有任何建议吗?

I got the advice to make the call in its own thread. 我得到了在自己的线程中进行调用的建议。 So now I'm performing the request in its own thread. 所以现在我在自己的线程中执行请求。 However, if the request dont have a response, the application locks when I'm trying to set the test status to failed. 但是,如果请求没有响应,则在我尝试将测试状态设置为失败时应用程序会锁定。 But if it has a response I can set the test status to succeeded withouut any problems. 但如果它有响应,我可以将测试状态设置为成功,但不存在任何问题。 The code for this: 这个代码:

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();

Any advice on why I get this behaviour? 为什么我得到这种行为的任何建议? Thanx! 感谢名单!

Hmm.. Very strange way to set a timeout really. 嗯..非常奇怪的方式来设置超时真的。 Why don't you use timeout property of HttpWebRequest object? 为什么不使用HttpWebRequest对象的超时属性? And then surround HttpWebRequest.GetResponse() with try..catch(TimeoutException). 然后用try..catch(TimeoutException)包围HttpWebRequest.GetResponse()。 And it shouldn't be async at all. 它根本不应该是异步的。

This timeout is exact one that determines time needed to get working connection. 此超时是确定获得工作连接所需时间的超时。 If you later will want to control maximum GetResponse() time you should use MemoryStream for response stream reading it is also has readtimeout property. 如果您以后想要控制最大GetResponse()时间,您应该使用MemoryStream来读取响应流,它还具有readtimeout属性。 That's it. 而已。

If you still want it to run in separate thread do like this: 如果你仍然希望它在单独的线程中运行,请执行以下操作:

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});
});

Or something like that :) 或类似的东西 :)

为什么不在新线程中进行调用?

"the timer will timeout independently of whether the webservice is accessible and consequently the event will be fired independently of whether the webservice is accessible." “计时器将独立于Web服务是否可访问而超时,因此将独立于Web服务是否可访问而触发事件。”

You can stop the timer once the Web Service is reachable. 一旦可以访问Web服务,您就可以停止计时器。 If the timer call is set to 2000ms and the Web Service calls takes less than 2000ms to complete then disable the timer, otherwise the timer event will notify that there is something wrong with the Web Service 如果定时器调用设置为2000毫秒并且Web服务调用完成时间小于2000毫秒,则禁用定时器,否则定时器事件将通知Web服务有问题

You might also consider using the BackgroundWorker object to perform these calls in a more threadsafe manner. 您还可以考虑使用BackgroundWorker对象以更线程安全的方式执行这些调用。 It has capability to perform Async services and reporting back to the parent form/object. 它具有执行异步服务和向父表单/对象报告的功能。 You could then attach whatever timelengths and rules to the web request that you feel are necessary without fear of a thread exception. 然后,您可以将任何时间长度和规则附加到您认为必要的Web请求,而不必担心线程异常。

I tried solving your problem, but I didn't finish it. 我尝试解决你的问题,但我没有完成它。 Perhaps someone else could fix the bugs in it: 也许其他人可以解决其中的错误:

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;

            }
             * */
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM