Я работаю над унаследованным приложением, которое использует 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. Он проверяет, является ли имя пользователя пустым или пустым. Если это так, он пытается найти активного пользователя и заполнить свойство username именем этого пользователя:
private string GetUserName()
{
if (string.IsNullOrWhiteSpace(_userName))
{
var user = ServiceLocator.Resolve<User>();
if (user != null)
{
_userName = user.UserName;
}
}
return _userName;
}
Но это приводит к тому, что в базе данных регистрируется совершенно другое имя пользователя, которое также входит в приложение. Я думаю, это потому, что он разрешает не того активного пользователя, который является последним вошедшим пользователем, а не пользователем, который запустил транзакцию.