Inject service into Nhibernare Envers to customize revision entity

左心房为你撑大大i 提交于 2021-01-26 02:07:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!