I am using NserviceBus 2.5 and was facing the problem NSB caching the Nhibernate Sessions.
I spent sometime on internet and found that class implementing IMessageModule interface is the way to solve this. I also saw the implementation of such at https://github.com/NServiceBus/NServiceBus/blob/v2.5/src/impl/SagaPersisters/NHibernateSagaPersister/NServiceBus.SagaPersisters.NHibernate/NHibernateMessageModule.cs
MyEndPoint is defined like
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomLogging, IWantCustomInitialization
{
public void Init()
{
var location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
var windsorContainer = IoCBootstrapper.InitializeForSession(Path.Combine(location, "MyDll.config")); //This line creates Windsor container without Nhibernate Session I have not written real dll.config name but my code contains
ISessionFactory sessionFactory = MessageSessionFactory.ConfigureSessionFactory();
windsorContainer.Kernel.AddComponentInstance<ISessionFactory>(sessionFactory);
windsorContainer.Register(Component.For(typeof(NHibernateMessageModule)).LifeStyle.Singleton);
windsorContainer.Register(Component.For(typeof(MessageHandler)).LifeStyle.Transient);
NServiceBus.Configure.With(AllAssemblies.Except("XYZ.dll"))
.CastleWindsorBuilder(windsorContainer)
.XmlSerializer()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers();
SetLoggingLibrary.Log4Net(log4net.Config.XmlConfigurator.Configure);
}
}
I have defined following class to create SessionFactory
public class MessageSessionFactory
{
protected static ISessionFactory sessionFactory;
private static ILog log = LogManager.GetLogger(typeof(MessageSessionFactory));
public static ISessionFactory ConfigureSessionFactory()
{
try
{
if (sessionFactory != null) return sessionFactory;
string connectionString = System.Configuration.ConfigurationManager
.ConnectionStrings["SessionFactoryCS"].ToString();
NHibernate.Cfg.Configuration nHibernateConfiguration =
new NHibernate.Cfg.Configuration();
nHibernateConfiguration.SetProperty(
NHibernate.Cfg.Environment.ProxyFactoryFactoryClass,
typeof(NHibernate.ByteCode.Castle.ProxyFactoryFactory).AssemblyQualifiedName);
nHibernateConfiguration.SetProperty(
NHibernate.Cfg.Environment.Dialect,
typeof(NHibernate.Dialect.MsSql2005Dialect).AssemblyQualifiedName);
nHibernateConfiguration.SetProperty(
NHibernate.Cfg.Environment.ConnectionString, connectionString);
nHibernateConfiguration.SetProperty(
NHibernate.Cfg.Environment.FormatSql, "true");
nHibernateConfiguration.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass,
typeof(NHibernate.Context.ThreadStaticSessionContext).AssemblyQualifiedName);
nHibernateConfiguration.AddAssembly(Assembly.GetCallingAssembly());
sessionFactory = nHibernateConfiguration
.BuildSessionFactory();
return sessionFactory;
}
catch (TypeInitializationException ex)
{
throw new Exception("TO DO :Enter message");
}
}
}
Whenever I try to start the service I see messages like at HandleEndMessage
NHibernate.HibernateException: No current session context configured.
at NHibernate.Context.CurrentSessionContext.GetCurrentSessionContext(ISessionFactory factory)
at NHibernate.Context.CurrentSessionContext.HasBind(ISessionFactory factory)
If I catch the exception here then this error shifts to HandleError
Could you anybody tell me where I could be wrong?
that message means that you haven't configured nhibernate to tell it how to use contextual sessions. the nhibernate contextual sessions feature means that nhibernate will manage keeping track of the current session for you and you only need to worry about binding and unbinding the current session to/from the context and any time you ask the session factory for the current session within that context, you will get the same one. the message module andreas wrote makes use of this feature (and you should too in your handlers if that is how you are managing your sessions - meaning that if you have a dependency in your handler classes on ISessionFactory and get sessions from there, you should use ISessionFactory.GetCurrentSession() instead of ISessionFactory.OpenSesion()).
to fix the problem you are seeing, you need to tell NHibernate how to manage the session context. there are several built in options. the one andreas recommends in his blog post is ThreadStatic. this is fine in your case, as it seems you are only connecting to one database and using one session factory. note that this context class only supports one session factory, so it wouldn't work if you are dealing with more than one. thread static means each thread will have its own session context - you will get the same session as long as you are on the same thread. this works nicely with nservicebus as the handler will execute entirely on a thread and the message module will make sure you are getting a new session with each message and not using the same one from the previous message handled by that thread.
to configure nhibernate for this, you need to set the current_session_context_class property to thread_static. if you are configuring nhibernate directly, you know how you are doing it. if you are using fluent nhibernate, you will need to use the FluentConfiguration.ExposeConfiguration method to do this:
Fluently.Configure()
// whatever else you are doing
.ExposeConfiguration(
c => c.SetProperty("current_session_context_class", "thread_static")
);
here is andreas's post about it:
http://andreasohlund.net/2010/02/03/nhibernate-session-management-in-nservicebus/
Related
tl;dr How can I use Entity Framework in a multithreaded .NET Core API application even though DbContext is not threadsafe?
Context
I am working on a .NET Core API app exposing several RESTful interfaces that access the database and read data from it, while at the same time running several TimedHostedServices as background working threads that poll data regularly from other webservices and store them into the database.
I am aware of the fact that DbContext is not threadsafe. I read a lot of docs, blog Posts and answers here on Stackoverflow, and I could find a lot of (partly contradictory) answers for this but no real "best practice" when also working with DI.
Things I tried
Using the default ServiceLifetime.Scoped via the AddDbContext extension method results in exceptions due to race conditions.
I don't want to work with locks (e.g. Semaphore), as the obvious downsides are:
the code is polluted with locks and try/catch/finally for safely releasing the locks
it doesn't really seem 'robust', i.e. when I forget to lock a region that accesses the DbContext.
it seems redundant and 'unnatural' to artificially syncronize db access in the app when working with a database that also handles concurrent connections and access
Not injecting MyDbContext but DbContextOptions<MyDbContext> instead, building the context only when I need to access the db, using a using statement to immediatelly dispose it after the read/write seems like a lot of resource usage overhead and unnecessarily many connection opening/closings.
Question
I am really puzzled: how can this be achived?
I don't think my usecase is super special - populating the db from a Background worker and querying it from the web API layer - so there should be a meaningful way of doing this with ef core.
Thanks a lot!
You should create a scope whenever your TimedHostedServices triggers.
Inject the service provider in your constructor:
public MyServiceService(IServiceProvider services)
{
_services = services;
}
and then create a scope whenever the task triggers
using (var scope = _services.CreateScope())
{
var anotherService = scope.ServiceProvider.GetRequiredService<AnotherService>();
anotherService.Something();
}
A more complete example is available in the doc
Another approach to create own DbContextFactory and instantiate new instance for every query.
public class DbContextFactory
{
public YourDbContext Create()
{
var options = new DbContextOptionsBuilder<YourDbContext>()
.UseSqlServer(_connectionString)
.Options;
return new YourDbContext(options);
}
}
Usage
public class Service
{
private readonly DbContextFactory _dbContextFactory;
public Service(DbContextFactory dbContextFactory)
=> _dbContextFactory = dbContextFactory;
public void Execute()
{
using (var context = _dbContextFactory.Create())
{
// use context
}
}
}
With factory you don't need to worry about scopes anymore, and make your code free of ASP.NET Core dependencies.
You will be able to execute queries asynchronously, which not possible with scoped DbContext without workarounds.
You always be confident about what data saved when calling .SaveChanges(), where with scoped DbContext there are possibilities that some entity were changed in other class.
Context:
I am using DI in my Web application. (I am using NInject, but hopefully this should not matter)
Some places constructor injection is not possible, for example in my custom log4net database logger (that's not me, who instantiates my custom logger instead the log4net framework). So I am using my DI container there in service locator DP mode, and asking an instance resolve explicitly in the logger code.
Note this is just a sample, in many other cases I had to use NInject as service locator DP instead of constructor injection.
Now the problem:
I have an IAuditContextProvider which serves current request's audit data, like IP etc. The question arises how I configure my DI container to instantiate a concrete provider. So far I've used a request scope (singleton by request) what is supported out of box by NInject.
However recently I faced the fact I had to start a background processing initiated by a request. This is done by
// This is 'outside' it's actually a request serving method running in the request context, btw it is an MVC action method,
// Pseudo code:
var auditProvider = Locator.Resolve<IAuditProvider>()
Task.Run(() =>
{
// I would like to get the very same resolved auditProvider instance here as outside.
// Please note: outer local variables are not solution, because of implicit calls here inside, for example if there is a logging statement here, then the service locator in the custom logger must resolve the very same instance as outside
// Some how I must 'stamp' this thread to be the 'same' as the outside
// request thread in point of view of my custom scope resolver (see below)
}
Note: Configuring the DI container a wide scoped singleton are not solution because of multiple requests are server parallel, and they can not use a common auditProvider.
OK, I thought this is what for custom (resolving) scopes are for. Here is the pseudo code how I am configuring my DI container:
kernel
.Bind(typeof(IAuditContextProvider))
.To(typeof(WebAuditContextProvider)).InScope(dummy =>
{
// Here I have to return a very same object/number/id when in
// 'outside' the request thread, and inside the worker thread.
// This way I hopefully get the very same instance when resolving.
// To be short: I have no idea how?
});
I don't think there is a good answer for your question within the current bounds.
I do have an alternative suggestion - just perform the work synchronously in another process. This would require a form of inter-process communication (IPC) but shouldn't be too difficult.
A simple but effective form of IPC is just writing a record to a database table (acting like a queue) and having a windows service/daemon polling for new records to "process". In this example, you would put a record in the table with the contextual information (user id, etc) and the service would utilize this context to perform the work synchronously, but the workflow would be asynchronous to the Web UI.
This also has a nice side benefit: You can start to build monitoring, retry logic, etc into the service. These things are much harder to do reliably within an ASP.NET model.
You could forgo the database queue completely by using something like message queues/buses/events, but the basic concept is the same.
Update:
Did you try to use closures in C#? Like this:
var auditProvider = Locator.Resolve<IAuditProvider>()
Task.Run(() =>
{
// with closure you'll get that very variable you need:
auditProvider.SomeMethod();
}
You should read whole article about closures by John Skeet and how they can help you together with TPL.
Other useful information:
Such DI is being called as Ambient Context in famous book Dependency Injection by M. Seeman:
A truly universal CROSS-CUTTING CONCERN can potentially pollute a large part of the API for an application if you have to pass an instance around to every collaborator. An alternative is to define a context that’s available to anyone who needs it and that can be ignored by everyone else.
The AMBIENT CONTEXT is available to any consumer via a static property
or method. A consuming class might use it like this:
public string GetMessage() { return SomeContext.Current.SomeValue; }
In this case, the context has a static Current property that a consumer can access. This property may be truly static, or may be associated with the currently executing thread. To be useful in DI scenarios, the context itself must be an ABSTRACTION and it must be possible to modify the context from the outside—in the previous example, this means that the Current property must be writable. The context itself might be implemented as shown in the following listing.
The context is an abstract class, which allows us to replace one context with another implementation at runtime.
public abstract class SomeContext
{
public static SomeContext Current
{
get
{
// Get current context from TLS
var ctx = Thread.GetData(Thread.GetNamedDataSlot("SomeContext")) as SomeContext;
if (ctx == null)
{
ctx = SomeContext.Default;
Thread.SetData(Thread.GetNamedDataSlot("SomeContext"), ctx);
}
return ctx;
}
set
{
Thread.SetData(Thread.GetNamedDataSlot("SomeContext"), value);
}
}
public static SomeContext Default = new DefaultContext();
public abstract string SomeValue { get; }
}
TLS here stands for Thread Local Storage, which can be useful idea for you here.
Also I suggest you to read about OperationContext class, which can be helpful for you if you want to pass some context for your Task, something like this:
// save current context before task start
var operationContext = OperationContext.Current;
Task.Run(() =>
{
// set current operation context inside your Task with closure
OperationContext.Current = operationContext;
// Your work here
}
We are using Ninject.MVC5 and Ninject.Extention.Conventions in a multi-tenant web environment with multiple databases, one for each tenant along with a primary EF database. When a user logins in, we find them in the primary database and determine what database they should work with so we can bind all our datacontexts to that DB. (We use EF for the primary database and Linq to SQL for the tenant DB).
Here is the initial bind:
private static void RegisterServices(IKernel kernel)
string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
.ToSelf()
.InRequestScope()
.WithConstructorArgument(typeof(string), TennantConnection);
Where TennantConnection is a dummy default connection string initially
Here is the Rebind that is called after the login with the updated connection string
kernel.Rebind<TenantDB>().ToSelf().InRequestScope().WithConstructorArgument(typeof(string), ConfigConnection);
The kernel is injected into the constructor for the rebind class as follows:
public DataContextTennant(IKernel kernel)
All of the rest of the injections are done by convention.
The issue is that when we deploy the site (it happens to be an Azure Cloud app) many of the users get an error of an invalid SQL connection after first login which I believe is due to the rebind. But if they use a private browser session the rebind seems to work both for that session and subsequent sessions.
Although I was unable to resolve it with Ninject, I was able to resolve the issue with Unity. From the controller, after retrieving the tenant connection string, I call this:
public static void RegisterDBTypes(IUnityContainer container, string connection)
{
container.RegisterType<ADataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
container.RegisterType<RDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
container.RegisterType<PDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
}
This rebinds the data contexts which flows through to the various services and repositories.
I suggest that Ninject is working as expected. You should look into why the TenantDB is instanciated before login is complete and rebind is done. This should be what's causing your issues.
To do so, you should start with removing your default TenantDB binding:
string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
.ToSelf()
.InRequestScope()
.WithConstructorArgument(typeof(string), TennantConnection);
because after all, this binding only results in a TenantDB which is unusable, so why bother? It's just post-poning the issue to later - making it harder to detect.
It's much better to fail fast - have ninject throw an ActivationException! (which happens if there's no binding).
This should help you in finding out under which circumstances TenantDB is instanciated before login is complete.
Edit: Verification that IBindingRoot.Rebind works:
public class Test
{
[Fact]
public void Foo()
{
const string text1 = "Text1";
const string text2 = "Text2";
var kernel = new StandardKernel();
kernel.Bind<string>().ToConstant(text1);
kernel.Get<string>().Should().Be(text1);
kernel.Rebind<string>().ToConstant(text2);
kernel.Get<string>().Should().Be(text2);
}
}
Ninject's rebind works. I think you're making a configuration mistake and when using ninject, your building parts of your object tree - which depend on the DbContext before the Rebind is done. Thus "pre-login DbContext" leaks through to after login.
If i should be mistaken, you should create a minimal verifiable example and post it on Ninject's Issue tracker.
Im having issues configuring application using windsor, facilities and nhibernate.
Im getting this exception:
ObjectDisposedException: Session is closed
Shouldnt windsor take care of instantiating session per request and opening it when I have configuration like this? Could I miss some configuration?
Here is my confuguration:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Configuration config = BuildDatabaseConfiguration();
Kernel.Register(
Component.For<ISessionFactory>()
.LifeStyle.Singleton
.UsingFactoryMethod(config.BuildSessionFactory),
Component.For<ISession>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession()));
}
private Configuration BuildDatabaseConfiguration()
{
return Fluently.Configure()
.Database(SetupDatabase)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<RnUlice>())
.ExposeConfiguration(ConfigurePersistence)
.BuildConfiguration() ;
}
......
}
If your Repository<T> gets a ISession in its constructor and it's singleton (default lifestyle), then it will only work in the first request you call your repository. In subsequent requests the repository will still have the same ISession as in the first call (because repository is singleton), but that session is now closed and invalid to use, therefore the error you see.
This is why most of the time you don't want a singleton depending on other components with "shorter" lifestyles (like per-web-request or transient).
See this article for a more thorough analysis of common lifestyle issues.
I figured out what was wrong. I forgot to configure my repository lifestyle to Transient. I dont quite understand how this is a problem though.
container.Register(Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>)).LifeStyle.Transient);
I wonder what is the default lifestyle then? I was reading in docs that it is singleton?! How could that be a problem?
They say that to build a session factory in NHibernate is expensive and that it should only happen once. I use a singleton approach on this. This is done on the first time that a session is requested.
My question : Would there every be a time when you should close the Session factory? If so, when would one do this?
This is what i do in Java with Hibernate :
public class HibernateUtil
{
private static final SessionFactory sessionFactory;
static
{
try
{
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex)
{
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
You can free your SessionFactory when you don't need it anymore I guess, but honestly I've never closed my session factory
To AZ: This is referring to the SessionFactory, not the session. Though I wouldn't say there should only be one instance of SessionFactory. There should be one per unique configuration. For instance, if a single app is connecting to 2 different databases, then you need 2 different SessionFactory instances.
No, it dies with your program and that is fine.
There should be only one instance of sessionfactory . The code above is not an example of singleton pattern.
If you are working in an enterprise application, I would suggest use Spring with hibernate .
That would help you out in managing transactions and take away all this headache of managing session factory