问题
I'am using NHibernate and envers in a .net 5 web application, i need to add user id to default revision entity and find no way to use dependency injection to do it.
this is envers configuration
private static void SetupEnvers(NHibernate.Cfg.Configuration cfg)
{
var enversConf = new NHibernate.Envers.Configuration.Fluent.FluentConfiguration();
enversConf.Audit<Persona>();
IRevisionListener revListner = new EnversRevisionListener(new IUserManagement);
enversConf.SetRevisionEntity<RevisionEntity>(e => e.Id, e => e.RevisionDate, revListner);
cfg.SetEnversProperty(ConfigurationKey.AuditTableSuffix, "_LOG");
cfg.SetEnversProperty(ConfigurationKey.AuditStrategy, typeof(CustomValidityAuditStrategy));
cfg.IntegrateWithEnvers(enversConf);
}
Problem is IRevisionListener revListner = new EnversRevisionListener(new IUserManagement);
how can i inject the UserManagement?
i found this topics https://nhibernate.jira.com/browse/NHE-17 but how can i use it?
this is my custom revision entity:
public class RevisionEntity : DefaultRevisionEntity
{
public virtual string IdUtente { get; set; }
public virtual string? IdUtenteImpersonato { get; set; }
}
public class EnversRevisionListener : IRevisionListener
{
IUserManagement um = null;
public EnversRevisionListener(IUserManagement ium) : base()
{ um = ium; }
public void NewRevision(object revisionEntity)
{
var casted = revisionEntity as RevisionEntity;
if (casted != null)
{
casted.IdUtente = um.GetUtenteCorrente().Id;
casted.IdUtenteImpersonato = um.GetUtenteCorrente().UtenteImpersonato.Id;
}
}
}
this is nhibernate config
public static IServiceCollection AddNHibernate(this IServiceCollection services, bool genereteDB = false)
{
_sessionFactory = Fluently.Configure()
.Database(OracleManagedDataClientConfiguration.Oracle10
.ConnectionString(DbSettings.Current.ConnectionStrings.AbilioDB)
.DoNot.ShowSql()
.DoNot.FormatSql())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.AddFromAssemblyOf<UnitOfWork>()
)
.ExposeConfiguration(config => SetupEnvers(config))
.ExposeConfiguration(config => new SchemaUpdate(config).Execute(false, true))
.BuildSessionFactory();
services.AddSingleton(_sessionFactory);
services.AddScoped(factory => _sessionFactory.OpenSession());
services.AddScoped<IUnitOfWorkFactory, UnitOfWorkFactory>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
return services;
}
回答1:
Move the session factory creation into a delegate factory when registering it with the container. That delegate factory provides access to a service provider that can be used to resolve the desired service
The current setup code is too tightly coupled to implementation details. By using the deferred factory delegate while configuring services will allow for dependencies to be resolved easier.
This
//...
services.AddSingleton(_sessionFactory);
services.AddScoped(factory => _sessionFactory.OpenSession());
//...
needs to be changed to
public static IServiceCollection AddNHibernate(this IServiceCollection services, bool genereteDB = false) {
services.AddSingleton<ISessionFactory>(sp => Fluently.Configure()
.Database(OracleManagedDataClientConfiguration.Oracle10
.ConnectionString(DbSettings.Current.ConnectionStrings.AbilioDB)
.DoNot.ShowSql()
.DoNot.FormatSql())
.Mappings(m =>
m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.AddFromAssemblyOf<UnitOfWork>()
)
.ExposeConfiguration(config => SetupEnvers(config, sp)) //<-- NOTE THIS
.ExposeConfiguration(config => new SchemaUpdate(config).Execute(false, true))
.BuildSessionFactory()
);
services.AddScoped<ISession>(sp => sp.GetService<ISessionFactory>().OpenSession());
services.AddTransient<IRevisionListener, EnversRevisionListener>();
services.AddTransient<IUserManagement, UserManagement>();
services.AddScoped<IUnitOfWorkFactory, UnitOfWorkFactory>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
return services;
}
Where SetupEnvers
is refactored to resolve the required service
private static void SetupEnvers(NHibernate.Cfg.Configuration cfg, IServiceProvider services) {
var enversConf = new NHibernate.Envers.Configuration.Fluent.FluentConfiguration();
enversConf.Audit<Persona>();
IRevisionListener revListner = services.GetService<IRevisionListener>();
enversConf.SetRevisionEntity<RevisionEntity>(e => e.Id, e => e.RevisionDate, revListner);
cfg.SetEnversProperty(ConfigurationKey.AuditTableSuffix, "_LOG");
cfg.SetEnversProperty(ConfigurationKey.AuditStrategy, typeof(CustomValidityAuditStrategy));
cfg.IntegrateWithEnvers(enversConf);
}
来源:https://stackoverflow.com/questions/65717834/inject-service-into-nhibernare-envers-to-customize-revision-entity