Open Closed

Extrange caching Behavior #4706


User avatar
0
jmalla.cp created
  • ABP Framework version: v6.0.1
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): Tired
  • UI Theme: LeptonX: Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX 1.0.0

I get strange behavior when running my project on my production service.

Everything starts up fine, but after a few minuts doing nothing on the web, when I run some action on the web, such as click menu option, the left hand menu disappear, and the web shows me that I'm not authorized. If I try to logout and go back in again the issue persists. I need to clean the browser cache and redis cache and then everything shows up.


10 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please share all logs of your projects. AuthServer ApiHost and Web. liming.ma@volosoft.com

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The token lifetime is 1 hour by default. You can increase it by

    PreConfigure<OpenIddictServerBuilder>(builder =>
    {
        builder.SetAccessTokenLifetime(TimeSpan.FromHours(12));
    });
    
  • User Avatar
    0
    jmalla.cp created

    Hi,

    I get it, but if I log out and then log back in, the menu on the left dosen't show it. Why if I renewed the token?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can try IntrospectAccessToken in your web project. please share the logs of AuthServer ApiHost and Web again if still not working.

        <PackageReference Include="IdentityModel" Version="6.0.0" />
    
    context.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies", options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromDays(365);
            options.IntrospectAccessToken();
        })
    
    using System;
    using IdentityModel.Client;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Options;
    
    namespace MyCompanyName.MyProjectName.Web;
    
    public static class CookieAuthenticationOptionsExtensions
    {
        /// <summary>
        /// Introspect access token on validating the principal.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="oidcAuthenticationScheme"></param>
        /// <returns></returns>
        public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc")
        {
            var originalHandler = options.Events.OnValidatePrincipal;
            options.Events.OnValidatePrincipal = async principalContext =>
            {
                originalHandler?.Invoke(principalContext);
    
                if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated)
                {
                    var accessToken = principalContext.Properties.GetTokenValue("access_token");
                    if (!accessToken.IsNullOrWhiteSpace())
                    {
                        var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme);
                        if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null)
                        {
                            openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted);
                        }
    
                        var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest
                        {
                            Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect",
                            ClientId = openIdConnectOptions.ClientId,
                            ClientSecret = openIdConnectOptions.ClientSecret,
                            Token = accessToken
                        });
    
                        if (response.IsActive)
                        {
                            return;
                        }
                    }
    
                    principalContext.RejectPrincipal();
                    await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name);
                }
            };
    
            return options;
        }
    }
    
    
  • User Avatar
    0
    jmalla.cp created

    Hi,

    Sorry, but not working. I just sent you new logs

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you test if changing ApplicationConfigurationDtoCacheAbsoluteExpiration works?

    By the way change log level in all applications.

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
            Configure<AbpAspNetCoreMvcClientCacheOptions>(options =>
            {
                options.ApplicationConfigurationDtoCacheAbsoluteExpiration = TimeSpan.Zero;
            });
    }
    
    public class Program
    {
        public async static Task<int> Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .Enrich.FromLogContext()
                .WriteTo.Async(c => c.File("Logs/logs.txt"))
                .WriteTo.Async(c => c.Console())
                .CreateLogger();
    
    
  • User Avatar
    0
    jmalla.cp created

    Hi,

    What namespace do I need, to use AbpAspNetCoreMvcClientCacheOptions?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You are using 6.0

    Add MyMvcCachedApplicationConfigurationClient class. set AbsoluteExpirationRelativeToNow = TimeSpan.Zero

    
    using System;
    using System.Globalization;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Caching.Distributed;
    using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
    using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies;
    using Volo.Abp.AspNetCore.Mvc.Client;
    using Volo.Abp.Caching;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Threading;
    using Volo.Abp.Users;
    
    namespace MyCompanyName.MyProjectName.Web;
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(ICachedApplicationConfigurationClient), typeof(MyMvcCachedApplicationConfigurationClient))]
    public class MyMvcCachedApplicationConfigurationClient :  ICachedApplicationConfigurationClient, ITransientDependency
    {
        protected IHttpContextAccessor HttpContextAccessor { get; }
        protected AbpApplicationConfigurationClientProxy ApplicationConfigurationAppService { get; }
        protected ICurrentUser CurrentUser { get; }
        protected IDistributedCache<ApplicationConfigurationDto> Cache { get; }
    
        public MyMvcCachedApplicationConfigurationClient(
            IDistributedCache<ApplicationConfigurationDto> cache,
            AbpApplicationConfigurationClientProxy applicationConfigurationAppService,
            ICurrentUser currentUser,
            IHttpContextAccessor httpContextAccessor)
        {
            ApplicationConfigurationAppService = applicationConfigurationAppService;
            CurrentUser = currentUser;
            HttpContextAccessor = httpContextAccessor;
            Cache = cache;
        }
    
        public async Task<ApplicationConfigurationDto> GetAsync()
        {
            var cacheKey = CreateCacheKey();
            var httpContext = HttpContextAccessor?.HttpContext;
    
            if (httpContext != null && httpContext.Items[cacheKey] is ApplicationConfigurationDto configuration)
            {
                return configuration;
            }
    
            configuration = await Cache.GetOrAddAsync(
                cacheKey,
                async () => await ApplicationConfigurationAppService.GetAsync(),
                () => new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.Zero //TODO: Should be configurable.
                }
            );
    
            if (httpContext != null)
            {
                httpContext.Items[cacheKey] = configuration;
            }
    
            return configuration;
        }
    
        public ApplicationConfigurationDto Get()
        {
            var cacheKey = CreateCacheKey();
            var httpContext = HttpContextAccessor?.HttpContext;
    
            if (httpContext != null && httpContext.Items[cacheKey] is ApplicationConfigurationDto configuration)
            {
                return configuration;
            }
    
            return AsyncHelper.RunSync(GetAsync);
        }
    
        private string CreateCacheKey()
        {
            var userKey = CurrentUser.Id?.ToString("N") ?? "Anonymous";
            return $"ApplicationConfiguration_{userKey}_{CultureInfo.CurrentUICulture.Name}";
        }
    }
    
  • User Avatar
    0
    jmalla.cp created

    Hi,

    With your last recomendation I get this error.

    ArgumentOutOfRangeException: The relative expiration value must be positive. (Parameter 'AbsoluteExpirationRelativeToNow')
    Actual value was 00:00:00.
    
    Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions.set_AbsoluteExpirationRelativeToNow(Nullable<TimeSpan> value)
    
        Stack Query Cookies Headers Routing 
    
        ArgumentOutOfRangeException: The relative expiration value must be positive. (Parameter 'AbsoluteExpirationRelativeToNow') Actual value was 00:00:00.
            Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions.set_AbsoluteExpirationRelativeToNow(Nullable<TimeSpan> value)
            Cincaporc.WebApp.Web.MyMvcCachedApplicationConfigurationClient+<>c.<GetAsync>b__13_1() in MyMvcCachedApplicationConfigurationClient.cs
    
                        () => new DistributedCacheEntryOptions
    
    Volo.Abp.Caching.DistributedCache<TCacheItem, TCacheKey>.GetOrAddAsync(TCacheKey key, Func<Task<TCacheItem>> factory, Func<DistributedCacheEntryOptions> optionsFactory, Nullable<bool> hideErrors, bool considerUow, CancellationToken token)
    Cincaporc.WebApp.Web.MyMvcCachedApplicationConfigurationClient.GetAsync() in MyMvcCachedApplicationConfigurationClient.cs
    
                    configuration = await Cache.GetOrAddAsync(
    
    Volo.Abp.AspNetCore.Mvc.Client.RemoteLanguageProvider.GetLanguagesAsync()
    Microsoft.AspNetCore.RequestLocalization.DefaultAbpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync()
    Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
    Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext()
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi Sorry for that, Please ignore the cache.

     configuration = await ApplicationConfigurationAppService.GetAsync();
    
Made with ❤️ on ABP v9.1.0-preview. Updated on December 13, 2024, 06:09