ASP.NET Boilerplate MVC中RecordManager类日志注入失效问题
首先得明确核心问题:你手动new RecordManager(SessionID)的方式绕开了ABP的依赖注入容器,导致Logger属性没有被ABP自动注入——你虽然给它赋值了NullLogger.Instance,但这个实现本来就不会输出任何日志,这就是为什么RecordManager里的日志没动静。而你尝试手动注册时出错,是因为sessionID是请求级别的动态值,没法在DI容器注册阶段就提供固定值。
下面是具体的解决方法,按照推荐程度排序:
方法1:通过ABP的DI容器解析RecordManager,并传递动态sessionID
ABP支持带参数的依赖解析,你可以在控制器里注入IIocResolver(或者直接用IocManager.Instance,但推荐注入),然后用它来创建RecordManager实例,这样ABP会自动注入Logger,同时你能传入当前请求的sessionID。
修改你的控制器和RecordManager代码:
public class MainController : Controller { public Castle.Core.Logging.ILogger Logger { get; set; } // 注入IIocResolver private readonly IIocResolver _iocResolver; // 构造函数注入IIocResolver public MainController(IIocResolver iocResolver) { _iocResolver = iocResolver; Logger = NullLogger.Instance; // 初始化默认值,ABP会覆盖它 } public ActionResult Index(string SessionID) { Logger.Info("MainController - inside Index"); // 用IocResolver创建RecordManager实例,传入sessionID using (var recordMgr = _iocResolver.ResolveAsDisposable<RecordManager>(new { sessionID = SessionID })) { recordMgr.Object.PushRecords(); } } } public class RecordManager { public ILogger Logger { get; set; } // ABP会自动注入这个属性 private string _sessionID = string.Empty; public RecordManager(string sessionID) { _sessionID = sessionID; Logger = NullLogger.Instance; // 初始化默认值,ABP会覆盖 Logger.Info("RecordManager - inside constructor"); } public void PushRecords() { Logger.Info("RecordManager - PushRecords - start"); } }
然后,你需要在Web模块的Initialize方法里注册RecordManager到DI容器:
public class YourWebModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); // 注册RecordManager,因为它有构造函数参数,用Transient生命周期(每个请求创建新实例) IocManager.Register<RecordManager>(DependencyLifeStyle.Transient); } }
这样做的好处是:
- ABP会自动注入Logger,不用手动处理
- 你能正确传递请求级别的sessionID
- 用
ResolveAsDisposable可以确保实例被正确释放(符合ABP的资源管理规范)
方法2:手动注入Logger属性(不推荐,但适合快速测试)
如果你不想用DI容器创建RecordManager,也可以在new之后手动让ABP注入Logger属性:
public ActionResult Index(string SessionID) { Logger.Info("MainController - inside Index"); var recordMgr = new RecordManager(SessionID); // 手动让ABP注入Logger属性 IocManager.Instance.InjectProperties(recordMgr); recordMgr.PushRecords(); }
这种方式虽然能解决日志问题,但不符合ABP的依赖注入规范,也没法利用DI的生命周期管理,只适合临时测试用。
为什么手动注册会报错?
你尝试手动注册时遇到的sessionID依赖问题,是因为DI容器注册阶段是应用启动时执行的,这时候还没有用户请求,自然没有sessionID这个动态值。DI容器只能注册类型依赖,不能注册请求级别的动态参数,所以必须在请求处理时再传递这些动态值,也就是方法1里的带参数解析方式。
内容的提问来源于stack exchange,提问作者sridhar Rishab

