I'm currently creating a system which in some cases, if the database is not available, uses a MSMQ instead. E.g. if the application (in one of the cases it's a wcf web service) starts, and the database is not available, all incoming requests should be written to the MSMQ. When the database is available again, the requests should be written to the db again.
I am using NHibernate and the session factory is wrapped by a singleton. This is what the service looks like:
try
{
// to database (just an example)
SessionProvider.Current.CurrentSession.Save...
}
catch(NHibernate.ADOException)
{
// to msmq
}
This setup works when the service is up and running for some time and the session factory has been build. When stopping the SQL server ADO exceptions are raised and things are written to the MSMQ properly.
Now my problem. If the database is not available BEFORE the service is started the first time, the session factory cannot be build and a TypeInitializationException is thrown. My singleton session provider is now broken. So when the database is running again, I somehow need a way to rebuild the session factory. Would I do that timer based? Like trying to rebuild it every 5 minutes? How can I 'reinstantiate' a singleton?
Here's an excerpt of the session provider pattern I am using:
public sealed class SessionProvider : ISessionProvider
{
private ISessionFactory sessionFactory;
private SessionProvider()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISessionFactory SessionFactory
{
get
{
return Nested.SessionProvider.sessionFactory;
}
}
public static ISessionProvider Current
{
get
{
// TypeInitializationException is thrown when building session factory fails
return Nested.SessionProvider;
}
}
private class Nested
{
internal static readonly SessionProvider SessionProvider = new SessionProvider();
}
}
I suggest you change your SessionProvider like this:
...
private ISessionFactory sessionFactory;
private Configuration config;
private SessionProvider()
{
config= new Configuration();
config.Configure();
}
public static ISessionFactory SessionFactory
{
get
{
if(sessionFactory==null)
sessionFactory=config.BuildSessionFactory();
return Nested.SessionProvider.sessionFactory;
}
}
...
Related
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;
}
}
I have got WCF service running as Windows service and I need to run a method of the WCF Service when Windows Service is starting. Is it possible in any way?
[ServiceContract]
public interface IWebMonitorServiceLibrary
{
[OperationContract]
void TestMethod();
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WebMonitorServiceLibrary : IWebMonitorServiceLibrary
{
#region properties
#endregion
#region events
#endregion
public WebMonitorServiceLibrary()
{
Initialization();
}
private void Initialization()
{
/////////
}
public void TestMethod()
{
//////////
}
}
You don't explain why you want this initialization code to run, but given you almost never want to use a single-instance WCF service, the proper way would be to use dependency injection (see How do I pass values to the constructor on my wcf service?).
Create an object in which you store the things you want to initialize, which you initialize on your Windows Service start:
public class SomeSettingsYouWantToInitialize
{
public string SomeSetting { get; set; }
}
public class WindowsServiceInstance : ServiceBase
{
protected override void OnStart(string[] args)
{
InitializeWcfService();
}
private void InitializeWcfService()
{
var settings = new SomeSettingsYouWantToInitialize
{
SomeSetting = "Foo"
};
_yourDependencyContainer.Register<SomeSettingsYouWantToInitialize>(settings);
}
}
Then (using whatever dependency injection framework you use), inject that into your service's constructor:
public class WebMonitorServiceLibrary
{
public WebMonitorServiceLibrary(SomeSettingsYouWantToInitialize settings)
{
// do stuff with settings
}
}
Generally, no. This is because by default (and following best practice) you will have configured your service to run per-call (or per session), which means there can be multiple instances of your actual service running in your service host.
Therefore, any requirement for you to be able to return an instance of the service from the service host will involve some nasty plumbing code and is not advised.
Specifically, however, there are two approaches you could use to do what you want.
The first involves running your service in InstanceContextMode.Single - this means there will be a single service instance which will handle all requests. If you do this then you can simply create the service instance and then pass it into the servicehost when you start the windows service:
var service = new MyService();
var host = new ServiceHost(service);
You then have access to the service instance and can call the operation directly.
service.MyOperation("something");
The second thing you can do for when you don't want to run a singleton service you can make your service implementation just a wrapper around a static instance of a shared class that actually process the requests. As an example:
public class MyService : IMyService
{
private static IMyService instance = new MySharedServiceClass();
public static IMyService Instance
{
get { return instance ; }
}
public bool MyOperation(string something)
{
return instance.MyOperation(something);
}
}
Then you can call the method on the class like this:
var host = new ServiceHost(typeof(MyService));
var instance = MyService.Instance;
instance.MyOperation("something");
I would still avoid doing this if at all possible. Think to yourself why do you even want this method called on startup? Surely it would be better to have this code directly in the windows service if it's something that needs to be run on startup?
at this moment we are migrating from Entityspaces(Tiraggo) into Servicestack Ormlite.
One point is the way to open and close the DBConnection.
I apologize for the comparission but it is useful for the question. In Tiraggo, inside my wep application, in the global.asax.cs I put this:
protected void Application_Start(object sender, EventArgs e)
{
Tiraggo.Interfaces.tgProviderFactory.Factory = new Tiraggo.Loader.tgDataProviderFactory();
}
In web.config exists the section for Tiraggo, the connectionstring and the ORM does the rest.
During the use of the classes we just do this:
User user = new User(); user.Name="some"; user.Comment = "some"; user.Save();
I dont open, close a DBConnection. It is transparent for the programmer. Just create the instance classes and use them.
I define a class, a repository and that's all. No DB definition or interaction. Everything happens in a webforms app, with the datalayer inside the same app.
When we are migrating to Servicestack ORMLite, I see the open of the DBConnection is too inside the globlal.asax.cs, but it references a Service no a class or repository.
public class AppHost : AppHostBase
{
public AppHost() : base("Hello ServiceStack", typeof(HelloService).Assembly) {}
public override void Configure(Container container) {}
}
So my first question is: how can I use it if I dont have a Service (HelloService), I have just classes or repositories. So I cant use this technique for DBConnection my DB.
I also see that accesing the Db, I need a open connection. I try to do this:
using (var Db = DbFactory.Conn.OpenDbConnection())
{
return Db.SingleById<Anio>(id);
}
Later, I found a sample like I was looking for, the Pluralsight video ".NET Micro ORMs" Steve Mihcelotti, and he just open the connection, but never Close it, never use the "using" syntax.
So my 2 questions are:
1) Is there a way for open the DbFactory(dbConnection) like all the samples using servicestack ormlite, but without using a Services ( I dont use Services, I want to use Ormlite but just with classes and repositories)
2) Is there a way for connnect to the database in each trip to the class or repository without using the "using" syntax, or
3) the only way is the one showed in the Pluralsight video, ie. open the connection throw the using syntax in each Method (trip to the class)
I hope I was clear.
The nice thing about IDbConnectionFactory is that it's a ThreadSafe Singleton which can be safely passed around and referenced as it doesn't hold any resources open itself (i.e. DB Connections).
A lazy pattern which provides a nice call-site API is the RepositoryBase class:
public abstract class RepositoryBase : IDisposable, IRepository
{
public virtual IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
This is the same pattern ServiceStack's Service class uses to provide a nice API that only gets opened when it's used in Services, e.g:
public class MyRepository : RepositoryBase
{
public Foo GetFooById(int id)
{
return Db.SingleById<Foo>(id);
}
}
Note: This pattern does expect that your dependencies will be disposed after use.
Another alternative is to leverage your IOC to inject an Open IDbConnection with a managed lifetime scope, e.g:
container.Register<IDbConnection>(c =>
c.Resolve<IDbConnectionFactory>().OpenDbConnection())
.ReusedWithin(ReuseScope.Request);
The life-cycle of the connection is then up to your preferred IOC.
Without Using an IOC
Whilst it's typically good practice to use an IOC to manage your Apps dependencies and provide loose-coupling, if you don't want to use an IOC you can also make DbFactory a static property, e.g:
public abstract class RepositoryBase : IDisposable
{
public static IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
Which you can just initialize directly on startup, e.g:
protected void Application_Start(object sender, EventArgs e)
{
RepositoryBase.DbFactory = new OrmLiteConnectionFactory(
connectionString, SqlServer.Provider);
}
Note: If you're not using an IOC then you want to make sure that instances of your repository classes (e.g. MyRepository) are disposed of after use.
I have a ASP.NET MVC4 web api that uses fluent NHibernate, but when I run debug it takes 1½ min to access any site that uses the database the first time I try, so I found Fluent nHibernate Slow Startup Time but I am not sure how to utilize that,
When it runs on the live server it must garbage collect the session data as it takes ages to configure again if I havent used it for a long time.
Is it possiible to cut it down to maybe sub 10 seconds instead of 1.5 minutes?
My current SessionFactory class looks like this
public class SessionFactory
{
private static readonly string ConnString = System.Configuration.ConfigurationManager.ConnectionStrings["MySQLConnectionString"].ConnectionString;
private static ISessionFactory _session;
private static readonly object SyncRoot = new Object();
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration
.Standard
.ConnectionString(ConnString))
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<UserMap>())
.ExposeConfiguration(UpdateSchema)
.BuildSessionFactory();
}
private static void UpdateSchema(Configuration cfg)
{
new SchemaUpdate(cfg).Execute(false, true);
}
public static ISession Session
{
get
{
if (_session == null)
{
lock (SyncRoot)
{
if (_session == null)
_session = CreateSessionFactory();
}
}
return _session.OpenSession();
}
}
}
Here is a screenshot of a dotTrace
Timing the request on my host it takes 1 min and 50 seconds for the initial request, and thats on "live" server (I cant control the IIS there)
I can see a host of things wrong with this code. Your CreateSessionFactory should only ever be called once in the lifetime of your application. Create a static variable in global.asax and call CreateSessionFactory once in Application_Start(). Also in global.asax, you want to setup some events for Application_BeginRequest and Application_EndRequest. This is where you are going to create and destory sessions. This is your unit of work in a web application. You should also store your session in the HttpContext.
public static ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items[sessionkey]; }
set { HttpContext.Current.Items[sessionkey] = value; }
}
protected void Application_BeginRequest()
{
CurrentSession = SessionFactory.OpenSession();
}
protected void Application_EndRequest()
{
if (CurrentSession != null)
CurrentSession.Dispose();
}
Your code recreates the SessionFactory every time you need a session.
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).