c# - Getting InvalidOperationException during call to GetResponseAsync()? -


preface: know code excerpt lengthy did't want leave out detail else might spot cause of issue. reason verbose nature of code , many exception traps due hunt nullreferenceexception describe below. can wade through code salient parts jumping await keywords found amongst async methods call each other.

update: invalidoperationexception occurring because altering isenabled status of buttons. on main thread not sure why happening. know why?

i have windows phone 7 application written c# getting system.invalidoperationexception when getresponseasync() called in particular code context. application uses petfinder api create cat breed guessing game intention of helping cats in animal shelters adopted. here exact exception message in entirety:

message: unhandled exception of type 'system.invalidoperationexception' occurred in system.windows.ni.dll 

before exception occurs, there several successful calls getresponseasync(). have included code methods involved in exception in order called below. can tell me why getting exception , how fix it?

the exception occurring out of current code context calls it, it's interaction between code below , library contains getresponseasync() creating conditions problem. thread code context before call getresponseasync() main thread.

background note:

this began while chasing down nullreferenceexception occuring during call getrandompetext() within doloadrandompet(). reading did on so, guess null task being returned getrandompetext(). if @ code you'll see i'm doing in power trap spurious exception , avoid returning null task. current belief still @ time null task occurring because other code generating spurious exception outside of code. perhaps in microsoft.bcl.async? strange synchronization context problem or hidden cross-thread access issue?

the strange part before made particular change did not invalidoperationexception @ all, intermittent nullreferenceexception every 1 out of 20 30 calls method chain shown below. invalidoperationexception on other hand happens every time new code structure. change made me minor 1 meant debugging efforts. thing did create method wrapper moved guts of loadrandompet() doloadrandompet(). did disable buttons triggered method calls might interfere operation random pet. wrapped call doloadrandompet() in try/finally block, make sure buttons re-enabled when operation exited. why cause such major change in code execution?

    async private void loadrandompet(int maxretries = 3)     {         // not allow guess breed or adopt me buttons          //  clicked while getting next pet.         btnadoptme.isenabled = false;         btnguessmybreed.isenabled = false;          try         {             await doloadrandompet(maxretries);         }                 {     // >>>>> code never reached.              // make sure buttons re-enabled.             btnadoptme.isenabled = true;             btnguessmybreed.isenabled = true;         }     }      // -------------------- called next      /// <summary>     /// (awaitable) loads random pet limit on number of retries in case of failure.     /// </summary>     /// <param name="maxretries">the number of retries permitted.</param>     async private task doloadrandompet(int maxretries = 3)     {         // show busy indicator.         radbusymain.visibility = visibility.visible;          try         {              // random pet.             list<keyvaluepair<string, string>> listurlargs = new list<keyvaluepair<string, string>>();              // cats.             listurlargs.addkvp("animal", petfinderutils.enumanimaltype.cat.tostring());              if (!string.isnullorwhitespace(mainmenu.zipcode))             {                 listurlargs.addkvp(petfinderutils.url_field_location, mainmenu.zipcode);             }              if (maxretries < 0)                 throw new argumentoutofrangeexception("the maximum retries value negative.");              debug.writeline("------------------ start: loading random pet ----------------");              // loop until random pet found.             int numretries = 0;              // select breed, otherwise ton of "domestic short hair" responses,             //  not game.  breeds returning empty search             //  results session filtered too.             string strbreedname = mainmenu.getrandombreedname();              listurlargs.addkvp("breed", strbreedname);              while (numretries <= maxretries)             {                 try                 {                     // save last successful retrieval.                     if (this._pbi != null)                         _pbilast = this._pbi;                      this._pbi = await getrandompetext(listurlargs);                 }                 catch (emptysearchresultsexception esr)                 {                     // getrandompetext() not find suitable cat given current parameters.                     //  swallow exception without notifying user.  allow code                     //  further down re-use last cat retrieved in hopes next                     //  quiz won't have problem.                       debug.writeline(">>>>>>>>>> doloadrandompet() - getrandompet() failed find cat.");                 }                 catch (petfinderapiexception pfexc)                 {                     if (pfexc.responsecode == petfinderutils.enumresponsecodes.pfapi_err_limit)                         // swallow exception, let user know stop playing awhile                         //  since have exceeded our rate limit.                         catquizaux.easytoast("the petfinder server busy.\nplease try playing game\nlater.");                     else                         // swallow exception, let user know stop playing awhile                         //  since have exceeded our rate limit.                         catquizaux.easytoast("the petfinder may down.\nplease try playing game\nlater.");                      // exit.                     return;                 } // try                 catch (exception exc)                 {                     // bad practice we're out of time.   swallow exception                     //  avoid crashing program.                     debug.writeline(">>>>>>>>>> doloadrandompet() - getrandompet() other exception occurrred.  exception message: " + exc.message);                 }                   // if returned pet null no pets using current search criteria                 //  found.                 if (this._pbi != null)                 {                     // got random pet, stop looping.  save backup cat field too.                     break;                 }                 else                 {                     // using location?                     if (listurlargs.haskey(petfinderutils.url_field_location))                         // retry without location open search entire petfinder api                         //  inventory.                         listurlargs.deletekvp(petfinderutils.url_field_location);                     else                     {                         // use differet breed.  add current breed list of breeds returning                         //  empty search results don't bother breed again session.                         mainmenu.listemptybreeds.add(strbreedname);                          // remove current breed.                         listurlargs.deletekvp("breed");                          // choose new breed.                         strbreedname = mainmenu.getrandombreedname();                         listurlargs.addkvp("breed", strbreedname);                     } // else - if (listurlargs.haskey(petfinderutils.url_field_location))                 } // if (this._pbi == null)                  // sleep bit.                 await taskex.delay(1000);                  numretries++;             } // while (numretries <= maxretries)              // if still have null _pbi reference, use back-up one.             if (this._pbi == null)                 this._pbi = this._pbilast;              if (this._pbi == null)                 throw new argumentnullexception("(viewpetrecord::doloadrandompet) failed find new cat quiz.  please try again later.");              // add pet quizzed list.             mainmenu.addcatquizzed(this._pbi.id.t.tostring());              // show cat's details.             lblpetname.text = this._pbi.name.t;             imgpet.source = new bitmapimage(new uri(this._pbi.media.photos.photo[0].t, urikind.absolute));              // dump cat's breed list debug window inspection.             dumpbreedsforpet(this._pbi);         }                 {             // make sure busy indicator hidden.             radbusymain.visibility = visibility.collapsed;         }     } // async private void doloadrandompet(int maxretries = 3)      // -------------------- called next      /// <summary>     /// gets random pet.  retries maxretries times find pet not in <br />     ///  quizzed list before giving , returning last 1 found.  skips pets without <br />     ///  photos.     /// </summary>     /// <param name="listurlargs">a list of url arguments pass add api call.</param>     /// <param name="maxretries">the number of retries make.</param>     /// <returns>the basic info retrieved pet or null if pet not found <br />     ///  using current url arguments (search criteria).</returns>     async private task<petbasicinfo> getrandompetext(list<keyvaluepair<string, string>> listurlargs, int maxretries = 3)     {         petbasicinfo newpbi = null;          try         {             newpbi = await dogetrandompetext(listurlargs, maxretries);         }         catch (exception exc)         {             debug.writeline(">>>>>> (viewpetrecord::getrandompetext) exception: " + exc.message);             throw;         } // try/catch          return newpbi;     } // async private void getrandompetext()      // -------------------- called next      // done debug nullreferenceexception error fighting.     //  see getrandompetext() below.     async private task<petbasicinfo> dogetrandompetext(list<keyvaluepair<string, string>> listurlargs, int maxretries = 3)     {         if (maxretries < 0)             throw new argumentoutofrangeexception("the maximum retries value negative.");          debug.writeline("------------------ start: getting random pet ----------------");          // loop until random pet found has not been used in quiz or until         //  hit maxretries limit.         int numretries = 0;          petbasicinfo pbi = null;          while (numretries <= maxretries)         {             try             {                 pbi = await mainmenu.petfinderapi.getrandompet_basic(listurlargs);             }             catch (petfinderapiexception pfexcept)             {                 // pfexcept.responsecode = petfinderutils.enumresponsecodes.pfapi_err_limit;                  switch (pfexcept.responsecode)                 {                     case petfinderutils.enumresponsecodes.pfapi_err_noent:                         debug.writeline("the petfinder api returned empty result set current url arguments.");                         // no results found.  swallow exception , return                         //  null let caller know this.                         return null;                     case petfinderutils.enumresponsecodes.pfapi_err_limit:                         debug.writeline("the petfinder api returned rate limit error.");                         // throw exception.  let caller handler it.                         throw;                     default:                         // rethrow exception know crash reports.                         // other exception.  stop retrying , show user error message.                         debug.writeline("exception during getrandompetext()\n" + pfexcept.errormessage);                         throw;                 } // switch()             }              // pet have photo?             if (pbi.media.photos.photo.length > 0)             {                 // yes. has pet been used in quiz?                 if (!mainmenu.iscatquizzed(pbi.id.t.tostring()))                     // no. success.                     return pbi;             } // if (pbi.media.photos.photo.length > 0)              // retry required.             debug.writeline(string.format("retrying, retry count: {0}", numretries));              // no photo or used in quiz.  wait little before retrying.             await taskex.delay(1000);              // count retires.             numretries++;         } // while (numretries <= maxretries)          // unable find cat not quizzed.  return last retrieved.         debug.writeline("retry count exceeded.  returning last retreived pet.");          // returning null results in await throwing non-specific nullreferenceexception.           //  better throw our own exception.         throw new emptysearchresultsexception("(viewpetrecord::getrandompetext) unable retrieve new random cat petfinder api server.");         // return pbi;     } // async private petbasicinfo dogetrandompetext()      // ------------------ called next      /// <summary>     /// returns basic information randomly chosen pet of given animal type.     /// </summary>     /// <param name="enanimaltype">the desired animal type restrict search to.</param>     /// <returns></returns>     async public task<json.jsonpetrecordtypes.petbasicinfo> getrandompet_basic(list<keyvaluepair<string, string>> urlargumentpairs = null)     {         debug.writeline("(getrandompet_basic) top of call.");          // if url argument pairs parameter null, create one.         if (urlargumentpairs == null)             urlargumentpairs = new list<keyvaluepair<string, string>>();          // add "output" parameter tells petfinder want basic information pet,         //  not id or full record.         urlargumentpairs.addkvp("output", "basic");          // add unique url argument defeat url caching may taking         //  place in windows phone library or @ petfinder api server.         //  defeats problem new random pet returned         //  each call, instead of same one.         long n = datetime.now.ticks;          urlargumentpairs.addkvp("nocache", n.tostring());          // build api call.         string strapicall =                 buildpetfinderapiurl(method_random_pet,                 urlargumentpairs);          debug.writeline("(getrandompet_basic) url call: \n" + strapicall);          // make call.         string strjsonreturn = await misc.urltostringasyncez(strapicall);          bool bisjsonreturnvalid = false;          try         {             json.jsonpetrecordtypes.petrecordbasicinfo jsonpetbasic = jsonconvert.deserializeobject<json.jsonpetrecordtypes.petrecordbasicinfo>(strjsonreturn);              // deserialization succeeded.             bisjsonreturnvalid = true;              // success code?             // strange reason t cast "int" here in getbreedlist it's equivalent cast string.             int iresponsecode = jsonpetbasic.petfinder.header.status.code.t;              if (iresponsecode != 100)                 throw new petfinderapiexception("petfinder::getrandompet_basic", iresponsecode);                 // throw new exception("(petfinder::getrandompet_basic) response document contains failure response code: " + iresponsecode.tostring() + ":" + jsonpetbasic.petfinder.header.status.message);              // return pet record basic info.             return jsonpetbasic.petfinder.pet;         }                 {             if (!bisjsonreturnvalid)                 // setting debug trap inspect json return.                 debug.writeline("json deserialization failure.");              debug.writeline("(getrandompet_basic) bottom of call.");         } // try/finally     }      // -------------------- called next, never returns      /// <summary>     /// (awaitable) simpler version of above call.  same warnings getting byte stream <br />     ///  objects apply here urltostringasync()     /// </summary>     /// <param name="sturl"></param>     /// <param name="reqmethod"></param>     /// <returns></returns>     async public static task<string> urltostringasyncez(string strurl, httprequestmethod reqmethod = httprequestmethod.http_get)     {         strurl = strurl.trim();          if (string.isnullorwhitespace(strurl))             throw new argumentexception("(misc::urltostringasyncez) url empty.");          httpwebrequest request = (httpwebrequest)webrequest.create(strurl);          // string value request method.         request.method = reqmethod.getdescription();      // >>>>> call getresponseasync() triggers exception (see stack trace below)         // async wait respone.         httpwebresponse response = (httpwebresponse)await request.getresponseasync();          // use stream reader return string.         using (var sr = new streamreader(response.getresponsestream()))         {             return sr.readtoend();         }     }  // -------------------- stack trace before urltostringasync(), call triggers exception.  >   common_wp7.dll!common_wp7.misc.urltostringasyncez(string strurl, common_wp7.misc.httprequestmethod reqmethod) line 1079 c# catquiz.dll!catquiz.petfinderutils.getrandompet_basic(system.collections.generic.list<system.collections.generic.keyvaluepair<string,string>> urlargumentpairs) line 441    c# catquiz.dll!catquiz.viewpetrecord.dogetrandompetext(system.collections.generic.list<system.collections.generic.keyvaluepair<string,string>> listurlargs, int maxretries) line 55    c# catquiz.dll!catquiz.viewpetrecord.getrandompetext(system.collections.generic.list<system.collections.generic.keyvaluepair<string,string>> listurlargs, int maxretries) line 123 c# catquiz.dll!catquiz.viewpetrecord.doloadrandompet(int maxretries) line 243  c# catquiz.dll!catquiz.viewpetrecord.loadrandompet(int maxretries) line 343    c# catquiz.dll!catquiz.viewpetrecord.pageviewpetrecord_loaded(object sender, system.windows.routedeventargs e) line 355    c# system.windows.ni.dll!ms.internal.coreinvokehandler.invokeeventhandler(int typeindex, system.delegate handlerdelegate, object sender, object args)  unknown system.windows.ni.dll!ms.internal.jolthelper.fireevent(system.intptr unmanagedobj, system.intptr unmanagedobjargs, int argstypeindex, int actualargstypeindex, string eventname)    unknown      ======================= exception  // -------------------- stack trace when exception occurs >   catquiz.dll!catquiz.app.application_unhandledexception(object sender, system.windows.applicationunhandledexceptioneventargs e) line 101 c# system.windows.ni.dll!ms.internal.error.callapplicationuehandler(system.exception e)    unknown system.windows.ni.dll!ms.internal.error.isnonrecoverableuserexception(system.exception ex, out uint xresultvalue)   unknown system.windows.ni.dll!ms.internal.jolthelper.fireevent(system.intptr unmanagedobj, system.intptr unmanagedobjargs, int argstypeindex, int actualargstypeindex, string eventname)    unknown       // -------------------- code context when exception occurs     // code execute on unhandled exceptions     private void application_unhandledexception(object sender, applicationunhandledexceptioneventargs e)     {         if (system.diagnostics.debugger.isattached)         {             // unhandled exception has occurred; break debugger             system.diagnostics.debugger.break();         }     } 


Comments

Popular posts from this blog

blackberry 10 - how to add multiple markers on the google map just by url? -

php - guestbook returning database data to flash -

java - Using an Integer ArrayList in Android -