Custom attribute private fields not being initialized when using Reflection

25 views Asked by At

I've been busting my head on this, and I'm sure it's something silly.

I've created a custom attribute:

[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : Attribute
{
    public string[] Keys { get; set; }
    private int _retention;

    public int Retention
    {
        get => _retention;
        set
        {
            if (SlidingExpiration && value == 0)
            {
                throw new ArgumentException("Retention must have a value when SlidingExpiration is true.");
            }

            _retention = value;
        }
    }

    public bool SlidingExpiration { get; set; }

    public CacheAttribute(string[] keys = null, int retention = 0, bool slidingExpiration = false)
    {
        Keys = keys;
        Retention = retention;
        SlidingExpiration = slidingExpiration;
    }
}

I'm using it like this:

[HttpPost("[action]")]
[Cache(Keys = new[] { "TableName", "d" }, SlidingExpiration = true)]
public ActionResult<string> ReadDataFromMsSqlDB([FromBody] DatabaseRequestModel requestModel, CancellationToken cancellationToken = default)
{
     List<SqlParameter> parameterList = new();
     List<SqlParamsModel> sqlParams = requestModel.Parameters ?? new List<SqlParamsModel>();

     SqlParameter[]? parameterArray = null;

     if (sqlParams.Count > 0)
     {
         foreach (var parameter in sqlParams)
         {
             parameterList.Add(new SqlParameter($"@{parameter.Key}", parameter.Value));
         }

         parameterArray = parameterList.ToArray();
     }

     // Create
     DataTable resultSet = _msSql.ExecuteQuery(requestModel.Query ?? string.Empty, parameterArray);
     string jsonResult = JsonConvert.SerializeObject(resultSet);

     return Ok(jsonResult);
}

And ExecuteQuery is:

public DataTable ExecuteQuery(string query, SqlParameter[]? parameters)
{
     StackFrame stackFrame = new StackFrame(1); // Skip one frame to get the caller's frame
     MethodBase? callingMethod = stackFrame.GetMethod();
     var cacheAttribute = callingMethod?.GetCustomAttribute<CacheAttribute>();

     // If CacheAttribute is present and caching is enabled, try to fetch data from cache
     if (cacheAttribute != null)
     {
         string cacheKey = GenerateCacheKey(query, parameters);
         var cachedItem = _cache.GetAsync<DataTable>(cacheKey);

         // If cached data is found, return it
         if (cachedItem.Exception == null)
         {
             DataTable cachedData = cachedItem.Result;
             return cachedData;
         }
     }

     // ... some more code
}

The cacheAttribute variable has the data I'm supplying in the attribute (I can see keys' value and I can see that SlidingExpiration is indeed true, but when I'm debugging the code, I can see the CacheAttribute constructor has all the variables still with their default value - meaning, it's not being instantiated correctly, and as a result, the Retention getter is not throwing an exception as expected).

What am I doing wrong?

Thanks

I tried to make the Retention getter to kick in, and fire the exception.

It didn't happen, as the cacheAttribute class is not being instantiated.

0

There are 0 answers