Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在调用GetResponseAsync()期间获取InvalidOperationException?_C#_Windows Phone 7_Async Await_Nullreferenceexception_Invalidoperationexception - Fatal编程技术网

C# 在调用GetResponseAsync()期间获取InvalidOperationException?

C# 在调用GetResponseAsync()期间获取InvalidOperationException?,c#,windows-phone-7,async-await,nullreferenceexception,invalidoperationexception,C#,Windows Phone 7,Async Await,Nullreferenceexception,Invalidoperationexception,前言:我知道代码摘录很长,但我不想遗漏一个其他人可能会认为是问题原因的细节。代码有点冗长,并且存在许多异常陷阱,这是因为我在下面描述了对NullReferenceException的搜索。通过跳转到在相互调用的async方法中找到的wait关键字,您可以快速浏览代码,找到重要部分 更新:InvalidOperationException正在发生,因为我正在更改某些按钮的IsEnabled状态。我处于主线上,所以我不确定为什么会发生这种情况。有人知道为什么吗 我有一个用C语言编写的Windows

前言:我知道代码摘录很长,但我不想遗漏一个其他人可能会认为是问题原因的细节。代码有点冗长,并且存在许多异常陷阱,这是因为我在下面描述了对NullReferenceException的搜索。通过跳转到在相互调用的async方法中找到的wait关键字,您可以快速浏览代码,找到重要部分

更新:InvalidOperationException正在发生,因为我正在更改某些按钮的IsEnabled状态。我处于主线上,所以我不确定为什么会发生这种情况。有人知道为什么吗

我有一个用C语言编写的Windows Phone 7应用程序,它得到一个系统。当在特定代码上下文中调用GetResponseAsync()时,InvalidOperationException。该应用程序使用PetFinder API创建一个猫品种猜测游戏,旨在帮助动物收容所的猫被收养。以下是完整的异常消息:

Message: An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.ni.dll
在异常发生之前,对GetResponseAsync()有几个成功的调用。我已经按照下面调用的顺序包含了异常中涉及的方法的代码。有人能告诉我为什么会出现这个异常以及如何修复它吗

异常完全是在调用它的当前代码上下文之外发生的,因此下面的代码和包含GetResponseAsync()的库之间的一些交互为问题创造了条件。调用GetResponseAsync()之前的线程代码上下文是主线程

背景说明:

这一切都始于我在调用doLoadRandomPet()中的getRandomPetExt()时发现的NullReferenceException。根据我在上面所做的阅读,我猜测是从getRandomPetExt()返回了一个NULL任务。但是,如果您查看该代码,您会发现我正在尽我所能捕获虚假异常并避免返回空任务。目前我仍然认为,之所以出现空任务,是因为其他一些代码在我的代码之外生成了一个虚假的异常。可能是Microsoft.Bcl.Async中的某些内容?这是某种奇怪的同步上下文问题还是隐藏的跨线程访问问题

奇怪的是,在我进行特定更改之前,我根本没有得到InvalidOperationException,只有间歇性的NullReferenceException每隔20到30次调用一次方法链,如下所示。另一方面,InvalidOperationException每次使用新的代码结构时都会发生。我所做的改动对我来说只是一个小改动,旨在帮助我进行调试。我所做的唯一一件事就是创建一个方法包装器,将loadRandomPet()的内容移动到doLoadRandomPet()。我这样做是为了禁用一些触发方法调用的按钮,这些方法调用可能会干扰获取随机宠物的操作。我在try/finally块中包装了对doLoadRandomPet()的调用,以确保在操作退出时按钮被重新启用。为什么这会导致代码执行发生如此重大的变化

    async private void loadRandomPet(int maxRetries = 3)
    {
        // Do not allow the Guess My Breed or Adopt Me buttons to be 
        //  clicked while we are getting the next pet.
        btnAdoptMe.IsEnabled = false;
        btnGuessMyBreed.IsEnabled = false;

        try
        {
            await doLoadRandomPet(maxRetries);
        }
        finally
        {
    // >>>>> THIS CODE IS NEVER REACHED.

            // Make sure the buttons are re-enabled.
            btnAdoptMe.IsEnabled = true;
            btnGuessMyBreed.IsEnabled = true;
        }
    }

    // -------------------- CALLED NEXT

    /// <summary>
    /// (awaitable) Loads a random pet with a limit on the 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 the busy indicator.
        radbusyMain.Visibility = Visibility.Visible;

        try
        {

            // Get a random pet.
            List<KeyValuePair<string, string>> listUrlArgs = new List<KeyValuePair<string, string>>();

            // Only 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 is negative.");

            Debug.WriteLine("------------------ START: LOADING Random Pet ----------------");

            // Loop until a random pet is found.
            int numRetries = 0;

            // Select the breed, otherwise we will get a ton of "Domestic Short Hair" responses,
            //  which are not good for the game.  Breeds that are returning empty search
            //  results this session are filtered too.
            string strBreedName = MainMenu.GetRandomBreedName();

            listUrlArgs.addKVP("breed", strBreedName);

            while (numRetries <= maxRetries)
            {
                try
                {
                    // Save the last successful retrieval.
                    if (this._pbi != null)
                        _pbiLast = this._pbi;

                    this._pbi = await getRandomPetExt(listUrlArgs);
                }
                catch (EmptySearchResultsException esr)
                {
                    // getRandomPetExt() could not find a suitable cat given the current parameters.
                    //  Swallow the Exception without notifying the user.  Just allow the code
                    //  further down to re-use the last cat retrieved in the hopes the next
                    //  quiz won't have the problem.  
                    Debug.WriteLine(">>>>>>>>>> doLoadRandomPet() - getRandomPet() failed to find a cat.");
                }
                catch (PetFinderApiException pfExc)
                {
                    if (pfExc.ResponseCode == PetFinderUtils.EnumResponseCodes.PFAPI_ERR_LIMIT)
                        // Swallow the Exception, but let the user know to stop playing for the awhile
                        //  since we have exceeded our rate limit.
                        CatQuizAux.EasyToast("The PetFinder server is busy.\nPlease try playing the game\nlater.");
                    else
                        // Swallow the Exception, but let the user know to stop playing for the awhile
                        //  since we have exceeded our rate limit.
                        CatQuizAux.EasyToast("The PetFinder may be down.\nPlease try playing the game\nlater.");

                    // Just exit.
                    return;
                } // try
                catch (Exception exc)
                {
                    // This is really bad practice but we're out of time.   Just swallow the Exception
                    //  to avoid crashing the program.
                    Debug.WriteLine(">>>>>>>>>> doLoadRandomPet() - getRandomPet() Other Exception occurrred.  Exception Message: " + exc.Message);
                }


                // If the returned pet is NULL then no pets using the current search criteria
                //  could be found.
                if (this._pbi != null)
                {
                    // Got a random pet, stop looping.  Save it to the backup cat field too.
                    break;
                }
                else
                {
                    // Are we using a location?
                    if (listUrlArgs.hasKey(PetFinderUtils.URL_FIELD_LOCATION))
                        // Retry without the location to open the search to the entire PetFinder API
                        //  inventory.
                        listUrlArgs.deleteKVP(PetFinderUtils.URL_FIELD_LOCATION);
                    else
                    {
                        // Use a differet breed.  Add the current breed to the list of breeds returning
                        //  empty search results so we don't bother with that breed again this session.
                        MainMenu.ListEmptyBreeds.Add(strBreedName);

                        // Remove the current breed.
                        listUrlArgs.deleteKVP("breed");

                        // Choose a new breed.
                        strBreedName = MainMenu.GetRandomBreedName();
                        listUrlArgs.addKVP("breed", strBreedName);
                    } // else - if (listUrlArgs.hasKey(PetFinderUtils.URL_FIELD_LOCATION))
                } // if (this._pbi == null)

                // Sleep a bit.
                await TaskEx.Delay(1000);

                numRetries++;
            } // while (numRetries <= maxRetries)

            // If we still have a null _pbi reference, use the back-up one.
            if (this._pbi == null)
                this._pbi = this._pbiLast;

            if (this._pbi == null)
                throw new ArgumentNullException("(ViewPetRecord::doLoadRandomPet) Failed completely to find a new cat for the quiz.  Please try again later.");

            // Add the pet to the already quizzed list.
            MainMenu.AddCatQuizzed(this._pbi.Id.T.ToString());

            // Show the 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 the cat's breed list to the Debug window for inspection.
            dumpBreedsForPet(this._pbi);
        }
        finally
        {
            // Make sure the busy indicator is hidden.
            radbusyMain.Visibility = Visibility.Collapsed;
        }
    } // async private void doLoadRandomPet(int maxRetries = 3)

    // -------------------- CALLED NEXT

    /// <summary>
    /// Gets a Random Pet.  Retries up to maxRetries times to find a pet not in the already <br />
    ///  quizzed list before giving up and returning the last one found.  Also skips pets without <br />
    ///  photos.
    /// </summary>
    /// <param name="listUrlArgs">A list of URL arguments to pass add to the API call.</param>
    /// <param name="maxRetries">The number of retries to make.</param>
    /// <returns>The basic info for the retrieved pet or NULL if a pet could not be found <br />
    ///  using the 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

    // This was done just to help debug the NullReferenceException error we are currently 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 is negative.");

        Debug.WriteLine("------------------ START: Getting Random Pet ----------------");

        // Loop until a random pet is found that has not already been used in the quiz or until
        //  we hit the 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 an empty result set with the current URL arguments.");
                        // No results found.  Swallow the Exception and return
                        //  NULL to let the caller know this.
                        return null;
                    case PetFinderUtils.EnumResponseCodes.PFAPI_ERR_LIMIT:
                        Debug.WriteLine("The PetFinder API returned a rate limit error.");
                        // Throw the Exception.  Let the caller handler it.
                        throw;
                    default:
                        // Rethrow the Exception so we know about it from the crash reports.
                        // Other Exception.  Stop retrying and show the user the error message.
                        Debug.WriteLine("Exception during getRandomPetExt()\n" + pfExcept.ErrorMessage);
                        throw;
                } // switch()
            }

            // Does the pet have a photo?
            if (pbi.Media.Photos.Photo.Length > 0)
            {
                // Yes. Has the pet already been used in a 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 already used in a quiz.  Wait a little before retrying.
            await TaskEx.Delay(1000);

            // Count retires.
            numRetries++;
        } // while (numRetries <= maxRetries)

        // Unable to find a cat not already quizzed.  Just return the last retrieved.
        Debug.WriteLine("Retry count exceeded.  Returning last retreived pet.");

        // Returning NULL results in a await throwing a non-specific NullReferenceException.  
        //  Better to throw our own Exception.
        throw new EmptySearchResultsException("(ViewPetRecord::getRandomPetExt) Unable to retrieve a new random cat from the PetFinder API server.");
        // return pbi;
    } // async private PetBasicInfo doGetRandomPetExt()

    // ------------------ CALLED NEXT

    /// <summary>
    /// Returns the basic information for a randomly chosen pet of the given animal type.
    /// </summary>
    /// <param name="enAnimalType">The desired animal type to restrict the 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 the URL Argument Pairs parameter is null, then create one.
        if (urlArgumentPairs == null)
            urlArgumentPairs = new List<KeyValuePair<string, string>>();

        // Add the "output" parameter that tells PetFinder we want the Basic information for the pet,
        //  not the ID or full record.
        urlArgumentPairs.addKVP("output", "basic");

        // Add a unique URL argument to defeat URL caching that may be taking
        //  place in the Windows Phone library or at the PetFinder API server.
        //  This defeats the problem so that a new random pet is returned
        //  each call, instead of the same one.
        long n = DateTime.Now.Ticks;

        urlArgumentPairs.addKVP("nocache", n.ToString());

        // Build the API call.
        string strApiCall =
                buildPetFinderApiUrl(METHOD_RANDOM_PET,
                urlArgumentPairs);

        Debug.WriteLine("(GetRandomPet_basic) URL for call: \n" + strApiCall);

        // Make the 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?
            // For some strange reason T is cast to an "int" here where in GetBreedList it's equivalent is cast to a 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) The response document contains a failure response code: " + iResponseCode.ToString() + ":" + jsonPetBasic.Petfinder.Header.Status.Message);

            // Return the pet record basic info.
            return jsonPetBasic.Petfinder.Pet;
        }
        finally
        {
            if (!bIsJsonReturnValid)
                // Setting debug trap to 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 about getting byte stream <br />
    ///  objects apply here as they do to 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) The URL is empty.");

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);

        // Get the string value for the request method.
        request.Method = reqMethod.GetDescription();

    // >>>>> THIS CALL to GetResponseAsync() TRIGGERS THE EXCEPTION (see stack trace below)
        // Async wait for the respone.
        HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();

        // Use a stream reader to return the string.
        using (var sr = new StreamReader(response.GetResponseStream()))
        {
            return sr.ReadToEnd();
        }
    }

// -------------------- STACK TRACE JUST BEFORE URLToStringAsync(), the call the triggers the 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 to execute on Unhandled Exceptions
    private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            // An unhandled exception has occurred; break into the debugger
            System.Diagnostics.Debugger.Break();
        }
    }
async private void loadRandomPet(int-maxRetries=3)
{
//不要让“猜我的品种”或“领养我的纽扣”被忽略
//当我们得到下一只宠物时点击。
btnAdoptMe.IsEnabled=false;
btnguesmybreed.IsEnabled=false;
尝试
{
等待doLoadRandomPet(最大重试次数);
}
最后
{
//>>>>>>>永远不会到达此代码。
//确保按钮已重新启用。
btnAdoptMe.IsEnabled=true;
btnguesmybreed.IsEnabled=true;
}
}
//---------下一步调用
/// 
///(等待)加载随机宠物,并限制失败时的重试次数。
/// 
///允许的重试次数。
异步专用任务doLoadRandomPet(int maxRetries=3)
{
//显示忙指示灯。
radbusyMain.Visibility=可见性.Visibility;
尝试
{
//随机得到一只宠物。
List listUrlArgs=新列表();
//只有猫。
listUrlArgs.addKVP(“动物”,PetFinderUtils.enumanialtype.cat.ToString());
如果(!String.IsNullOrWhiteSpace(main menu.ZipCode))
{
listUrlArgs.addKVP(PetFinderUtils.URL\u FIELD\u位置,main menu.ZipCode);
}
如果(最大重试次数<0)
抛出新ArgumentOutOfRangeException(“最大重试次数值为负值”);
Debug.WriteLine(“--------------开始:加载随机Pet--------------------”;
//循环直到找到随机的宠物。
int numRetries=0;
//选择品种,否则我们会得到大量的“国产短发”回复,
//这对游戏不好。返回空搜索的品种
//此会话的结果也将被筛选。
字符串strBreedName=MainMenu.GetRandomBreedName();
listUrlArgs.addKVP(“品种”,strBreedName);
while(numRetries>>>>此对GetResponseAsync()的调用会触发异常(请参阅下面的堆栈跟踪)
//异步等待响应。
HttpWebResponse=(HttpWebResponse)等待请求。GetResponseAsync();
//使用流读取器返回字符串。
使用(var sr=newstreamreader(response.GetResponseStream())
{
返回sr.ReadToEnd();