Solved

Can I recursively call a method from inside that method?

Posted on 2011-09-28
4
204 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

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

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

It seems a simple enough task, yet I see repeated questions asking how to do it: how to pass data between two forms. In this article, I will show you the different mechanisms available for you to do just that. This article is directed towards the .N…
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.
In a recent question (https://www.experts-exchange.com/questions/28997919/Pagination-in-Adobe-Acrobat.html) here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…

776 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