ASP.NET MVC (C#) アプリケーションの一部として NInject と nHibernate を使用する継承されたアプリケーションに取り組んでいます。現在、変更の監査に関する問題を調べています。各エンティティには、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;
}
ご覧のとおり、セッション ファクトリはシングルトン スコープにあります。したがって、イベントリスナーとスタンパーもこのスコープでインスタンス化されます (私はそう思います)。これは、ユーザーがまだログインしていない場合、スタンパーのユーザー名が空の文字列または「不明」に設定されることを意味します。スタンパーを改造することで、この問題を補おうとしました。ユーザー名が null または空かどうかをチェックします。これが true の場合、アクティブなユーザーを見つけようとし、username-property にそのユーザーの名前を入力します。
private string GetUserName()
{
if (string.IsNullOrWhiteSpace(_userName))
{
var user = ServiceLocator.Resolve<User>();
if (user != null)
{
_userName = user.UserName;
}
}
return _userName;
}
ただし、これにより、アプリケーションにもログインし、データベースにログインしている、まったく異なるユーザー名が発生します。これは、トランザクションを開始したユーザーではなく、最後にログインしたユーザーである間違ったアクティブなユーザーを解決するためだと思います。