Search code examples
asp.net-coredependency-injectionmicroservicesautofacextension-methods

property injection into extension class with autofac


I want to inject my class(IDateTimeService ) into extension class using property injection as you can see :

public  static  class DateTimeGetter
{

    public static  IDateTimeService Localdate { set; get; }
   
    public async  static Task<DateTime> FromService(this DateTime value)
    {
        //ocaldate = localdate;
        return await Localdate.Get();
    }
}

I have used restease to connect to another microservice using interface as you can see :

public interface IDateTimeService
{
    [AllowAnyStatusCode]
    [Get("api/LocalTime")]
    Task<DateTime> Get();
}

Finally i added the injection code into my startup file :

builder.RegisterType<IDateTimeService>();

The problem is when i run my service the Localdate property is null :

enter image description here


Solution

  • Prevent storing Volatile Dependencies into static fields, as this leads to the Ambient Context anti-pattern:

    An Ambient Context supplies application code outside the Composition Root with global access to a Volatile Dependency or its behavior by the use of static class members.

    A Volatile Dependency is:

    a Dependency that involves side effects that can be undesirable at times. This may include modules that don’t yet exist or that have adverse requirements on its runtime environment. These are the Dependencies that are addressed by DI and hidden behind Abstractions.

    Instead, there are several solutions:

    • Inject IDateTimeService using Method Injection into the static FromService method. (see example 1)
    • Promote the DateTimeGetter to an instance class and inject IDateTimeService using Constructor Injection into DateTimeGetter's constructor. (see example 2)

    Example 1:

    public static class DateTimeGetter
    {
        public async static Task<DateTime> FromService(
            this DateTime value, IDataTimeService timeProvider)
        {
            return await timeProvider.Get();
        }
    }
    

    Example 2:

    public class DateTimeGetter : IDateTimeGetter
    {
        private readonly IDataTimeService timeProvider;
    
        public DateTimeGetter(IDataTimeService timeProvider)
        {
            this.timeProvider = timeProvider ?? throw new ArgumentNullException("timeProvider");
        }
    
        public async Task<DateTime> FromService(
            DateTime value, IDataTimeService timeProvider)
        {
            return await this.timeProvider.Get();
        }
    }
    

    When using Constructor Injection, the DateTimeGetter itself will have to be injected into its consumers.