NHibernate: Configure() in every page request? - c#

I have been reading many books on NHibernate and have noticed how the Configure() is implemented. In the books that method is called every time the application is run in a console application. Most of the ASP.NET examples online call Configure() on every page request. I think this will have alot of overhead since NHibernate must be configured on every request. Does it matter if NHibernate is configured on every page request? If not, how would someone save the configuration - application wide in asp.net mvc?

NHibernate is designed to be configured once per application start. In the case of a console program, that's every time you run the program. In the case of an ASP.NET application, that's every time the application starts, firing the Application.Start event.
The SessionFactory NHibernate creates from Configure() is safe to be cached for the lifetime of the application and is thread-safe to create sessions repeatedly. There is no need to configure on every request.
In the most basic way, you can use a lazy-initialized static property to safely give you a singleton for your application to use:
public static class NHibernateSessions
{
private static readonly Lazy<SessionFactory> lazyFactory;
static NHibernateSessions
{
lazyFactory = new Lazy<SessionFactory >(
() => NHibernateSessions.CreateSessionFactory());
}
public static SessionFactory Factory
{
get
{
return NHibernateSessions.lazyFactory.Value;
}
}
public static void Initialize()
{
if(!NHibernateSessions.lazyFactory.IsValueCreated)
{
// Access the value to force initialization.
var factory = lazyFactory.Value;
}
}
private static SessionFactory CreateSessionFactory()
{
// Add code here to configure and create factory.
}
}
This code uses the Lazy<T> type, to ensure the initialization is thread-safe. You can then call NHibernateSessions.Factory to get the singleton factory with which to re-use throughout your application.
By default the factory is initialized on the first get of the Factory property. This means that for an ASP.NET application, the first request to attempt to use NHibernate will be a slow one. If this is a problem, you can force initialization when the application starts by calling the Initialize() method in an Application.Start event-handler.

Related

Managing DbContext lifetime in ASP.NET Core SignalR

I have implemented an ASP.Core SignalR Application.
A shared hub class is invoking a signal to all its client on every 10 seconds
from class SharedHub (this class is not inherited from Hub it has logic to get IHubContext to invoke)
public void Tick(){
var time = _context.table.time;
invoke('tick', time.tick);
}
Also in the same class once a new connection established a method called to update database
public void UpdateSocketConnection(int connectionId){
var connection =_context.connection;
connection.id = connectionId;
_context.saveChanges();
}
Problem with this implementation is if the connection is currently calling Tick() method and also a client connected the same time. _context throws an error saying:
_context in use.
(I'll update exact error message once I reproduce).
What I have done ?
I have implemented a factory method to get a new instance of _context on top of every method
public void Tick(){
var time = factory.GetContext().time;
invoke('tick', time.tick);
}
public void UpdateSocketConnection(int connectionId){
var context = Factory.getContext();
var connection =context.connection;
connection.id = connectionId;
context .saveChanges();
}
This actually solved the problem. But it seems not the right thing to do. I am not sure of the performance when getting a new context every time on top of every method. this seems bad practice.
I want to know what are the possible implementation for this scenario.
In the first approach DbContext is shared between operations at the same time and it cause error and unexpected result. To avoid create and dispose DbContext every time in the second approach, DbContextPooling can help performance.
A pool of reusable instances can be created. Instead of disposing an instance, it returns to the pool and resets the instance to its default state. So instead of creating a new instance every time, the code will first check if there is an instance available in the pool or not.
You can enable DbContextPooling in Configure method in startup class:
services.AddDbContextPool<YourContext>(options => options.UseSqlServer(connection));
The default pool size value is 128. Read this article for more info.

How to correctly and safely dispose of singletons instances registered in the container when an ASP.NET Core app shuts down

I am looking for guidance on how to correctly and safely dispose of registered singleton instances when my ASP.NET Core 2.0 app is shutting down.
According to the following document, if I register a singleton instance (via IServiceCollection) the container will never attempt to create an instance (nor will it dispose of the instance), thus I am left to dispose of these instances myself when the app shuts down.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.0 (2.1 has the same guidance)
I enclose some pseudo code that illustrates what I am trying to achieve.
Note I am having to maintain a reference to IServiceCollection since the IServiceProvider provided to the OnShutDown method is a simple service locator and doesn't give me the ability to execute complex queries.
When the app shuts down I want a generic way to ensure all singleton instances are disposed. I could maintain a reference to all these singleton instances directly but this doesn't scale well.
I originally used the factory method which would ensure the DI managed the lifetime of my objects, however, the execution of the factory method happened at runtime in the pipeline of handling a request, which meant that if it threw an exception the response was 500 InternalServerError and an error was logged. By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment. This doesn't seem unreasonable to me, but then at the same time I don't to misuse the DI.
Does anyone have any suggestions how I can achieve this more elegantly?
namespace MyApp
{
public class Program
{
private static readonly CancellationTokenSource cts = new CancellationTokenSource();
protected Program()
{
}
public static int Main(string[] args)
{
Console.CancelKeyPress += OnExit;
return RunHost(configuration).GetAwaiter().GetResult();
}
protected static void OnExit(object sender, ConsoleCancelEventArgs args)
{
cts.Cancel();
}
static async Task<int> RunHost()
{
await new WebHostBuilder()
.UseStartup<Startup>()
.Build()
.RunAsync(cts.Token);
}
}
public class Startup
{
public Startup()
{
}
public void ConfigureServices(IServiceCollection services)
{
// This has been massively simplified, the actual objects I construct on the commercial app I work on are
// lot more complicated to construct and span several lines of code.
services.AddSingleton<IDisposableSingletonInstance>(new DisposableSingletonInstance());
// See the OnShutdown method below
this.serviceCollection = services;
}
public void Configure(IApplicationBuilder app)
{
var applicationLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(this.OnShutdown, app.ApplicationServices);
app.UseAuthentication();
app.UseMvc();
}
private void OnShutdown(object state)
{
var serviceProvider = (IServiceProvider)state;
var disposables = this.serviceCollection
.Where(s => s.Lifetime == ServiceLifetime.Singleton &&
s.ImplementationInstance != null &&
s.ServiceType.GetInterfaces().Contains(typeof(IDisposable)))
.Select(s => s.ImplementationInstance as IDisposable).ToList();
foreach (var disposable in disposables)
{
disposable?.Dispose();
}
}
}
}
It's the DI's job to dispose of any IDisposable objects it creates, whether transient, scoped or singleton. Don't register existing singletons unless you intend to clean them up afterwards.
In the question's code there's no reason to register an instance of DisposableSingletonInstance. It should be registered with :
services.AddSingleton<IDisposableSingletonInstance,DisposableSingletonInstance>();
When the IServiceCollection gets disposed, it will call Dispose() on all the disposable entities created by it. For web applications, that happens when RunAsync() ends;
The same holds for scoped services. In this case though, the instances will be disposed when the scope exits, eg when a request ends.
ASP.NET creates a scope for each request. If you want your service to be disposed when that request ends, you should register it with :
services.AddScoped<IDisposableSingletonInstance,DisposableSingletonInstance>();
Validation
For the latest edit :
By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment.
That's a different problem. Deployment errors are often caused by bad configuration values, unresponsive databases etc.
Validating Services
A very quick & dirty way to check would be to instantiate the singleton once all startup steps are complete with :
services.GetRequiredService<IDisposableSingletonInstance>();
Validating Configuration
Validating the configuration is more involved but not that tricky. One could use Data Annotation attributes on the configuration classes for simple rules and use the Validator class to validate them.
Another option is to create an IValidateable interface with a Validate method that has to be implemented by each configuration class. This makes discovery easy using reflection.
This article shows how the IValidator interface can be used in conjunction with an IStartupFilter to validate all configuration objects when an application starts for the first time
From the article :
public class SettingValidationStartupFilter : IStartupFilter
{
readonly IEnumerable<IValidatable> _validatableObjects;
public SettingValidationStartupFilter(IEnumerable<IValidatable> validatableObjects)
{
_validatableObjects = validatableObjects;
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
foreach (var validatableObject in _validatableObjects)
{
validatableObject.Validate();
}
//don't alter the configuration
return next;
}
}
The constructor gets all instances that implement IValidatable from the DI provider and calls Validate() on them
That's not accurate. Singletons are disposed at app shutdown, though it's kind of not actually all that relevant because when the process stops, everything goes with it anyways.
The general rule of thumb is that when using DI, you should use DI all the way down, which then means you'll almost never be disposing on your own, anywhere. It's all about ownership. When you new stuff up yourself, you're also then responsible for disposing of it. However, when using DI, the container is what's newing things up, and therefore, the container and only the container should then dispose of those things.
Thanks for the responses Panagiotis Kanavos and Chris Pratt and for helping to clarify how best to deal with this scenario. The two take away points are this:
Always strive to let the container manage the life cycle of your objects so when the app is shutdown the container will automatically dispose of all objects.
Validate all your configuration on app startup before it is consumed by objects registered in the container. This allows your app to fail fast and protects your DI from throwing exceptions when creating new objects.

Application Variables in ASP.NET Core 2.0

How would I go about setting and accessing application-wide variables in ASP.NET Core 2.0?
Details:
I have a variable, let's call it CompanyName, which resides in the database and is used on literally every page. I don't want to hit the database every time I need to display the CompanyName. 100 years ago, I would have set Application["CompanyName']=CompanyName but I understand that this is not the way to do things in .NET Core. What would be the alternative?
A lot has progressed in the last 100 years. Some time ago, I believe in ASP.NET 1.0, the Application object in ASP classic was superseded with caching (although the Application object was left in for backward compatibility with ASP classic).
AspNetCore has replaced the caching mechanism of ASP.NET and made it DI-friendly, but it is still very similar to how the state of things was in ASP.NET. The main difference is that you now need to inject it instead of using the static HttpContext.Current.Cache property.
Register the cache at startup...
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
And you can inject it like...
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public IActionResult Index()
{
string companyName = _cache[CacheKeys.CompanyName] as string;
return View();
}
Then to make it work application wide, you can use a filter or middleware combined with some sort of cache refresh pattern:
Attempt to get the value from the cache
If the attempt fails
Lookup the data from the database
Repopulate the cache
Return the value
public string GetCompanyName()
{
string result;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.CompanyName, out result))
{
// Key not in cache, so get data.
result = // Lookup data from db
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromMinutes(60));
// Save data in cache.
_cache.Set(CacheKeys.CompanyName, result, cacheEntryOptions);
}
return result;
}
Of course, you could clean that up and make a service with strongly typed properties as a wrapper around your cache that is injected into controllers, but that is the general idea.
Note also there is a distributed cache in case you want to share data between web servers.
You could alternatively use a static method or a statically registered class instance, but do note if hosting on IIS that the static will go out of scope every time the application pool recycles. So, to make that work, you would need to ensure your data is re-populated using a similar refresh pattern.
The primary difference is that with caching there are timeout settings which can be used to optimize how long the data should be stored in the cache (either a hard time limit or a sliding expiration).
You could create a Singleton-class called ApplicationWideSettings. Give that class public Properties. Initialize all the values you need one time and then use them by accesing the only instance of your class via:
ApplicationWideSettings.Instance.PropertyName;
Just make sure the namespace of the ApplicationWideSettings-class is referenced when you want to access it.
I prefer this over global/static settings because you have one class to save all your globally available data.
If you are unsure what a Singleton is I can just suggest you look into this article from Jon Skeet:
C# In Depth: Implementing the Singleton Pattern in C#

NHibernate Performance and Scalability

I have a web forms site that use NHibernate to connect to a MSSQL database.
I use the following class to create the SessionFactory and get the current session to use:
internal static class SessionManager
{
static readonly Configuration Configuration = new Configuration().Configure();
internal readonly static ISessionFactory SessionFactory = Configuration.BuildSessionFactory();
internal static ISession CurrentSession { get { if (!CurrentSessionContext.HasBind(SessionFactory))CurrentSessionContext.Bind(SessionFactory.OpenSession()); return SessionFactory.GetCurrentSession(); } }
}
And that is an example of how I use the previous one:
public abstract class Repository<TEntity>
{
protected internal ISession Session { get { return SessionManager.CurrentSession; } }
public IQueryable<TEntity> AllItems { get { return Session.Query<TEntity>(); } }
}
Everything works fine, although I believe I'm doing something really bad in terms of performance and scalability, but I can't see what.
Can anyone point me out what is and/or suggest a better way to handle this?
Thanks in advance!
I think the main issue in your code is that, when you put the Session object as a static field in a static class, you will have only one session for the whole process, what can bring you problems, like "a different object with the same identifier value was already associated with the session", for example.
What you could do is create another static method to allow you to close the session, but you would have to control when to close it (in a web environment, it could be in the end of every Request), or you could use some dependency injection framework like NInject or Castle Windsor to control the lifetime of the Session object.
Take a look at this:
(Yet another) nHibernate sessionmanager for ASP.NET (MVC)
Effective NHibernate Session management for web apps

Structuremap PerRequest lifecycle

I want to inject an instance into structuremap on the fly (i.e. outside of a registry/configuration) that lives for the life of the request.
Currently I'm doing this in the HandleBeginRequest event of an IHttpModule:
container.Configure(x => x.For<IMyClass>()
.LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
.Use(new MyClass()));
However, if at some point in the application's life I do:
ObjectFactory.WhatDoIHave();
I see as many configured instances for IMyClass as there have been requests (or at least a significant amount).
Thinking about it, this sort of makes sense given the code I have.
Is there a better way to inject an instance into the container just for the life of the current request in a way that doesn't pollute the whole container?
Thanks
Your problem is that you're registering the type in the container once per request, which is building up on the registrations. Configuring the container should ideally be made once in the application's lifecycle - typically in the Application_Start event for web applications.
Structuremap allows you to specify a creational function that is invoked upon creating the object, which will let you configure advanced object creation steps.
Instead of your current call to Configure in the Begin_Request event, stick the following in the container configuration during Application_Start.
For<IMyClass>().HttpContextScoped().Use(() => new MyClass());
Notice the lambda in the Use method. The lambda can contain any logic needed in order to create the object and it will be invoked one per lifecycle (per request in the case of HttpContext lifecycle).
I went with this in the end
For<IRequestContextStorage>()
.HybridHttpOrThreadLocalScoped()
.Use<RequestContextStorage>();
For<MyClass>()
.Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());
...
public class RequestContextStorage : IRequestContextStorage
{
readonly IDictionary<Type, object> hash;
public RequestContextStorage()
{
this.hash = new Dictionary<Type, object>();
}
public T Get<T>() where T : class
{
if(this.hash.ContainsKey(typeof(T)))
return this.hash[typeof (T)] as T;
return null;
}
public void Set<T>(T instance)
{
this.hash[typeof (T)] = instance;
}
}
...
static void HandleBeginRequest(object sender, EventArgs e) {
ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());
}
If you only have one container, and you have multiple requests, you will run into this problem. I would suggest managing the per request instances yourself by storing them in HttpContext.Items.
If you want to be able to access it through the container, create a gateway class that holds no state and pulls your per request dependency out of HttpContext for you. Register that in your container, and update dependencies on the per request object to you the gateway.
Update
I can't believe I overlooked this before, what you really want is to use HttpContextLifecycle, which will cache a given instance in the HttpContext.Items collection, where it will be available throughout your request. You will still have multiple instances active during concurrent requests, but StructureMap can figure out which one to return based on HttpContext.Current.

Categories

Resources