如何在非DI创建的领域对象中注入ILogger(Azure Functions v3)
给Azure Function v3领域对象注入ILogger的几种方案
好问题!在Azure Functions v3的依赖注入体系里,领域对象通常是咱们手动实例化的(不是由DI容器直接管理的),所以没法直接通过构造注入拿到ILogger。这里有几个实用的解决思路,你可以根据业务场景选:
方案1:构造函数传递(最直接推荐)
这是最符合DI设计原则的方式——在创建领域对象的时候,把已经从容器拿到的ILogger手动传进去。比如你的Function类已经能正常注入ILogger了,那就在实例化领域对象时把它传递过去:
// 你的Function类,已经通过DI注入了ILogger public class TestFunction { private readonly ILogger<TestFunction> _logger; // Function的构造注入 public TestFunction(ILogger<TestFunction> logger) { _logger = logger; } [FunctionName("TestFunction")] public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req) { // 创建领域对象时,把logger传进去 var domainObject = new YourDomainObject(_logger); await domainObject.DoBusinessLogic(); } } // 你的领域对象 public class YourDomainObject { private readonly ILogger _logger; // 接收外部传入的logger public YourDomainObject(ILogger logger) { _logger = logger; } public async Task DoBusinessLogic() { _logger.LogInformation("领域对象里的日志输出"); // 业务逻辑... } }
方案2:用工厂模式封装创建逻辑
如果你的领域对象创建逻辑复杂,或者在很多地方都要实例化,那可以封装一个工厂类,让工厂类由DI容器管理,再通过工厂来创建带logger的领域对象:
// 定义工厂接口 public interface IDomainObjectFactory { YourDomainObject Create(); } // 工厂实现类,注入ILogger public class DomainObjectFactory : IDomainObjectFactory { private readonly ILogger<YourDomainObject> _logger; public DomainObjectFactory(ILogger<YourDomainObject> logger) { _logger = logger; } public YourDomainObject Create() { return new YourDomainObject(_logger); } } // 在Startup里注册工厂 [assembly: FunctionsStartup(typeof(YourNamespace.Startup))] namespace YourNamespace { public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { builder.Services.AddScoped<IDomainObjectFactory, DomainObjectFactory>(); } } } // 在Function里使用工厂创建领域对象 public class TestFunction { private readonly IDomainObjectFactory _domainFactory; public TestFunction(IDomainObjectFactory domainFactory) { _domainFactory = domainFactory; } [FunctionName("TestFunction")] public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req) { var domainObject = _domainFactory.Create(); await domainObject.DoBusinessLogic(); } }
方案3:服务定位器(应急用,不推荐)
如果领域对象的层级很深,传递logger太麻烦,可以用服务定位器模式直接从容器获取ILogger,但这种方式会增加代码耦合度,尽量少用:
// 在Startup里注册IServiceProvider(其实容器本身已经提供了,不过可以显式注入) [assembly: FunctionsStartup(typeof(YourNamespace.Startup))] namespace YourNamespace { public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { // 注册IServiceProvider,方便后续获取 builder.Services.AddSingleton(sp => sp); } } } // 在Function里注入IServiceProvider,然后传递给领域对象 public class TestFunction { private readonly IServiceProvider _serviceProvider; public TestFunction(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } [FunctionName("TestFunction")] public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req) { var domainObject = new YourDomainObject(_serviceProvider); await domainObject.DoBusinessLogic(); } } // 领域对象里通过服务定位器获取logger public class YourDomainObject { private readonly ILogger _logger; public YourDomainObject(IServiceProvider serviceProvider) { _logger = serviceProvider.GetRequiredService<ILogger<YourDomainObject>>(); } public async Task DoBusinessLogic() { _logger.LogInformation("通过服务定位器拿到的logger输出"); } }
总结一下,优先用方案1或方案2,尽量避免方案3,这样能保持代码的可维护性和DI的设计初衷。
内容的提问来源于stack exchange,提问作者barracuda317
相关产品推荐
相关产品推荐

