private void navigate( ResourceInfo destination, FullResponse secondaryResponse ) { var requestState = AppRequestState.Instance.EwfPageRequestState; string destinationUrl; try { // Determine the final redirect destination. If a destination is already specified and it is the current page or a page with the same entity setup, // replace any default optional parameter values it may have with new values from this post back. If a destination isn't specified, make it the current // page with new parameter values from this post back. At the end of this block, redirectInfo is always newly created with fresh data that reflects any // changes that may have occurred in EH methods. It's important that every case below *actually creates* a new page info object to guard against this // scenario: // 1. A page modifies data such that a previously created redirect destination page info object that is then used here is no longer valid because it // would throw an exception from init if it were re-created. // 2. The page redirects, or transfers, to this destination, leading the user to an error page without developers being notified. This is bad behavior. if( requestState.ModificationErrorsExist || ( requestState.DmIdAndSecondaryOp != null && requestState.DmIdAndSecondaryOp.Item2 == SecondaryPostBackOperation.NoOperation ) ) destination = InfoAsBaseType.CloneAndReplaceDefaultsIfPossible( true ); else if( destination != null ) destination = destination.CloneAndReplaceDefaultsIfPossible( false ); else destination = createInfoFromNewParameterValues(); // This GetUrl call is important even for the transfer case below for the same reason that we *actually create* a new page info object in every case // above. We want to force developers to get an error email if a page modifies data to make itself unauthorized/disabled without specifying a different // page as the redirect destination. The resulting transfer would lead the user to an error page. destinationUrl = destination.GetUrl(); } catch( Exception e ) { throw getPossibleDeveloperMistakeException( "The post-modification destination page became invalid.", innerException: e ); } // Put the secondary response into session state right before navigation so that it doesn't get sent if there is an error before this point. if( secondaryResponse != null ) { // It's important that we put the response in session state first since it's used by the Info.init method of the pre-built-response page. StandardLibrarySessionState.Instance.ResponseToSend = secondaryResponse; StandardLibrarySessionState.Instance.SetClientSideNavigation( EwfApp.MetaLogicFactory.CreatePreBuiltResponsePageInfo().GetUrl(), !secondaryResponse.FileName.Any(), null ); } // If the redirect destination is identical to the current page, do a transfer instead of a redirect. if( destination.IsIdenticalToCurrent() ) { AppRequestState.Instance.ClearUserAndImpersonator(); resetPage(); } // If the redirect destination is the current page, but with different query parameters, save request state in session state until the next request. if( destination.GetType() == InfoAsBaseType.GetType() ) StandardLibrarySessionState.Instance.EwfPageRequestState = requestState; NetTools.Redirect( destinationUrl ); }