简体   繁体   中英

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).

One of the tests is to check the availability of a simple webservice. If the webservice is available, the test case is to succeed, otherwise fail. I first tried to accomplish this by using the System.Net.HttpWebRequest class, setting the timeout to 1500 ms and invoking GetResponse. Now, if the webservice is not available the request should timeout and the test case fails. However, as it turns out, the timeout is set on the actual response from the webservice. That is to say, the timeout starts counting from when a connection to the webservice has fist been established. If the webservice is simply unreachable, the timeout does not occur, and consequently it will take at least 30 seconds until the testcase fails.

To solve this problem, I was advised to make an asynchronous call using BeginGetResponse with a callback for when the request is finished. Now, the same problem occurrs here, because if the webservice is not available, it will take at least 30 seconds until the callback occurs.

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. 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.

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? And then surround HttpWebRequest.GetResponse() with try..catch(TimeoutException). 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. 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."

You can stop the timer once the Web Service is reachable. 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

You might also consider using the BackgroundWorker object to perform these calls in a more threadsafe manner. 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.

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;

            }
             * */
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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