NInject, NHIbernate и ISession в области запроса
Я в основном использую пример, который я видел во многих местах, но я не уверен, что он работает должным образом.
Итак, у меня есть следующее:
public class NHibernateHelper
{
private readonly string _connectionString;
private ISessionFactory _sessionFactory;
public ISessionFactory SessionFactory
{
get { return _sessionFactory ?? (_sessionFactory = CreateSessionFactory()); }
}
public NHibernateHelper(string connectionString)
{
_connectionString = connectionString;
}
private ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MySQLConfiguration.Standard
.Dialect("NHibernate.Spatial.Dialect.MySQLSpatialDialect,NHibernate.Spatial.MySQL")
.ConnectionString(_connectionString))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<EventListing>())
.ExposeConfiguration(x =>
{
x.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass, ConfigurationManager.AppSettings["current_session_context_class"]);
})
.BuildSessionFactory();
}
}
и в моем стартапе Ninject у меня есть
private static void RegisterServices(IKernel kernel)
{
NHibernateHelper helper = new NHibernateHelper(WebConfigurationManager.ConnectionStrings["eventlisting"].ConnectionString);
kernel.Bind<ISessionFactory>().ToConstant(helper.SessionFactory).InSingletonScope();
kernel.Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
kernel.Bind(typeof(IReadOnlyRepository<>)).To(typeof(ReadOnlyRepository<>)).InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
}
и мой класс поставщика сеанса выглядит
public class SessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
ISession session = DependencyResolver.Current.GetService<ISessionFactory>().OpenSession();
session.FlushMode = FlushMode.Auto;
return session;
}
}
Что меня смущает, так это то, что, несмотря на утверждение о том, что ISession должен быть создан в области запроса, он, по-видимому, выполняет метод CreateInstance несколько раз за запрос и, по-видимому, порождает несколько сеансов.
например, если у меня есть контроллер с этим конструктором:
public SomeController(
IRepository<SomeClass> someClassRepository,
IRepository<SomeOtherClass> someOtherClassRepository)
{
_someClassRepository = someClassRepository;
_someOtherRepository = someOtherClassRepository;
}
затем метод CreateInstance вызывается дважды (я должен добавить конструктор для репозиториев, принимающий параметр ISession):
public Repository(ISession session)
{
this.Session = session;
}
Я думал, что наличие InRequestScope будет означать, что он вызывается только один раз. Это мое недоразумение или я где-то пропускаю какой-то код.
1 ответ
Я сделал быструю проверку, чтобы убедиться, что базовые функциональные возможности Nincject и Provider работают правильно:
public class StringProvider : Provider<string>
{
protected override string CreateInstance(IContext context)
{
return context.ToString();
}
}
var kernel = new StandardKernel();
kernel.Bind<string>().ToProvider(new StringProvider()).InSingletonScope();
kernel.Get<string>();
kernel.Get<string>();
kernel.Get<string>();
В этом случае, StringProvider.CreateInstance(..)
это - правильно - вызывается только один раз.
Я считаю, что ваша проблема связана с правильной конфигурацией расширения ninject, которое обеспечивает .InRequestScope()
, Печальная правда в том, что когда он не настроен правильно, он не будет кричать на вас / выдавать исключение, нет, он будет молчать. Вы узнаете это только после того, как неожиданное поведение укусит вас в задницу;-)
Смотрите здесь: ASP.NET MVC + Ninject: InRequestScope. Это пример такой проблемы, на которую я ответил только вчера.