Terminating a function after a specified time

127 views Asked by At

Im working on an EConnect integration Windows form app in C#. Im having a lot of trouble testing my connection string. Basically I give the user the option to change the connection string so I want to be able to test it. As far as I know EConnect doesnt have any built in functions that test the connection so I'm writing a pretty crude function to do it myself. Just for everyones information the connection string consists of a server name that the GP databases are located on and a database name.

The particulars of the actual test function I dont think are that important but the main issue is within that function I call an eConnect method called getEntity, this method uses the connection string and if the connection string is right it will pull information. If the database name is wrong the getEntity method will return an eConnect exception which is easy enough to catch, however if the server name is wrong the getEntity method will just spin and my app gets stuck.

Im trying to write something where I can possibly run my test function asynchronously and simultaneously check for a timeout or the econnect exception. This is where I get stuck, I cant for the life of me get it to work. Here is the first thing I tried (this is in my TestConnection method):

task = Task.Factory.StartNew(() => requester.GetEntity(GPCongfigSettings.GPConnectionString, myXmlDocument.OuterXml), token);

try
{
    if (!task.Wait(timeOut, token))
    {
        Console.WriteLine("The server name is incorrect - task timed out");
        return false;
    }
}
catch (ThreadInterruptedException)
{
return false;
}
catch (AggregateException ae)
{
    ae.Handle((x) =>
    {
        if (x is eConnectException) // This we know how to handle.
        {
            Console.WriteLine("Incorrect Database Name! -- " + x.Message);
            return false;
        }
        return false; // Let anything else stop the application.
    });

}

This would catch the cases where the server was wrong and if my econnect method would just time out. But it never caught the eConnect exception, Visual Studio would break the app and tell me I had an unhandled exception.

Here is what Im trying now, this is the full class I have for my form. Here I'm trying to use IAsyncResult and using a WaitHandle to check to see if the function completes or times out. This seems to work sometimes, it works for a correct string and for when the database is wrong, and sometimes it works for when the server is wrong, but once I test for a wrong server name it doesnt work correctly for anything else anymore. Is there something I'm missing or is there a better way to run the getentity method in TestGPConnection and check to see if it hasnt completed after a certain time period and if it hasnt kill that method and have the user reenter a server name?

public partial class UpdateGPConnection : Form
{
    Task task;
    AsyncCallback cb;
    public delegate string startProcessToCall();
    startProcessToCall sp2c;       

    public UpdateGPConnection()
    {
        InitializeComponent();
        this.txtDatasourceName.Text = ConfigurationManager.AppSettings.Get("GPDataServer");
        this.txtDatabaseName.Text = ConfigurationManager.AppSettings.Get("GPDatabase");                   

        cb = new AsyncCallback(startProcessCallback);
        sp2c = new startProcessToCall(TestGPConnection);
    }

    public void startProcessCallback(IAsyncResult iar)
    {
        startProcessToCall mc = (startProcessToCall)iar.AsyncState;
        bool result = mc.EndInvoke(iar);
        Console.WriteLine("Function value = {0}", result);
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        config.AppSettings.Settings["GPDataServer"].Value = txtDatasourceName.Text.ToUpper();
        config.AppSettings.Settings["GPDatabase"].Value = txtDatabaseName.Text.ToUpper();
        config.Save(ConfigurationSaveMode.Modified);

        ConfigurationManager.RefreshSection("appSettings");

        GPCongfigSettings.GPConnectionString = @"data source=" + txtDatasourceName.Text.ToUpper() + ";initial catalog=" + txtDatabaseName.Text.ToUpper() + ";integrated security=SSPI;persist security info=False;packet size=4096";

        IAsyncResult asyncResult = null;
        asyncResult = sp2c.BeginInvoke(cb, null);
        timer1.Enabled = true;

        Thread.Sleep(0);

        bool test = asyncResult.AsyncWaitHandle.WaitOne(15000);

        if (test)
        {
            try
            {
                string testResult = sp2c.EndInvoke(asyncResult);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
            }
        }



        bool result = asyncResult.IsCompleted;

        asyncResult.AsyncWaitHandle.Close();

        this.Close();
    }



    public string TestGPConnection()
    {

        eConnectMethods requester = new eConnectMethods();
        try
        {                

            // Create an eConnect document type object
            eConnectType myEConnectType = new eConnectType();

            // Create a RQeConnectOutType schema object
            RQeConnectOutType myReqType = new RQeConnectOutType();

            // Create an eConnectOut XML node object
            eConnectOut myeConnectOut = new eConnectOut();

            // Populate the eConnectOut XML node elements
            myeConnectOut.ACTION = 1;
            myeConnectOut.DOCTYPE = "GL_Accounts";
            myeConnectOut.OUTPUTTYPE = 2;
            myeConnectOut.FORLIST = 1;
            myeConnectOut.WhereClause = "(ACTNUMST = '99-9999-99-999')";

            // Add the eConnectOut XML node object to the RQeConnectOutType schema object
            myReqType.eConnectOut = myeConnectOut;

            // Add the RQeConnectOutType schema object to the eConnect document object
            RQeConnectOutType[] myReqOutType = { myReqType };
            myEConnectType.RQeConnectOutType = myReqOutType;

            // Serialize the eConnect document object to a memory stream
            MemoryStream myMemStream = new MemoryStream();
            XmlSerializer mySerializer = new XmlSerializer(myEConnectType.GetType());
            mySerializer.Serialize(myMemStream, myEConnectType);
            myMemStream.Position = 0;

            // Load the serialized eConnect document object into an XML document object
            XmlTextReader xmlreader = new XmlTextReader(myMemStream);
            XmlDocument myXmlDocument = new XmlDocument();
            myXmlDocument.Load(xmlreader);

            string reqDoc = requester.GetEntity(GPCongfigSettings.GPConnectionString, myXmlDocument.OuterXml);

            return "Correct Connection";


        }
        catch (eConnectException exc)
        {
            Console.WriteLine(exc.Message);
            return "eConnect Excpetion";
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return "Excpetion";
        }
    }

    private void btnExit_Click(object sender, EventArgs e)
    {
        this.Close();
    }


}
1

There are 1 answers

1
InBetween On

You are not handling the eConnectException. You are showing a message in the Console and then essentially rethrowing the exception by returning false.

If you do handle an exception then you should return true to avoid rethrowing it:

catch (AggregateException ae)
{
    ae.Handle((x) =>
    {
        if (x is eConnectException) // This we know how to handle.
        {
            Console.WriteLine("Incorrect Database Name! -- " + x.Message);
        }

        return x is eConnectException; //rethrow anything that is not an eConnectException
    });
}