我正在开发一个继承的应用程序,它使用 NInject 和 nHibernate 作为 ASP.NET MVC (C#) 应用程序的一部分。目前,我正在研究修改审计的问题。每个实体都有 ChangedOn/ChangedBy 和 CreatedOn/CreatedBy 字段,它们映射到数据库列。但是,这些要么填写错误的用户名,要么根本没有用户名。我认为这是因为它的配置方式错误,但是我对nHibernate和NInject的了解还不够,无法解决问题,所以希望有人能提供帮助。下面是一些代码片段,希望能在应用程序中提供足够的洞察力。
创建会话工厂和会话:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider(new SessionFactoryProvider()).InSingletonScope();
Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
Bind<INHibernateUnitOfWork>().To<NHibernateUnitOfWork>().InRequestScope();
Bind<User>().ToProvider(new UserProvider()).InRequestScope();
Bind<IStamper>().ToProvider(new StamperProvider()).InRequestScope();
}
}
public class SessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
// Create session
var sessionFactory = context.Kernel.Get<ISessionFactory>();
var session = sessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
}
}
public class SessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ToString();
var stamper = context.Kernel.Get<IStamper>();
return NHibernateHelper.CreateSessionFactory(connectionString, stamper);
}
}
public class StamperProvider : Provider<IStamper>
{
protected override IStamper CreateInstance(IContext context)
{
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
System.Security.Principal.IIdentity identity = user == null ? null : user.Identity;
string name = identity == null ? "Unknown" : identity.Name;
return new Stamper(name);
}
}
public class UserProvider : Provider<User>
{
protected override UserCreateInstance(IContext context)
{
var userRepos = context.Kernel.Get<IUserRepository>();
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
System.Security.Principal.IIdentity identity = user == null ? null : user.Identity;
string name = identity == null ? "" : identity.Name;
var user = userRepos.GetByName(name);
return user;
}
}
配置会话工厂:
public static ISessionFactory CreateSessionFactory(string connectionString, IStamper stamper)
{
// Info: http://wiki.fluentnhibernate.org/Fluent_configuration
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString))
.Mappings(m =>
{
m.FluentMappings
.Conventions.Add(PrimaryKey.Name.Is(x => "Id"))
.AddFromAssemblyOf<NHibernateHelper>();
m.HbmMappings.AddFromAssemblyOf<NHibernateHelper>();
})
// Register
.ExposeConfiguration(c => {
c.EventListeners.PreInsertEventListeners =
new IPreInsertEventListener[] { new EventListener(stamper) };
c.EventListeners.PreUpdateEventListeners =
new IPreUpdateEventListener[] { new EventListener(stamper) };
})
.BuildSessionFactory();
}
来自事件监听器的片段:
public bool OnPreInsert(PreInsertEvent e)
{
_stamper.Insert(e.Entity as IStampedEntity, e.State, e.Persister);
return false;
}
如您所见,会话工厂位于单例范围内。因此 eventlistener 和 stamper 也在这个范围内被实例化(我认为)。这意味着当用户尚未登录时,压模中的用户名设置为空字符串或“未知”。我试图通过修改 Stamper 来弥补这个问题。它检查用户名是空还是空。如果这是真的,它会尝试找到活动用户,并用该用户的名称填充用户名属性:
private string GetUserName()
{
if (string.IsNullOrWhiteSpace(_userName))
{
var user = ServiceLocator.Resolve<User>();
if (user != null)
{
_userName = user.UserName;
}
}
return _userName;
}
但这会导致一个完全不同的用户名,它也登录到应用程序,登录到数据库中。我猜这是因为它解决了错误的活动用户,即最后一个登录的用户,而不是启动交易的用户。