none
InvalidOperationException: Sequence contains no elements ADALTokenCache.BeforeAccessNotification(TokenCacheNotificationArgs args) in AdalTokenCache.cs:60 RRS feed

  • Question

  • Hi

    I am getting the following error when I am accessing a MVC5 site which has been developed for internal purposes. This site uses o365 authentication for the users and works fine while authenticating for the first time However after the first access, the user gets this error 

    [InvalidOperationException: Sequence contains no elements]
       System.Linq.Enumerable.First(IEnumerable`1 source) +451
       Web.Models.ADALTokenCache.BeforeAccessNotification(TokenCacheNotificationArgs args) in C:\Users\ramprakashumapathy\source\Kasanova\Progetti\Sede\FaldoneFotoNew\Web\Models\AdalTokenCache.cs:60
       Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache.OnBeforeAccess(TokenCacheNotificationArgs args) +95
       Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.<StoreResultExToCacheAsync>d__54.MoveNext() +92
       System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +60
       Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.<RunAsync>d__53.MoveNext() +3747
       System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +60
       Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenByAuthorizationCodeCommonAsync>d__35.MoveNext() +451
       System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +60
       Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenByAuthorizationCodeAsync>d__51.MoveNext() +368

     

    The stack trace indicates the line 60 of file generated while creating the MVC project.

     

    This happens especially when an application pool has been recycled and I can able to reproduce the error by recycling the pool. Not sure how to resolve. I hereby attach cs file

    Thanks,

    Holy

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using Microsoft.IdentityModel.Clients.ActiveDirectory;
    
    namespace Web.Models
    {
        public class ADALTokenCache : TokenCache
        {
            private ApplicationDbContext db = new ApplicationDbContext();
            private string userId;
            private UserTokenCache Cache;
    
            public ADALTokenCache(string signedInUserId)
            {
                // associate the cache to the current user of the web app
                userId = signedInUserId;
                this.AfterAccess = AfterAccessNotification;
                this.BeforeAccess = BeforeAccessNotification;
                this.BeforeWrite = BeforeWriteNotification;
                // look up the entry in the database
                Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
                // place the entry in memory
                try
                {
                    this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
                }
                catch (System.Security.Cryptography.CryptographicException cge)
                {
                    db.UserTokenCacheList.Remove(Cache);
                    db.SaveChanges();
                }
            }
    
            // clean up the database
            public override void Clear()
            {
                base.Clear();
                var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
                db.UserTokenCacheList.Remove(cacheEntry);
                db.SaveChanges();
            }
    
            // Notification raised before ADAL accesses the cache.
            // This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
            void BeforeAccessNotification(TokenCacheNotificationArgs args)
            {
                if (Cache == null)
                {
                    // first time access
                    Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
                }
                else
                { 
                    // retrieve last write from the DB
                    var status = from e in db.UserTokenCacheList
                                 where (e.webUserUniqueId == userId)
                    select new
                    {
                        LastWrite = e.LastWrite
                    };
    
                    // if the in-memory copy is older than the persistent copy
                    if (status.First().LastWrite > Cache.LastWrite)
                    {
                        // read from from storage, update in-memory copy
                        Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
                    }
                }
                this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
            }
    
            // Notification raised after ADAL accessed the cache.
            // If the HasStateChanged flag is set, ADAL changed the content of the cache
            void AfterAccessNotification(TokenCacheNotificationArgs args)
            {
                // if state changed
                if (this.HasStateChanged)
                {
                    if (Cache == null)
                    {
                        Cache = new UserTokenCache
                        {
                            webUserUniqueId = userId
                        };
                    }
    
                    Cache.cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache");
                    Cache.LastWrite = DateTime.Now;
    
                    // update the DB and the lastwrite 
                    db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
                    db.SaveChanges();
                    this.HasStateChanged = false;
                }
            }
    
            void BeforeWriteNotification(TokenCacheNotificationArgs args)
            {
                // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
            }
    
            public override void DeleteItem(TokenCacheItem item)
            {
                base.DeleteItem(item);
            }
        }
    }


    • Edited by Holysmoke Tuesday, February 19, 2019 11:13 AM
    Tuesday, February 19, 2019 11:12 AM