GithubHelp home page GithubHelp logo

Comments (4)

shohei-51 avatar shohei-51 commented on August 16, 2024 1

@ThadT
By implementing your updated code, my app now works fine without NullReferenceException

Thank you for reviewing this case.
I appreciate your support.

from arcgis-maps-sdk-dotnet-samples.

ThadT avatar ThadT commented on August 16, 2024

@shohei-51
Thanks, and apologies for the late reply.
I haven't been able to reproduce this problem, are you still experiencing it? If so, can you perhaps try using the same OAuth info I'm testing with? Here it is:

// URL of the server to authenticate with
private const string ServerUrl = "https://www.arcgis.com/sharing/rest";
// TODO: Provide the client ID for your app (registered with the server)
private const string ClientId = "2Gh53JRzkPtOENQq";
// TODO: Provide a URL registered for the app for redirecting after a successful authorization
private const string RedirectUrl = "https://developers.arcgis.com";
// TODO: Provide an ID for a secured web map item hosted on the server
private const string WebMapId = "72b6671b89194220b44c4361a17f4fcb";

Thanks

from arcgis-maps-sdk-dotnet-samples.

shohei-51 avatar shohei-51 commented on August 16, 2024

@ThadT
Thank you for your reply. I have uploaded my test code
https://github.com/shohei-51/AGOAuthSample

Please run the test code. For the first sign-in, there will be no NullReferenceException. Then sign out once and sign-in again. In my environment, the second time sign-in triggers the NullReferenceException.

I'm wondering if this is because I'm not correctly signing-out from AGO.

Thank you

from arcgis-maps-sdk-dotnet-samples.

ThadT avatar ThadT commented on August 16, 2024

@shohei-51
I gave this a look today and experienced the same issue you described. I could work around the issue by either:

  • copying the private _tcs variable into a local variable
  • always dispatching to the UI thread

It looks like _tcs was getting set to null and the two workarounds above either delay the call enough to avoid the error or make a local copy before the private variable is destroyed.

While these workarounds are fine, I think I found a cleaner way to do it. The key is to never explicitly set the TaskCompletionSource variable to null. Instead of checking if the variable is null in the challenge handler function, see if the associated Task is still in progress.

I've enclosed the relevant parts of the updated code below. Thanks a bunch for pointing out this problem! I'll make sure to update the OAuth samples to use these updates. Let me know if you continue to have problems or have further questions.

        // Function to handle authorization requests, takes the URIs for the secured service, the authorization endpoint, and the redirect URI
        public Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
        {
            if (_tcs?.Task.IsCompleted == false)
                throw new Exception("Task in progress");

            _tcs = new TaskCompletionSource<IDictionary<string, string>>();

            // Store the authorization and redirect URLs
            _authorizeUrl = authorizeUri.AbsoluteUri;
            _callbackUrl = callbackUri.AbsoluteUri;

            // Call a function to show the login controls, make sure it runs on the UI thread for this app
            var dispatcher = Application.Current.Dispatcher;
            if (dispatcher == null || dispatcher.CheckAccess())
            {
                AuthorizeOnUIThread(_authorizeUrl);
            }
            else
            {
                var authorizeOnUIAction = new Action((() => AuthorizeOnUIThread(_authorizeUrl)));
                dispatcher.BeginInvoke(authorizeOnUIAction);
            }

            // Return the task associated with the TaskCompletionSource
             return _tcs.Task;
        }

        // Challenge for OAuth credentials on the UI thread
        private void AuthorizeOnUIThread(string authorizeUri)
        {
            // Create a WebBrowser control to display the authorize page
            var webBrowser = new WebBrowser();

            // Handle the navigation event for the browser to check for a response to the redirect URL
            webBrowser.Navigating += WebBrowserOnNavigating;

            // Display the web browser in a new window 
            _window = new Window
            {
                Content = webBrowser,
                Height = 430,
                Width = 395,
                WindowStartupLocation = WindowStartupLocation.CenterOwner
            };

            // Set the app's window as the owner of the browser window (if main window closes, so will the browser)
            if (Application.Current != null && Application.Current.MainWindow != null)
            {
                _window.Owner = Application.Current.MainWindow;
            }

            // Handle the window closed event then navigate to the authorize url
            _window.Closed += OnWindowClosed;
            webBrowser.Navigate(authorizeUri);

            // Display the Window
            _window.ShowDialog();
        }

        // Handle the browser window closing
        void OnWindowClosed(object sender, EventArgs e)
        {
            // If the browser window closes, return the focus to the main window
            if (_window != null && _window.Owner != null)
            {
                _window.Owner.Focus();
            }

            // If the task wasn't completed, the user must have closed the window without logging in
            if (!_tcs.Task.IsCompleted)
            {
                // Set the task completion source exception to indicate a canceled operation
                _tcs.SetCanceled();
            }

            _window = null;
        }

        // Handle browser navigation (content changing)
        void WebBrowserOnNavigating(object sender, NavigatingCancelEventArgs e)
        {            
            // Check for a response to the callback url
            const string portalApprovalMarker = "/oauth2/approval";
            var webBrowser = sender as WebBrowser;

            Uri uri = e.Uri;

            // If no browser, uri, or an empty url, return
            if (webBrowser == null || uri == null || string.IsNullOrEmpty(uri.AbsoluteUri))
                return;

            // Check for redirect
            bool isRedirected = uri.AbsoluteUri.StartsWith(_callbackUrl) ||
                _callbackUrl.Contains(portalApprovalMarker) && uri.AbsoluteUri.Contains(portalApprovalMarker);

            if (isRedirected)
            {
                // Browser was redirected to the callbackUrl (success!)
                //    -close the window 
                //    -decode the parameters (returned as fragments or query)
                //    -return these parameters as result of the Task
                e.Cancel = true;

                // Call a helper function to decode the response parameters
                var authResponse = DecodeParameters(uri);

                // Set the result for the task completion source
                _tcs.SetResult(authResponse);

                if (_window != null)
                {
                    _window.Close();
                }
            }
        }

from arcgis-maps-sdk-dotnet-samples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.