How to get NHibernate Configuration from ISessionFactory - nhibernate

Is there any way to get Configuration details from instance of ISessionFactory in NHibernate?

the ISessionFactory doesn't expose the configuration that was used to create the session factory, and I'm not sure the concrete implementation does either.
However, why don't you consider injecting the configuration to? Maybe you are not using dependency injection, if you do, just register it into the kernel.
Otherwise, consider using a wrapper class that keeps both the configuration and the ISessionFactory.

If you are using app.config or hibernate.xml.cfg I use the following to expose configuration:
NHibernate.Cfg.Configuration normalConfig = new NHibernate.Cfg.Configuration().Configure();
I pass the above in when I configure my session factory and I just expose this configuration object in my static session factory class.

I have written an extension class that maps a session factory and configuration over a hashtable. And you can easily get a configuration for a session factory in any place of your code but you must set a configuration for a factory first.
public static class SessionFactoryConfigurationBindingExtension
{
private static readonly Dictionary<ISessionFactory, Configuration> _mappings = new Dictionary<ISessionFactory, Configuration>();
private static readonly Object _mappingsLocker = new Object();
public static Configuration GetConfiguration(this ISessionFactory sessionFactory)
{
lock (_mappingsLocker)
{
if (_mappings.ContainsKey(sessionFactory))
{
return _mappings[sessionFactory];
}
else
{
return null;
}
}
}
public static void SetConfiguration(this ISessionFactory sessionFactory, Configuration configuration)
{
lock (_mappingsLocker)
{
_mappings[sessionFactory] = configuration;
}
}
}

From Session I use the following
Session.Connection.ConnectionString;
My class is
UserIO : Base<User>
User is entity.

If you use dependency injenction:
public IServiceCollection ConfigureServices(IServiceCollection services)
{
// Add Configuration
var configuration = BuildHNibernateConfiguration(_appSettings.connectionString);
services.AddSingleton(configuration);
// Add SessionFactory
services.AddSingleton<ISessionFactory>(s => s.GetRequiredService<Configuration>().BuildSessionFactory());
// Add Session
services.AddScoped<ISession>(s => s.GetRequiredService<ISessionFactory>().WithOptions().Interceptor(new AppInterceptor(s)).OpenSession());
and then somewhere else:
var cfg = serviceProvider.GetRequiredService<Configuration>();

Related

Creating Singleton CacheManager in Asp.Net Core

I am trying to create Singleton CacheManager class that has dependency on IMemoryCache.
public class CacheManager:ICacheManager
{
private readonly IMemoryCache _cache;
public CacheManager(IMemoryCache cache)
{
_cache = cache;
}
public void LoadCache(MyData data)
{
// load cache here at startup from DB
}
}
I also have a Scoped service that retrives data from the database
public class LookupService:ILookupService
{
private readonly MyDatabaseContext _dbContext;
public class LookupService(MyDatabaseContext dbContext)
{
_dbContext = dbContext;
}
public void Dispose()
{
//Dispose DBContext here
}
// some async methods that returns lookup collection
}
Register these services in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// EF
services.AddDbContext<MyDatabaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// domain services
services.AddScoped<ILookupService, LookupService>();
services.AddMemoryCache();
// singleton
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var service = scope.ServiceProvider.GetService<ILookupService>())
{
how do i create cacheManager instance by injecting IMemoryCache and also register callback function
}
}
});
}
ILookupService is registered as Scoped service becuase it has dependency on DBContext which is also (by default) registered with Scoped lifetime. I do not want to change lifetime of these services.
However I want CacheManager to be registered as Singleton, that means I cannot inject ILookupService as dependency into CacheManager.
So here is my possible solution to create & register singleton instance of CacheManager
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var lookupService = scope.ServiceProvider.GetService<ILookupService>())
{
var cache = scope.ServiceProvider.GetService<IMemoryCache>();
var manger = new CacheManager(cache);
manger.LoadCache(lookupService.GetData());
return manger;
}
}
});
Not sure this is the best way to create CacheManager. How do I implement a callback function to re-populate CacheEntry if it becomes null?
I guess I would simply configure services.AddSingleton<CacheManager>();
(CacheManager having a default constructor)
After configuring all of the DI dependencies and having a serviceprovider, get the Cachemanager singleton and initialize it with LoadCache.
(so let DI create "empty" singleton cachemanager, but initialize immediately somewhere in startup of application)
var cachemanager = scope.ServiceProvider.Get<CacheManager>();
var lookupService = scope.ServiceProvider.Get<ILookupService>();
var cache = scope.ServiceProvider.Get<IMemoryCache>();
cachemanager.Cache = cache;
cachemanager.LoadCache(lookupService.GetData());
Looks like the underlying issue is that ILookupService cannot be resolved until runtime and requests start coming in. You need to create CacheManager before this.
DI COMPOSITION
This should be done when the app starts - as in this class of mine. Note the different lifetimes for different types of object but I just focus on creating the objects rather than interactions.
DI RESOLUTION
.Net uses a container per request pattern where scoped objects are stored against the HttpRequest object. So a singleton basically needs to ask for the current ILookupService, which is done by calling:
container.GetService<ILookupService>
So include the DI container as a constructor argument to your CacheManager class and you will be all set up. This is the service locator pattern and is needed to meet your requirement.
An alternative per request resolution mechanism is via the HttpContext object as in this class, where the following code is used:
IAuthorizer authorizer = (IAuthorizer)this.Context.RequestServices.GetService(typeof(IAuthorizer));
SUMMARY
The important thing is to understand the above design pattern, and you can then apply it to any technology.
register Cache service as singleton, try below code
public class CacheService : ICacheService
{
private ObjectCache _memoryCache;
/// <summary>
/// Initializes a new instance of the <see cref="CacheService"/> class.
/// </summary>
public CacheService()
{
this._memoryCache = System.Runtime.Caching.MemoryCache.Default;
}
}

How to write an extension method that allows you to set options without creating the options instance

I really like the pattern where I can configure a service through an option class without having to create it, but I can't find an example of how to write an extension method that allows me to use that same pattern such as the one below that exists for registering a DbContext.
services.AddDbContext<MyDbContext>(options => options.EnableDetailedErrors());
I can see the method signature uses an action method, but I can't seem to find the extension class in GitHub for ASP.NET Core that shows me how to write an extension method using that type of option builder pattern.
For example, take the following service code. How would I write the extension method so that I could configure the options during service registration.
public void ConfigureServices(IServiceCollection services)
{
services.AddMyService(options => options.SomeSetting = true);
}
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
private readonly MyServiceOptions _options;
public MyService(IOptions<MyServiceOptions> options)
{
_options = options.Value;
}
public void DoSomething()
{
Console.WriteLine(_options.SomeSetting);
}
}
public static class MyServiceExtensions
{
// How would I write this extension method so that I could configure it with options overload
public static IServiceCollection AddMyService(this IServiceCollection services, Action<MyServiceOptions> configure)
{
services.AddSingleton<IMyService, MyService>();
return services;
}
}
ASP.NET Core provides this mechanism with the IConfigureOptions
interface. You implement this interface in a configuration class and
use it to configure the IOptions object in any way you need.
It's as easy as:
public class MyServiceConfiguration : IConfigureOptions<MyServiceOptions>
{
private MyServiceOptions _options;
public MyServiceConfiguration(IOptions<MyServiceOptions> options)
{
_options = options.Value;
}
public void Configure(MyServiceOptions options)
{
options.SomeSetting = _options.SomeSetting;
options.SomeOtherSetting = _options.SomeOtherSetting;
}
}
All that remains is to register this implementation in the DI container.:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyServiceOptions>(options => options.SomeOtherSetting = true);
services.AddSingleton<IMyService, MyService>();
}
With this configuration, when IOptions is injected into your service, the MyServiceOptions object will be configured by the ConfigureMyServiceOptions class.
Be careful! The ConfigureMyServiceOptions object is registered as a singleton,
so it will capture any injected services of scoped or transient lifetimes.

Equivalent of Configure<T> using autofac modules

What is the equivalent to the method Configure<TOptions> of the OptionsConfigurationServiceCollectionExtensions when using Autofac modules?
My ConfigureServices method looks like this, but I want to move the services.Configure<MyOptions>(Configuration.GetSection("MyOptions")) to MyModule.
public IServiceProvider ConfigureServices(IServiceCollection services) {
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(services);
containerBuilder.RegisterModule<MyModule>();
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
How does the registration look like in the Load-method of the Module
protected override void Load(ContainerBuilder builder)
{
// configure options here
}
I'm not familiar with Autofac personally, but generally speaking, all Configure<T> does is 1) bind a particular configuration section to a class and 2) register that class with the service collection, so it can be injected directly.
As a result, you can instead use the following to bind your strongly-typed configuration:
var config = config.GetSection("MyOptions").Get<MyOptions>();
And, then you'd simply register that with Autofac as a constant in singleton-scope.
I recently encountered this same issue, I implemented the following so that you can still use IOptions, IOptionsMonitor and IOptionsSnapshot, but register the configuration from the AutoFac Module.
The prerequisite is that you call services.AddOptions() in ConfigureServices method:
var sfConfig = _configuration.GetSection("MyOptions");
builder.Register(ctx => new ConfigurationChangeTokenSource<MyOptions>(Options.DefaultName, sfConfig))
.As<IOptionsChangeTokenSource<MyOptions>>()
.SingleInstance();
builder.Register(ctx => new NamedConfigureFromConfigurationOptions<MyOptions>(Options.DefaultName, sfConfig, _ => { }))
.As<IConfigureOptions<MyOptions>>()
.SingleInstance();
This requires that you run services.AddOptions() within the ConfigureServices method.
In the example above, "MyOptions" is the section name in your configuration, and MyOptions type is the POCO class that has the fields to hold the result.
This is basically a conversion of what microsoft has here: https://github.com/aspnet/Options/blob/master/src/Microsoft.Extensions.Options.ConfigurationExtensions/OptionsConfigurationServiceCollectionExtensions.cs
Startup.cs
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory
// for you.
builder.RegisterModule(new AutofacModule(Configuration));
}
AutofacModule.cs
public class AutofacModule: Module
{
private IConfiguration configuration;
public AutofacModule(IConfiguration configuration)
{
this.configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
builder.Register(p => configuration.GetSection("AppAPIKey").Get<ConfigSettings>()).SingleInstance();
builder.RegisterType<TestService>()
.As<ITestService>()
.SingleInstance();
}
}

How can do I solve this? I want to inject a nhibernate session but the session is not created yet

Edit
I would like to try to do what Remo Gloor has recommended
Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
Create a binding for SessionFactory using the new provider and put it in SingletonScope
Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
Remove Application_BeginRequest, EndRequest.
Bind the repo using Bind().To();
I am looking for a tutorial that hits on these points with a file that I can download and play around with. If it uses lots of generics you needs to be pretty detailed as generics still get me.
Hi
I am trying to do session per request with my nhibernate.
I done this in my global.aspx
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Demo.WebUI.Models.NinjectModules;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Context;
using Ninject;
using Ninject.Modules;
using Ninject.Web.Mvc;
namespace Demo.WebUI
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller = "Account", action = "Login", id = UrlParameter.Optional} // Parameter defaults
);
}
public static ISessionFactory SessionFactory { get; private set; }
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
SessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
ISession session = SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
protected void Application_EndRequest(object sender, EventArgs e)
{
ISession session = CurrentSessionContext.Unbind(SessionFactory);
if (session != null)
{
try
{
session.Transaction.Commit();
}
catch (Exception)
{
session.Transaction.Rollback();
}
finally
{
session.Close();
session.Dispose();
}
}
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule(),
new RepoModule()
};
return new StandardKernel(modules);
}
private static void BuidSchema(NHibernate.Cfg.Configuration config)
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
}
}
}
In my RepoModule I have
Bind<IUserRepo>().To<UserRepo>().WithConstructorArgument("session",MvcApplication.SessionFactory.GetCurrentSession());
This will throw a error because ninject will create the kernal before OnApplicationStarted() gets started and before Application_Begin starts to bind it.
So what should I do?
Edit
This is what I found in some tutorial.
public static ISessionFactory SessionFactory { get; private set; }
public MvcApplication()
{
SessionFactory = CreateSessionFactory();
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
My binding
Bind<IUserRepo>().To<UserRepo>();
Bind<ISession>().ToMethod(x => MvcApplication.SessionFactory.GetCurrentSession());
So I first create the session factory on constructor load then I bind it to the Isession instead of passing it in as a parameter.
The only thing that I am not sure with the global aspx is if it will keep calling the constructor up everytime and recreating the SessionFactory what is bad. So I am not sure if I need to check if it exists first.
Your implementation is fine but not a good solution as you do manual control of the session lifecycle. The actual way this should be done is to let Ninject decide when the session is created, opened, closed and disposed.
E.g. imagine actions where you don't need any session. Or a larger project where you have several databases and sessions to split the load. In these situations you don't want all the possible sessions be created for each action as this means an avoidable overhead. You rather want that only those are created that are required for the current action.
To do so several changes are required:
Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
Create a binding for SessionFactory using the new provider and put it in SingletonScope
Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
Remove Application_BeginRequest, EndRequest.
Bind the repo using Bind<IUserRepo>().To<UserRepo>();
I recently blogged about using nhibernate in an asp.net mvc application with a repository pattern. This project provides an example of using nhibernate & ninject. Here are a few links:
http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/
http://blog.bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/
I think that we have a similar architecture. Take a look at the posts and let me know if you have any questions.
BTW, you can download this project at http://gpsnerd.codeplex.com
Bob
Wrap the SessionFactory initialization code in a singleton, that will initialize and configure the sessionfactory once when you access the "Instance" property on it. Use this in BeginRequest instead of current code.
You're using a current session context, you don't have to inject the session!
Inject the SessionFactory instead, then use GetCurrentSession() to obtain an ISession.
After that change, you can use Felice's solution.

nhibernate : Repository Session Management

At the moment my repository has 2 constructors. When i call these from my mvc website i am alway calling first constructor and thus opening a new session. Should i been passing in the session. How should i be doing this.
public CompanyRepository()
{
_session = NHibernateHelper.OpenSession();
}
public CompanyRepository(ISession session)
{
_session = session;
}
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(UserProfile).Assembly);
configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
System.Environment.MachineName);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
I'm using the Ninject IOC container ( very new to me ). I have the following container. How would i bind the ISession to the CompanyRepository.
private class EStoreDependencies : NinjectModule
{
public override void Load()
{
Bind<ICompanyRepository>().To<CompanyRepository>();
Bind<IUserProfileRepository>().To<UserProfileRepository>();
Bind<IAddressRepository>().To<AddressRepository>();
Bind<IRolesService>().To<AspNetRoleProviderWrapper>();
Bind<IUserService>().To<AspNetMembershipProviderWrapper>();
Bind<ICurrentUserSerivce>().To<DefaultCurrentUserSerivce>();
Bind<IPasswordService>().To<AspNetMembershipProviderWrapper>();
Bind<IStatusResponseRepository>().To<StatusResponseRepository>();
Bind<ICategoryRepository>().To<CategoryRepository>();
Bind<IProductRepository>().To<ProductRepository>();
}
}
You should be using the "one session per request" pattern, by storing the ISession object in the HttpContext and sharing it between repositories and queries made during the same HTTP request.
Here's an implementation using MVC action attributes.
An easy/basic implementation could also be achieved by simply altering your NHibernateHelper class like this:
public class NHibernateHelper {
//...
const string SessionKey = "NhibernateSessionPerRequest";
public static ISession OpenSession(){
var context = HttpContext.Current;
if(context != null && context.Items.ContainsKey(SessionKey)){
//Return already open ISession
return (ISession)context.Items[SessionKey];
}
else{
//Create new ISession and store in HttpContext
var newSession = SessionFactory.OpenSession();
if(context != null)
context.Items[SessionKey] = newSession;
return newSession;
}
}
}
Code hasn't been neither compiled nor tested... should work however.
Your code or, preferably, dependency injection should always pass the ISession into a repository's constructor. This allows multiple repositories to participate in a single transaction.
I second Paco's recommendation to let a dependency injection framework handle this for you. The challenge with this approach is with non-web applications that do not have clean unit-of-work boundaries like the HTTP request-response cycle. We have repositories that are shared by Windows Forms and ASP.NET applications and we manually manage newing up repositories in the Windows Forms applications.
Use an inversion of control container
Try using sessionFactory.GetCurrentSession() which will allow you to access a contextual session.
This will basically allow you to use the 'session per request' model as described in another answer, without having to code that yourself.
You can even choose what your context is: Http (as your example suggests) or a bunch of others too (I use CallSessionContext for my unit test).