0

On my Xamarin Forms project I'm trying to logout when the token is no longer valid and it returns 401 response.

For that I'm trying to use a DelegatingHandler but it will stop at SendAsync method without giving any errors.

Here is the DelegatingHandler class

public class HttpDelegatingHandler : DelegatingHandler
    {
        public HttpDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler)
        {
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // before request

            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            // after request

            if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
            {
                await Logout();
            }

            return response;
        }

        private async Task Logout()
        {
            CurrentPropertiesService.Logout();
            CurrentPropertiesService.RemoveCart();
            await Shell.Current.GoToAsync($"//main");
        }

And here is my class AzureApiService where GetAsync stops the application

 public class AzureApiService
    {
        HttpClient httpClient;

        public AzureApiService()
        {

#if DEBUG
            var httpHandler = new HttpDelegatingHandler(new HttpClientHandler());

#else
            var httpHandler = HttpDelegatingHandler(new HttpClientHandler());
#endif
            httpClient = new HttpClient(httpHandler);
            httpClient.Timeout = TimeSpan.FromSeconds(15);
            httpClient.MaxResponseContentBufferSize = 256000;
        }

        public async Task<string> LoginAsync(string url, AuthUser data)
        {
            var user = await HttpLoginPostAsync(url, data);

            if (user != null)
            {
                //Save data on constants
                CurrentPropertiesService.SaveUser(user);
                return user.Token;
            }
            else
            {
                return string.Empty;
            }
        }

        // Generic Get Method
        public async Task<T> HttpGetAsync<T>(string url, string token)
        {
            T result = default(T);

            try
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                var response = await httpClient.GetAsync(url);
                HttpContent content = response.Content;


                var jsonResponse = await content.ReadAsStringAsync();
                result = JsonConvert.DeserializeObject<T>(jsonResponse);

            }
            catch (Exception ex)
            {
                OnError(ex.ToString());
            }

            return result;

        }

Please help I don't know where the issue is. Thanks.

robluc
  • 121
  • 12
  • Might be a deadlock. Though I don't see anything in code that would cause that. If you set a breakpoint on that line, and look at call stack: Is there anything on the call stack that is **not** an `async` method? (For examples of situations that deadlock, google `xamarin httpclient deadlock`.) – ToolmakerSteve May 16 '22 at 17:40
  • @ToolmakerSteve I don't think is a deadlock but either way i found that my issue was another thing and I won't be able to do this till I solve my shell navigation problem. I posted a new question in case you can take a look at it. Thanks! – robluc May 16 '22 at 17:47
  • Which line caused the `TaskCanceledException`? Had you tried to skip the inner handler and directly create the response just like the [official document](https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers) says? – Liyun Zhang - MSFT May 17 '22 at 06:42
  • @LiyunZhang-MSFT No I haven't but before I make this work I need to be able to simply logout when a 401 response is found and it gives me error with shell navigation. If you could please take a look at my last question – robluc May 17 '22 at 07:04
  • I had checked it just now, you can check [this case](https://stackoverflow.com/questions/68234488/shell-current-gotoasync-to-xctpopup-results-in-error-system-nullreferenceexcept). Maybe the `Shell.Current` in your service is null, you can debug and check it. – Liyun Zhang - MSFT May 17 '22 at 07:36
  • @LiyunZhang-MSFT It is not null... I don't know why it works from a ViewModel but not from Service – robluc May 17 '22 at 07:46
  • Try to add a judge into the LoginPage's constructor such as `if(_azureApiService==null) _azureApiService = new AzureApiService();` – Liyun Zhang - MSFT May 17 '22 at 07:53
  • @LiyunZhang-MSFT It doesn't work. The issue is that after Shell.Current.GoToAsync is called it just continues with the code that I have on my `HttpGetAsync` method, returns the result and gives errors everywhere. I just want it to not continue with the code – robluc May 17 '22 at 07:57
  • @LiyunZhang-MSFT I don't think it will work from Service because I just saw a question where it happens the same, but I don't know where to do it then – robluc May 17 '22 at 08:03
  • But according to your description, it call the LoginPage's constructor which will create a new service and so on, it's a strange behavior. Normally, the instance of the page will not be recycled and it will not call the page's constructor when you go to a page which is not show the first time. – Liyun Zhang - MSFT May 17 '22 at 08:04
  • @LiyunZhang-MSFT By debugging I have found that using the route //login which is the one that I want won't call the `LoginPage` constructor. It works but as I said it just goes on with the code. I found that doing this from the service is the issue but don't know where or how to do it elsewhere – robluc May 17 '22 at 08:08
  • But I create a simple shell app, and when I call `await Shell.Current.GoToAsync(nameof(AboutPage));` from the loadata service, it can get into the AboutPage. – Liyun Zhang - MSFT May 17 '22 at 08:19
  • @LiyunZhang-MSFT Yes the issue is that it goes on with the code that I have on my Get method. So it can get into the page but it will give errors as the code goes on. I will insert a video on my last question – robluc May 17 '22 at 08:23
  • @LiyunZhang-MSFT I have added the video so you see what is happening – robluc May 17 '22 at 08:43
  • It seems I can't get it, when I open the link , it tell me denied. – Liyun Zhang - MSFT May 17 '22 at 08:46
  • @LiyunZhang-MSFT You should get access now – robluc May 17 '22 at 08:47
  • So when you use the route //login, the login page will not show and the program will continue with the Get method? – Liyun Zhang - MSFT May 17 '22 at 08:57
  • @LiyunZhang-MSFT exactly. I know the route is fine as it shows the page when I use it on my ViewModel but when I use it there the program continues with the get method and causes all the problems – robluc May 17 '22 at 08:59
  • You can check [this case](https://stackoverflow.com/questions/72170399/httppostasync-not-returning-any-result-but-inserting-entity-correctly/72179706#72179706) and try to use the `Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => { }` somewhere such as `Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => { await Shell.Current.GoToAsync($"//login"); }` – Liyun Zhang - MSFT May 17 '22 at 09:10
  • @LiyunZhang-MSFT the program stills continues with the get method – robluc May 17 '22 at 09:25
  • You may need to call `await Shell.Current.GoToAsync($"//login");` after the get method completed. – Liyun Zhang - MSFT May 18 '22 at 06:29

0 Answers0