如何实现类似IAbpSession的属性注入?自定义IEdwardSession遇阻
刚好对ABP的Session注入机制比较熟悉,我来给你拆解一下问题,帮你实现IEdwardSession的自动属性注入:
首先得搞清楚ABP原生IAbpSession是怎么工作的:ABP的ApplicationService基类之所以能自动拿到IAbpSession的实例,是因为ABP已经把IAbpSession的默认实现(比如ClaimsAbpSession)注册到了依赖注入容器中,并且通过属性注入的方式自动给ApplicationService的AbpSession属性赋值——完全不需要你手动实例化。
回到你的问题,要让IEdwardSession实现同样的自动注入,只需要按以下步骤来:
1. 让自定义Session接口继承IAbpSession
首先确保你的IEdwardSession继承自ABP的IAbpSession,这样可以复用ABP内置的Session核心功能,同时扩展自己的属性:
public interface IEdwardSession : IAbpSession { // 这里添加你的自定义属性/方法,比如: string UserRealName { get; } }
2. 实现自定义Session类
创建EdwardSession类,继承ABP的ClaimsAbpSession(这是ABP默认的Session实现,基于身份认证Claims),并实现IEdwardSession接口:
public class EdwardSession : ClaimsAbpSession, IEdwardSession { // 示例:从Claims中获取自定义字段 public string UserRealName => GetClaimValue("UserRealName"); // 调用父类构造函数,传入必要的依赖 public EdwardSession(IPrincipalAccessor principalAccessor, IMultiTenancyConfig multiTenancyConfig) : base(principalAccessor, multiTenancyConfig) { } }
3. 在ABP模块中注册自定义Session
打开你的模块类(比如SensingStoreCloudApplicationModule),在PreInitialize或Initialize方法中把IEdwardSession和它的实现类注册到DI容器:
public override void PreInitialize() { // 注册IEdwardSession的实现 IocManager.Register<IEdwardSession, EdwardSession>(); // 可选:如果想让默认的IAbpSession也指向你的实现,可以加这行 // IocManager.Register<IAbpSession, EdwardSession>(); }
4. 修改你的AppService基类
现在回到EdwardAppServiceBase,只需要声明EdwardSession属性即可,不要手动赋值NullEdwardSession.Instance——因为构造函数里的手动赋值会覆盖DI容器后续注入的真实实例:
public abstract class EdwardAppServiceBase : ApplicationService { public TenantManager TenantManager { get; set; } public UserManager UserManager { get; set; } protected EdwardActiveUnitOfWork EdwardActiveUnitOfWork => (EdwardActiveUnitOfWork)UnitOfWorkManager.Current; // 直接声明属性,DI会自动注入实例 protected IEdwardSession EdwardSession { get; set; } protected EdwardAppServiceBase() { LocalizationSourceName = SensingStoreCloudConsts.LocalizationSourceName; // 移除这行:EdwardSession = NullEdwardSession.Instance; } }
为什么之前的方式不行?
你之前取消注释EdwardSession = NullEdwardSession.Instance;后,始终拿到的是空实现,是因为构造函数的赋值会先执行,而ABP的属性注入是在构造函数执行之后完成的——但你手动给属性赋了值,DI容器就不会再覆盖它了。所以必须去掉这行手动赋值,让DI容器来负责给EdwardSession属性注入真实的EdwardSession实例。
另外,你之前用AbpSession as IEdwardSession能拿到实例,是因为如果你注册了IAbpSession指向EdwardSession,那么AbpSession本身就是EdwardSession的实例,强制转换自然有效。但通过属性注入IEdwardSession的方式更清晰,也更符合依赖注入的设计原则。
内容的提问来源于stack exchange,提问作者Edward

