Solved

Can I recursively call a method from inside that method?

Posted on 2011-09-28
4
206 Views
Last Modified: 2013-12-17
I have a method that calls an API which may or may not return with valid data.  If the data is not valid, I need to change a parameter and call the API again (see line 123).  This second time, if the data is not found, then I want to set a flag and return to the original caller.  Is there anything special I need to do (like where is the "return" statement  going to take me?)
public string imageURL = "";
        //------------------------------    look for book and parse results    ---------------------------|
        private bool InvokeItemSearch(string asin, string AWSKey, string AWSSecretKey) {
            Cursor.Current = Cursors.WaitCursor;

            string idType = asin.Substring(0, 1) == "B" ? idType = "ASIN" : idType = "ISBN";
            string associateTag = "abcdef-10"; //"pragbook-20";
            string requestString =
                "Service=AWSECommerceService" +
                "&Version=2011-08-01" +
                "&Operation=ItemLookup" + 
                "&ItemId=" + asin +
                "&IdType=" + idType +
                "&MerchantId=All" +
                "&AssociateTag=" + associateTag +
                "&ResponseGroup=Medium";

            if (idType == "ISBN")
                requestString += "&SearchIndex=Books";

            SignedRequestHelper helper = new SignedRequestHelper(AWSKey, AWSSecretKey, @"ecs.amazonaws.com");
            string requestURL = helper.Sign(requestString);
            WebRequest request = HttpWebRequest.Create(requestURL);


            request.Timeout = 30000;  //  30 seconds
            System.Net.ServicePointManager.MaxServicePointIdleTime = 10000;  //  needed for bug in .NET 2.0

            // get the response object
            HttpWebResponse response = null;
            try {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (Exception ex) {
                if (ex.Message.Contains("(403) Forbidden")) {
                    MessageBox.Show("Invalid Amazon key(s); verify them and try again", "Prager, Software", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
            imageURL = "";  //  clear it...

            // to read the contents of the file, get the ResponseStream
            StreamReader sr = null;
            try {
                sr = new StreamReader(response.GetResponseStream());
            }
            catch (Exception ex) {
                if (ex.Message.Contains("unable to connect to the remote server")) {
                    MessageBox.Show("Amazon.com appears to be busy; please try again", "Prager, Software", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return false;
                }
            }


            // Create an insntance of XmlTextReader and call Read method to read the file
            XmlTextReader textReader = new XmlTextReader(sr);
            textReader.Read();


            bool notFound = true;
            //string debugString = textReader.
            try {
                textReader.MoveToAttribute("ItemAttributes");
            }
            catch (Exception ex) {
                if (ex.Message.Contains("Root element is missing")) {
                    MessageBox.Show("Data returned from Amazon.com is invalid - try again", "Prager, Software", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    textReader.Close();  //  close the text reader
                    return false;
                }
            }

            while (textReader.Read()) {
                if (textReader.NodeType == XmlNodeType.Element && textReader.NodeType != XmlNodeType.EndElement)
                    switch (textReader.LocalName) {
                        case "Author":
                            textReader.Read();  //  get value
                            tbAuthor.Text = textReader.Value.Length > 75 ? textReader.Value.Substring(0, 75) : textReader.Value;
                            notFound = false;
                            break;
                        case "Binding":
                            textReader.Read();  //  get value
                            coBinding.Text = textReader.Value;
                            if (coBinding.Text.ToLower().Contains("paperback"))
                                coJacket.SelectedIndex = 8;  // none as issued 
                            notFound = false;
                            break;
                        case "NumberOfPages":
                            textReader.Read();  //  get value
                            tbPages.Text = textReader.Value.ToString();
                            notFound = false;
                            break;
                        case "PublicationDate":
                            textReader.Read();  //  get value
                            string[] splitFields = textReader.Value.Split('-');
                            tbYear.Text = splitFields[0];  //  just take the year
                            notFound = false;
                            break;
                        case "Publisher":
                            textReader.Read();  //  get value
                            tbPub.Text = textReader.Value.Length > 85 ? textReader.Value.Substring(0, 85) : textReader.Value;
                            notFound = false;
                            break;
                        case "Title":
                            textReader.Read();  //  get value
                            tbTitle.Text = textReader.Value.Length > 100 ? textReader.Value.Substring(0, 100) : textReader.Value;
                            notFound = false;
                            break;
                        case "Content":
                            textReader.Read();  //  get value  (11.4.0)
                            if (cbAddDesc.Checked)
                                tbDesc.Text = textReader.Value.Length > 500 ? textReader.Value.Substring(0, 500) : textReader.Value;
                            else
                                tbDesc.Text = "";
                            notFound = false;
                            break;
                        default:
                            break;
                    }
            }

            if (notFound) {  //  if we didn't find anything using ISBN, try again using ASIN
			//  this is where I want to set a flag at the top of the method and call InvokeItemSearch again   <------------------------
                return false;
            }

Open in new window

0
Comment
Question by:rmmarsh
  • 2
  • 2
4 Comments
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 36720167
You have to understand how function calls work in your machine. Such calls go onto a stack. Think of a stack of plates. Start with one plate. Now add a second. Can you remove the bottom plate without removing the top plate? That's how your function calls work. When you recursively call your function, a new copy is placed on the stack, and its parameters and values are seen only by it (barring any global variables).

Let's say you are in the first call (bottom plate). You get to line 123. Now you call the function a second time (top plate). The second call has to complete before the first call can be removed from memory. This is where you will be if you call the function a second time. Once the second call completes, you will be at line 124 of the first call. Just be sure to be careful if there are any global variables because you can affect the values of other calls by mutating them in any given call, just like normal execution (i.e. non-recursive) can.
0
 

Author Comment

by:rmmarsh
ID: 36720219
Hmmm... I think it would be safer to take the guts of the method and make another method out of it which could be called again (without recursion) depending on the results of the first call...

You agree?
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 36720351
It's probably more a matter of preference. You can certainly do that, but it is two pieces of code you have to maintain--if one changes, the other will most likely have to be changed (and you have to remember that the other needs to be changed!).

Recursion is not difficult to mess up (e.g. infinite recursion, incorrect values due to globals, etc.), but it's not terribly difficult to grasp if you practice it for a bit. Perhaps if you clarify your worries we can cover possible points of error or provide a better explanation.
0
 

Author Closing Comment

by:rmmarsh
ID: 36720461
Thank you... I appreciate it...
0

Featured Post

Webinar: Aligning, Automating, Winning

Join Dan Russo, Senior Manager of Operations Intelligence, for an in-depth discussion on how Dealertrack, leading provider of integrated digital solutions for the automotive industry, transformed their DevOps processes to increase collaboration and move with greater velocity.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

IP addresses can be stored in a database in any of several ways.  These ways may vary based on the volume of the data.  I was dealing with quite a large amount of data for user authentication purpose, and needed a way to minimize the storage.   …
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

679 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question