Skip to content

Latest commit

 

History

History
188 lines (163 loc) · 5.26 KB

File metadata and controls

188 lines (163 loc) · 5.26 KB

Consumer types

ConsumerTypes is used to get the list of consumer types of a given dependency. It contains an array of types and guarantees that it will contain at least one element. The use of ConsumerTypes is demonstrated on the example of Serilog library: Use this when one dependency must adapt behavior based on the concrete consuming type.

using Shouldly;
using Serilog.Core;
using Serilog.Events;
using Pure.DI;
using Serilog.Core;

Serilog.ILogger serilogLogger = new Serilog.LoggerConfiguration().CreateLogger();
var composition = new Composition(logger: serilogLogger);
var orderProcessing = composition.OrderProcessing;

interface IPaymentGateway;

class PaymentGateway : IPaymentGateway
{
    public PaymentGateway(Serilog.ILogger log)
    {
        log.Information("Payment gateway initialized");
    }
}

interface IOrderProcessing
{
    IPaymentGateway PaymentGateway { get; }
}

class OrderProcessing : IOrderProcessing
{
    public OrderProcessing(
        Serilog.ILogger log,
        IPaymentGateway paymentGateway)
    {
        PaymentGateway = paymentGateway;
        log.Information("Order processing initialized");
    }

    public IPaymentGateway PaymentGateway { get; }
}

partial class Composition
{
    private void Setup() =>

        DI.Setup(nameof(Composition))
            .Arg<Serilog.ILogger>("logger", "from arg")
            .Bind().To(ctx => {
                ctx.Inject<Serilog.ILogger>("from arg", out var logger);

                // Using ConsumerTypes to get the type of the consumer.
                // This allows us to create a logger with a context specific to the consuming class.
                return logger.ForContext(ctx.ConsumerTypes[0]);
            })
            .Bind().To<PaymentGateway>()
            .Bind().To<OrderProcessing>()
            .Root<IOrderProcessing>(nameof(OrderProcessing));
}
Running this code sample locally
dotnet --list-sdk
  • Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet add package Pure.DI
dotnet add package Shouldly
dotnet add package Serilog.Core
dotnet add package Serilog.Events
  • Copy the example code into the Program.cs file

You are ready to run the example 🚀

dotnet run

Limitations: consumer-aware configuration increases coupling to composition details; use it for infrastructure concerns (logging, tracing), not core domain behavior. See also: Interception, Factory.

The following partial class will be generated:

partial class Composition
{
#if NET9_0_OR_GREATER
  private readonly Lock _lock;
#else
  private readonly Object _lock;
#endif

  private readonly Serilog.ILogger _argLogger;

  [OrdinalAttribute(128)]
  public Composition(Serilog.ILogger logger)
  {
    _argLogger = logger ?? throw new ArgumentNullException(nameof(logger));
#if NET9_0_OR_GREATER
    _lock = new Lock();
#else
    _lock = new Object();
#endif
  }

  public IOrderProcessing OrderProcessing
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      Serilog.ILogger transientILogger13;
      Serilog.ILogger localLogger = _argLogger;
      // Using ConsumerTypes to get the type of the consumer.
      // This allows us to create a logger with a context specific to the consuming class.
      transientILogger13 = localLogger.ForContext(new Type[3] { typeof(PaymentGateway), typeof(OrderProcessing), typeof(Composition) }[0]);
      Serilog.ILogger transientILogger11;
      Serilog.ILogger localLogger1 = _argLogger;
      // Using ConsumerTypes to get the type of the consumer.
      // This allows us to create a logger with a context specific to the consuming class.
      transientILogger11 = localLogger1.ForContext(new Type[2] { typeof(OrderProcessing), typeof(Composition) }[0]);
      return new OrderProcessing(transientILogger11, new PaymentGateway(transientILogger13));
    }
  }
}

Class diagram:

---
 config:
  maxTextSize: 2147483647
  maxEdges: 2147483647
  class:
   hideEmptyMembersBox: true
---
classDiagram
	PaymentGateway --|> IPaymentGateway
	OrderProcessing --|> IOrderProcessing
	Composition ..> OrderProcessing : IOrderProcessing OrderProcessing
	ILogger o-- ILogger : "from arg"  Argument "logger"
	PaymentGateway *--  ILogger : ILogger
	OrderProcessing *--  ILogger : ILogger
	OrderProcessing *--  PaymentGateway : IPaymentGateway
	namespace Pure.DI.UsageTests.Advanced.ConsumerTypesScenario {
		class Composition {
		<<partial>>
		+IOrderProcessing OrderProcessing
		}
		class IOrderProcessing {
			<<interface>>
		}
		class IPaymentGateway {
			<<interface>>
		}
		class OrderProcessing {
				<<class>>
			+OrderProcessing(ILogger log, IPaymentGateway paymentGateway)
		}
		class PaymentGateway {
				<<class>>
			+PaymentGateway(ILogger log)
		}
	}
	namespace Serilog {
		class ILogger {
				<<interface>>
		}
	}
Loading