| Severity | Error |
| Reported by | Metalama.Patterns.Caching |
| Message | The method '<Method>' cannot be static because caching is configured to use dependency injection, and a static method cannot access an injected dependency. Make the method non-static, or disable dependency injection by setting the UseDependencyInjection property of the [Cache] or [CachingConfiguration] attribute to false. |
Cause
By default, the caching aspects get the caching service, ICachingService, through dependency injection: they introduce a field into the declaring type and pull it from the constructor. This field is an instance field, so a static method can't access it.
Metalama reports LAMA5110 in the following situations:
- The CacheAttribute aspect is applied to a static method, and dependency injection isn't disabled for this method.
- The InvalidateCacheAttribute aspect is applied to a static method, and at least one of the methods it invalidates uses dependency injection.
In both cases, <Method> is the static method. The aspect isn't applied.
When the [Cache] aspect is applied more than once to the same method, Metalama reports LAMA5112 instead.
In the following example, the static GetPrice method is cached, but dependency injection isn't disabled.
1using Metalama.Patterns.Caching.Aspects;
2
3namespace Doc.LAMA5110.Error;
4
5public class PriceCatalog
6{
7 // Error: the method is static, but caching uses dependency injection by default.
8 [Cache]
Error LAMA5110: The method 'PriceCatalog.GetPrice(string)' cannot be static because caching is configured to use dependency injection, and a static method cannot access an injected dependency. Make the method non-static, or disable dependency injection by setting the UseDependencyInjection property of the [Cache] or [CachingConfiguration] attribute to false.
9 public static decimal GetPrice( string productId ) => productId.Length * 10m;
10}
11
Resolution
Do one of the following:
- Disable dependency injection for the method by setting the UseDependencyInjection property of the [Cache] attribute to
false. The aspect then uses the CachingService.Default service. - Disable dependency injection for a whole type or project by adding the CachingConfigurationAttribute attribute with
UseDependencyInjection = falseto the type or to the assembly, or by calling ConfigureCaching in a fabric. - Make the method non-static, if the declaring type is created by your dependency injection container.
For an [InvalidateCache] method, make the method non-static, or disable dependency injection for the methods it invalidates.
In the following example, dependency injection is disabled for the GetPrice method.
1using Metalama.Patterns.Caching.Aspects;
2
3namespace Doc.LAMA5110.Fixed;
4
5public class PriceCatalog
6{
7 // Fixed: dependency injection is disabled for this method.
8 [Cache( UseDependencyInjection = false )]
9 public static decimal GetPrice( string productId ) => productId.Length * 10m;
10}
11
1using System;
2using System.Reflection;
3using Metalama.Patterns.Caching;
4using Metalama.Patterns.Caching.Aspects;
5
6namespace Doc.LAMA5110.Fixed;
7
8public class PriceCatalog
9{
10 // Fixed: dependency injection is disabled for this method.
11 [Cache(UseDependencyInjection = false)]
12 public static decimal GetPrice(string productId)
13 {
14 static object? Invoke(object? instance, object?[] args)
15 {
16 return GetPrice_Source((string)args[0]);
17 }
18
19 return ((ICachingService)CachingService.Default).GetFromCacheOrExecute<decimal>(_cacheRegistration_GetPrice, null, new object[] { productId }, Invoke);
20 }
21
22 private static decimal GetPrice_Source(string productId) => productId.Length * 10m;
23
24 private static readonly CachedMethodMetadata _cacheRegistration_GetPrice;
25
26 static PriceCatalog()
27 {
28 _cacheRegistration_GetPrice = CachedMethodMetadata.Register(typeof(PriceCatalog).GetMethod("GetPrice", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null) ?? throw new MissingMethodException("The method 'PriceCatalog.GetPrice(string)' could not be found using reflection."), new CachedMethodConfiguration() { AbsoluteExpiration = null, AutoReload = null, IgnoreThisParameter = null, Priority = null, ProfileName = (string?)null, SlidingExpiration = null }, false);
29 }
30}
31