ASP MVC 5 Keep Site Alive - asp.net-mvc

Currently I have a job to check and send out emails every minute. I'm using hangfire as the job scheduler but it requires the site to be kept alive in order to function properly. To work round this I'm using another job which runs every 5 minutes as follows to keep the site alive:
public static bool Ping()
{
try
{
var request = (HttpWebRequest)WebRequest.Create('http://xyz.domain.com');
request.Timeout = 3000;
request.AllowAutoRedirect = false; // find out if this site is up and don't follow a redirector
request.Method = "HEAD";
using (request.GetResponse())
{
return true;
}
}
catch
{
return false;
}
}
Anyone know of any better or more efficient way to keep the site alive aside from using a windows service or task scheduler?

In last week for the same purpose I used an Azure Scheduler. I think it is very nice tool, you can:
schedule a job,
defince an action
get access to history of your scheduled task
etc.
So if you have an MSDN subscription I think it is worthly to consider.

As you've noticed, app pool recycling, or application inactivity will cause recurring tasks and delayed jobs to cease being enqueued, and enqueued jobs will not be processed.
If you're hosting the application 'on premise' you can use the 'Auto Start' feature that comes with Windows Server 2008 R2 (or later) - running IIS 7.5 (or above)
Full setup instructions are on the Hangfire documentation - http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html
I'll summarise below.
1)
Create a class that implements IProcessHostPreloadClient
public class ApplicationPreload : System.Web.Hosting.IProcessHostPreloadClient
{
public void Preload(string[] parameters)
{
HangfireBootstrapper.Instance.Start();
}
}
2)
Update your global.asax.cs
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
//note - we haven't yet created HangfireBootstrapper
HangfireBootstrapper.Instance.Start();
}
protected void Application_End(object sender, EventArgs e)
{
HangfireBootstrapper.Instance.Stop();
}
}
3)
Create the HangfireBootstrapper class mentioned above.
public class HangfireBootstrapper : IRegisteredObject
{
public static readonly HangfireBootstrapper Instance = new HangfireBootstrapper();
private readonly object _lockObject = new object();
private bool _started;
private BackgroundJobServer _backgroundJobServer;
private HangfireBootstrapper()
{
}
public void Start()
{
lock (_lockObject)
{
if (_started) return;
_started = true;
HostingEnvironment.RegisterObject(this);
GlobalConfiguration.Configuration
.UseSqlServerStorage("connection string");
// Specify other options here
_backgroundJobServer = new BackgroundJobServer();
}
}
public void Stop()
{
lock (_lockObject)
{
if (_backgroundJobServer != null)
{
_backgroundJobServer.Dispose();
}
HostingEnvironment.UnregisterObject(this);
}
}
void IRegisteredObject.Stop(bool immediate)
{
Stop();
}
}
4)
Enable service auto-start
After creating above classes, you should edit the global
applicationHost.config file
(%WINDIR%\System32\inetsrv\config\applicationHost.config). First, you
need to change the start mode of your application pool to
AlwaysRunning, and then enable Service AutoStart Providers.
<applicationPools>
<add name="MyAppWorkerProcess" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" />
</applicationPools>
<!-- ... -->
<sites>
<site name="MySite" id="1">
<application path="/" serviceAutoStartEnabled="true"
serviceAutoStartProvider="ApplicationPreload" />
</site>
</sites>
<!-- Just AFTER closing the `sites` element AND AFTER `webLimits` tag -->
<serviceAutoStartProviders>
<add name="ApplicationPreload" type="WebApplication1.ApplicationPreload, WebApplication1" />
</serviceAutoStartProviders>
Note that for the last entry, WebApplication1.ApplicationPreload is
the full name of a class in your application that implements
IProcessHostPreloadClient and WebApplication1 is the name of your
application’s library. You can read more about this here.
There is no need to set IdleTimeout to zero – when Application pool’s
start mode is set to AlwaysRunning, idle timeout does not working
anymore.

Related

How to temporary stop logging RequestTrackingTelemetryModule in Application Insights for ASP.NET MVC(.NET Full)

How can we stop logging specific module such as RequestTrackingTelemetryModule in ASP.NET MVC (.NET Full, not .NET Core)
I have tried to remove
<Add Type="Microsoft.ApplicationInsights.Web.RequestTrackingTelemetryModule, Microsoft.AI.Web">
in ApplicationInsights.config but it throws me a strange exception
I am using Azure Web App for both staging and live environments. So I just want to stop logging request information on live environment since it cost too much.
Thanks for helping!
You can use ITelemetryProcessor, and following this link.
Add a custom class which implements ITelemetryProcessor:
public class MyTelemetryProcessor : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
public MyTelemetryProcessor(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry telemetry)
{
RequestTelemetry request = telemetry as RequestTelemetry;
if (request != null)
{
return;
}
if (request == null)
{
this.Next.Process(telemetry);
}
}
}
Then in the ApplicationInsights.config, add this:
<TelemetryProcessors>
<Add Type="WebApplicationMVC.MyTelemetryProcessor, WebApplicationMVC">
<!-- Set public property -->
</Add>
</TelemetryProcessors>
the screenshot:
It did filter out all the requests from app insights data, test result as below:

UWP Template 10 and Service Dendency Injection (MVVM) not WPF

I have spent over two weeks searching google, bing, stack overflow, and msdn docs trying to figure out how to do a proper dependency injection for a mobile app that I am developing. To be clear, I do DI every day in web apps. I do not need a crash course on what, who, and why DI is important. I know it is, and am always embracing it.
What I need to understand is how this works in a mobile app world, and in particular a UWP Template 10 Mobile app.
From my past, in a .net/Asp app I can "RegisterType(new XYZ).Singleton() blah" {please forgive syntax; just an example} in App_Start.ConfigureServices. This works almost identical in .netcore, granted some syntactic changes.
My problem is now I am trying to provide my api is going to an UWP app that needs to digest my IXYZ service. By no means do I think that they should "new" up an instance every time. There has to be a way to inject this into a container on the UWP side; and I feel I am missing something very simple in the process.
Here is the code I have:
App.xaml.cs
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
// TODO: add your long-running task here
//if (args.Kind == ActivationKind.LockScreen)
//{
//}
RegisterServices();
await NavigationService.NavigateAsync(typeof(Views.SearchCompanyPage));
}
public static IServiceProvider Container { get; private set; }
private static void RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<IXYZ, XYZ>();
Container = services.BuildServiceProvider();
}
MainPage.xaml.cs:
public MainPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}
MainPageViewModel:
public class MainPageViewModel : ViewModelBase
{
private readonly IXYZ _xyz;
public MainPageViewModel(IXYZ xyz)
{
//Stuff
_xyz= xyz;
}
}
I now get the error:
XAML MainPage...ViewModel type cannot be constructed. In order to be constructed in XAML, a type cannot be abstract, interface nested generic or a struct, and must have a public default constructor.
I am willing to use any brand of IoC Container, but what I need is an example of how to properly use DI for services in a UWP app. 99.9% of questions about DI is about Views (i.e. Prism?) not just a simple DI for a service (i.e. DataRepo; aka API/DataService).
Again, I feel I am missing something obvious and need a nudge in the right direction. Can somebody show me an example project, basic code, or a base flogging on how I should not be a programmer...please don't do that (I don't know if my ego could take it).
You can try to Microsoft.Hosting.Extensions just like ASP.NET, there's an implementation on Xamarin.Forms by James Montemagno, as well it can be used in UWP I have tried and it works perfectly. You have to change some parts in order to get it working.
In OnLaunched Method add Startup.Init();
public static class Startup
{
public static IServiceProvider ServiceProvider { get; set; }
public static void Init()
{
StorageFolder LocalFolder = ApplicationData.Current.LocalFolder;
var configFile = ExtractResource("Sales.Client.appsettings.json", LocalFolder.Path);
var host = new HostBuilder()
.ConfigureHostConfiguration(c =>
{
// Tell the host configuration where to file the file (this is required for Xamarin apps)
c.AddCommandLine(new string[] { $"ContentRoot={LocalFolder.Path}" });
//read in the configuration file!
c.AddJsonFile(configFile);
})
.ConfigureServices((c, x) =>
{
// Configure our local services and access the host configuration
ConfigureServices(c, x);
}).
ConfigureLogging(l => l.AddConsole(o =>
{
//setup a console logger and disable colors since they don't have any colors in VS
o.DisableColors = true;
}))
.Build();
//Save our service provider so we can use it later.
ServiceProvider = host.Services;
}
static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
//ViewModels
services.AddTransient<HomeViewModel>();
services.AddTransient<MainPageViewModel>();
}
static string ExtractResource(string filename, string location)
{
var a = Assembly.GetExecutingAssembly();
using (var resFilestream = a.GetManifestResourceStream(filename))
{
if (resFilestream != null)
{
var full = Path.Combine(location, filename);
using (var stream = File.Create(full))
{
resFilestream.CopyTo(stream);
}
}
}
return Path.Combine(location, filename);
}
}
Injecting a ViewModel is possible as well which is pretty nice.
With help from #mvermef and the SO question Dependency Injection using Template 10 I found a solutions. This turned out to be a rabbit hole where at every turn I ran into an issue.
The first problem was just getting Dependency Injection to work. Once I was able to get that figured out from the sources above I was able to start injecting my services into ViewModels and setting them to the DataContext in the code behind.
Then I ran into an injection issue problem with injecting my IXYZ services into the ViewModels of UserControls.
Pages and their ViewModels worked great but I had issues with the DataContext of the UserControl not being injected with UserControl's ViewModel. They were instead getting injected by the Page's ViewModel that held it.
The final solution turned out to be making sure that the UserControl had the DataContext being set in XAML not the code behind, as we did with the Pages, and then creating a DependencyProperty in the code behind.
To show the basic solution read below.
To make it work I started with:
APP.XAML.CS
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
// long-running startup tasks go here
RegisterServices();
await Task.CompletedTask;
}
private static void RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<IRepository, Repository>();
services.AddSingleton<IBinderService, BinderServices>();
**//ViewModels**
**////User Controls**
services.AddSingleton<AddressesControlViewModel, AddressesControlViewModel>();
services.AddSingleton<CompanyControlViewModel, CompanyControlViewModel>();
**//ViewModels**
**////Pages**
services.AddSingleton<CallListPageViewModel, CallListPageViewModel>();
services.AddSingleton<CallListResultPageViewModel, CallListResultPageViewModel>();
etc....
Container = services.BuildServiceProvider();
}
public override INavigable ResolveForPage(Page page, NavigationService navigationService)
{
**//INJECT THE VIEWMODEL FOR EACH PAGE**
**//ONLY THE PAGE NOT USERCONTROL**
if (page is CallListPage)
{
return Container.GetService<CallListPageViewModel>();
}
if (page is CallListResultPage)
{
return Container.GetService<CallListResultPageViewModel>();
}
etc...
return base.ResolveForPage(page, navigationService);
}
In the code behind for the Page
CALLLISTPAGE.XAML.CS
public CallListPage()
{
InitializeComponent();
}
CallListPageViewModel _viewModel;
public CallListPageViewModel ViewModel
{
get { return _viewModel ?? (_viewModel = (CallListPageViewModel)DataContext); }
}
In your XAML add your UserControl
CALLLISTPAGE.XAML
<binder:CompanyControl Company="{x:Bind ViewModel.SelectedCompany, Mode=TwoWay}"/>
In your UserControl make sure to add the DataContext to the XAML NOT the code behind like we did with the pages.
COMPANYCONTROL.XAML
<UserControl.DataContext>
<viewModels:CompanyControlViewModel x:Name="ViewModel" />
</UserControl.DataContext>
In the UserControl Code Behind add a Dependency Property
COMPANYCONTROL.XAML.CS
public static readonly DependencyProperty CompanyProperty = DependencyProperty.Register(
"Company", typeof(Company), typeof(CompanyControl), new PropertyMetadata(default(Company), SetCompany));
public CompanyControl()
{
InitializeComponent();
}
public Company Company
{
get => (Company) GetValue(CompanyProperty);
set => SetValue(CompanyProperty, value);
}
private static void SetCompany(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as CompanyControl;
var viewModel = control?.ViewModel;
if (viewModel != null)
viewModel.Company = (Company) e.NewValue;
}
In the end I am not sure if this is an elegant solution but it works.

How to keep asp.net mvc web application alive to continously running

I created an asp.net mvc project. In this project I want some code always running. I publish my code on a web hosting service. For first time I start the application by sending an http request to my domain and I expect the application to be always kept alive and never shut down. But this does not happen.
Even I saw some solutions that say if I ping my domain sometimes in my code prevent the application from shutting down. But this solution extend application life cycle to about 24 hours (not always!!!)
Here is my code:
public class Main
{
public static void main()
{
while (true)
{
try
{
// some codes
}catch(Exception exp)
{
// log the exception message, (but any exception hasn't occurred till now
}
}
}
}
Global.asax: (by using this code, the application shutdown shortly, in this way I use a dummy controller)
public class MvcApplication : System.Web.HttpApplication
{
static Thread keepAliveThread = new Thread(KeepAlive);
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
keepAliveThread.Start();
Main.main();
}
protected void Application_End()
{
keepAliveThread.Abort();
}
static void KeepAlive()
{
while (true)
{
WebRequest req = WebRequest.Create("http://mydomain/Home/Index");
req.GetResponse();
try
{
Thread.Sleep(60000);
}
catch (ThreadAbortException)
{
break;
}
}
}
}
Global.asax: (by using this code, application stay running about 24 hours. in this way I don't use any controller)
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
Main.main();
Timer timer = new Timer(new TimerCallback(refreshSession));
timer.Change(0, 5 * 60 * 1000); // 5 min
}
static void refreshSession(object state)
{
Unirest.get("http://mydomain/");
}
}
Is there any better solution for my purpose? If yes please give me a sample code.
Normally that's called scheduled/background jobs. You can use "scheduled" for googling. Most hosting provide some means to do it form the control panel. On azure for example you could use "webjobs".
Note that there are some well-known solutions for background jobs, like hangfire for example. Don't re-invent the wheel unless you really have to.

ASP.Net MVC: How to handle session start and end by owin middle ware

this is sample code for session start and end.
public void Session_OnStart()
{
Application.Lock();
Application["UsersOnline"] = (int)Application["UsersOnline"] + 1;
Application.UnLock();
}
public void Session_OnEnd()
{
Application.Lock();
Application["UsersOnline"] = (int)Application["UsersOnline"] - 1;
Application.UnLock();
}
from MVC6 there will be no global.asax file. so how to handle session start and end by owin middle ware. if possible discuss with code example. thanks
It will be very hard to replicate what you want to do in .NET Core 1.0. The SessionStart and SessionEnd events do not exists (and there is no plan to introduce them) and you can only try to "replicate" them with some tricks.
As clearly pointed out here in this extremely clear article,
Since one of the driving forces behind ASP.NET Core 1.0 is "cloud-readiness", the focus on session management design has been to make it work in a distributed scenario. Session_End only ever fired when sessions used inproc mode (local server memory) and the team have stated that they won't add features that only work locally.
BTW, short answer on session usage:
Setup
Add the following entries to the dependencies node of your project.json file
"Microsoft.AspNet.Session": "1.0.0-rc1-final"
Modify you ConfigureServices to activate the Session:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.CookieName = ".MyApplication";
});
}
Then you can activate it like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseSession();
//removed for brevity
}
Usage
HttpContext.Session.SetString("Name, "Foo");
HttpContext.Session.SetInt32("Age", 35);
or
var name = HttpContext.Session.GetString("Name");
var age = HttpContext.Session.GetInt32("Age");

Keep an nihbernate session open forever?

I am using quartz and nhibernate and ran into a problem. Normally I have all my nhibernate sessions close on finish of a web request but I have a scheduler that starts on application start and I need to pass in a nhibernate session that I think should never be closed.
I am unsure how to do that.
Ninject
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
}
}
Global.aspx
protected void Application_Start()
{
// Hook our DI stuff when application starts
IKernel kernel = SetupDependencyInjection();
// get the reminder service HERE IS WHERE THE PROBLEMS START
IScheduledRemindersService scheduledRemindersService = kernel.Get<IScheduledRemindersService>();
scheduledRemindersService.StartTaskRemindersSchedule();
RegisterMaps.Register();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
public IKernel SetupDependencyInjection()
{
IKernel kernel = CreateKernel();
// Tell ASP.NET MVC 3 to use our Ninject DI Container
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
return kernel;
}
protected IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NhibernateModule(),
new ServiceModule(),
new RepoModule()
};
return new StandardKernel(modules);
}
// service that is causing me the problems. Ninject will bind reminderRepo and give it an nihbernate session.
private readonly IReminderRepo reminderRepo;
private readonly ISchedulerFactory schedulerFactory;
public ScheduledRemindersService(IReminderRepo reminderRepo)
{
this.reminderRepo = reminderRepo;
schedulerFactory = new StdSchedulerFactory();
}
public void StartTaskRemindersSchedule()
{
IScheduler scheduler = schedulerFactory.GetScheduler();
scheduler.Start();
JobDetail jobDetail = new JobDetail("TaskRemindersJob",null,typeof(TaskReminderJob));
jobDetail.JobDataMap["reminderRepo"] = reminderRepo;
DateTime evenMinuteDate = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow);
SimpleTrigger trigger = new SimpleTrigger("TaskRemindersTrigger", null,
DateTime.UtcNow,
null,
SimpleTrigger.RepeatIndefinitely,
TimeSpan.FromMinutes(1));
scheduler.ScheduleJob(jobDetail, trigger);
}
So I need to pass in the reminderRepo into the job as I am doing above
jobDetail.JobDataMap["reminderRepo"] = reminderRepo;
It's the only way you can pass something into a job. Everytime the schedule gets executed a job is recreated and I am assuming it uses the same reminderRepo that I sent in.
My code in the service layer never gets executed again and of course the application start as well(unless I redeploy the site)
Job
public class TaskReminderJob : IJob
{
public void Execute(JobExecutionContext context)
{
JobDataMap dataMap = context.JobDetail.JobDataMap;
ReminderRepo reminderRepo = dataMap["reminderRepo"] as ReminderRepo;
if (context.ScheduledFireTimeUtc.HasValue && context.NextFireTimeUtc.HasValue && reminderRepo != null)
{
DateTime start = context.ScheduledFireTimeUtc.Value;
DateTime end = context.NextFireTimeUtc.Value;
List<PersonalTaskReminder> personalTaskReminders = reminderRepo.GetPersonalTaskReminders(start, end);
if (personalTaskReminders.Count > 0)
{
reminderRepo.DeletePersonalTaskReminders(personalTaskReminders.Select(x => x.ReminderId).ToList());
}
}
}
Reminder Repo. (When this repo gets instantiated a session should be given that will live till the end of the request)
public class ReminderRepo : IReminderRepo
{
private readonly ISession session;
public ReminderRepo(ISession session)
{
this.session = session;
}
public List<PersonalTaskReminder> GetPersonalTaskReminders(DateTime start, DateTime end)
{
List<PersonalTaskReminder> personalTaskReminders = session.Query<PersonalTaskReminder>().Where(x => x.DateToBeSent <= start && x.DateToBeSent <= end).ToList();
return personalTaskReminders;
}
public void DeletePersonalTaskReminders(List<int> reminderId)
{
const string query = "DELETE FROM PersonalTaskReminder WHERE ReminderId IN (:reminderId)";
session.CreateQuery(query).SetParameterList("reminderId", reminderId).ExecuteUpdate();
}
public void Commit()
{
using (ITransaction transaction = session.BeginTransaction())
{
transaction.Commit();
}
}
}
So I need some way of keeping the session alive for my reminders. All my other sessions for all my other repos should be as I have it now. It's only this one that seems to need to live forever.
Edit
I tried to get a new session each time so I am passing the IsessionFactory around. Probably not 100% best but it was the only way I could figure out how to get some new sessions.
I however do not know if my session are being closed through ninject still since I am manually passing in the session now. I thinking now but cannot verify.
**private readonly ISessionFactory sessionFactory;**
private readonly ISchedulerFactory schedulerFactory;
public ScheduledRemindersService(ISessionFactory sessionFactory)
{
**this.sessionFactory = sessionFactory;**
schedulerFactory = new StdSchedulerFactory();
}
public void StartTaskRemindersSchedule()
{
IScheduler scheduler = schedulerFactory.GetScheduler();
scheduler.Start();
JobDetail jobDetail = new JobDetail("TaskRemindersJob",null,typeof(TaskReminderJob));
**jobDetail.JobDataMap["reminderRepo"] = sessionFactory;**
DateTime evenMinuteDate = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow);
SimpleTrigger trigger = new SimpleTrigger("TaskRemindersTrigger", null,
DateTime.UtcNow,
null,
SimpleTrigger.RepeatIndefinitely,
TimeSpan.FromMinutes(1));
scheduler.ScheduleJob(jobDetail, trigger);
}
So my global.aspx is the same but since ninject now sees that "ScheduledRemindersService" now takes in a nhibernate session factory it binds one for me that I can use.
I then pass it off to the job.
public void Execute(JobExecutionContext context)
{
JobDataMap dataMap = context.JobDetail.JobDataMap;
ISessionFactory sessionFactory = dataMap["reminderRepo"] as ISessionFactory;
if (sessionFactory != null)
{
ISession openSession = sessionFactory.OpenSession();
ReminderRepo reminderRepo = new ReminderRepo(openSession);
}
}
I then pass it into my ReminderRepo so I am guessing it ignores the auto session binding from ninject but I am not 100% sure thus I am not sure if my sessions are being closed.
Is there a reason the job can't just open up a new session every time it runs? Presumably it's running at periodic intervals and not forever ever.
Keeping stuff open forever is usually a sure-fire way to encounter weird behavior.
Hope this helps.
I think the approach to this is altogether wrong. The application scope of a web app is not the place to schedule events or try to persist "state" as it is still a website and the web server will not always have the app "started". This occurs after server restart and before app request, during app pool recycling and other misc cases like load balancing.
The best place to schedule something is either using a windows service or build a console app and then use windows scheduler to run it periodically. Any polling operations like that will cause major issues if you rely on application state.
I would also have serious concerns about the memory cost of letting a data context persist indefinitely even if you could count on it.
Check out building a console app - you'll find it's pretty easy even if you haven't done it before.
The other bonus is when you're sure of what you're doing, console apps can be switched to windows services with relative ease.
I've developed a similar solution recently.
I chose to use a "windows service" to manage my schedules.
Anyway, I don't understand why you do something like this:
ISessionFactory sessionFactory = dataMap["reminderRepo"] as ISessionFactory;
Since I had the same problems I've decided to (only in this situation) get a SessionFactory from StructureMap (that's what I've used) and open a new session by myself.
This is my job:
public class ReminderScheduleJob : IStatefulJob
{
private readonly ILogger _Logger;
private readonly ISessionFactory _SessionFactory;
public ReminderScheduleJob()
{
this._Logger = ObjectFactory.GetInstance<ILogger>();
this._SessionFactory = ObjectFactory.GetInstance<ISessionFactory>();
}
void IJob.Execute(JobExecutionContext context)
{
using (var session = this._SessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
...
}
}
}
}
UPDATE:
This is my nHibernate registry (see structureMap for more infos) which is called at the start-up of my app (asp.net or windows service):
public class NhibernateRegistry: Registry
{
public NhibernateRegistry()
{
For<ISessionFactory>()
.Singleton()
.Use(new BpReminders.Data.NH.NHibernateSessionFactory(myConnectionString, schemaOperation).SessionFactory);
For<IUnitOfWork>()
.HybridHttpOrThreadLocalScoped()
.Use<BpReminders.Data.NH.UnitOfWork>();
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Use(o => ((BpReminders.Data.NH.UnitOfWork)o.GetInstance<IUnitOfWork>()).CurrentSession);
}
}
I've used a unit of work but that doesn't make any difference for you.
I've defined another registry (structureMap) for Quartz.net cause I want (and that's what they say) it to be singleton:
public class QuartzRegistry : Registry
{
public QuartzRegistry()
{
var properties = new NameValueCollection();
// I set all the properties here cause I persist my jobs etc on a DB.
For<ISchedulerFactory>()
.Singleton()
.Use(new StdSchedulerFactory(properties));
For<IScheduler>()
.Singleton()
.Use(x => x.GetInstance<ISchedulerFactory>().GetScheduler());
}
}
Now, in the global.asax I would start the scheduler asking StructureMap/ninject to resolve the IScheduler:
var scheduler = StructureMap.ObjectFactory.GetInstance<IScheduler>();
scheduler.Start();
I've seen you create a new scheduler in the ScheduledRemindersService:
public ScheduledRemindersService(IReminderRepo reminderRepo)
{
this.reminderRepo = reminderRepo;
schedulerFactory = new StdSchedulerFactory();
}
Since in my example the scheduler is already created and started as singleton you can ask ninject to have the instance ... and schedule your job.
In your job (TaskReminderJob) now you can ask the ObjectFactory to resolve the ISessionFactory (see the construct of my class ReminderScheduleJob).
You can now open a new session and pass the session to your repository.
When everything is done you can dispose your session.
Hope I've been clear enough.
As I told you I've got 2 layers. My web app is responsible to schedule the jobs and I've got a custom windows service (I haven't used the one available with Quartz.net) which is responsible to fetch the triggered events and do some actions.

Resources