ASP.NET MVC web application access and modify database recurrently best practice - c#

My applications users have a balance attribute that needs to be updated as long as they have services activated. So far, the update functionality uses a .net webjob that runs every hour (webjobs can run every hour at the most for shared or basic subscriptions).
Is there a better solution to implement a balance update feature? I also considered doing that on Application_Start() the following way:
public class MvcApplication : System.Web.HttpApplication
{
private ApplicationDbContext db = new ApplicationDbContext();
private PaymentsController paymentsController = new PaymentsController();
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Timer tmr = new Timer();
tmr.Interval = 60000; //1 minute
tmr.Elapsed += updateUsersBalance;
tmr.Start();
}
private void updateUsersBalance(Object source, System.Timers.ElapsedEventArgs e)
{
var users = db.Users.ToList();
foreach (var user in users)
{
user.balance -= 1;
db.Entry(user).State = EntityState.Modified;
}
db.SaveChanges(); //save updated balances
}
Is this a reliable mechanism to update the balance every minute? Is it ok to have a reference to the database and a controller in the Global.cs file?
(leave aside the precision of the timer)
In my case this scenario would be preferable to a webjob because of the limitation that I can run them every hour at the most.

No this would not be a reliable method by itself. It is possible for IIS to shut down the app pool and therefore your loop wouldn't be running. You could possible get around that by just setting up ASP.NET Auto-Start (in Azure there is an "Always On" switch in the Configuration page to enable it) but really a job runner is probably the better option (in addition to ASP.NET Auto-Start). Maybe checkout Hangfire (which is what we are currently using) or Quartz.net

#nest I did not understand exactly what is your architecture, but I think that I understand what you need.
Getting your balance updated every minute is something virtual, think about it: "Why you need to update your balance if no one read it?"
With that in mind you can assert that your balance is updated whenever someone access it. This way you save processing resources. So you don`t need to bother about run this process on every minute, you need to run every time is has changes and for redundancy you can recalculate before the access.
That said you can use a Job Scheduler to calculate the balance, I suggest Hangfire, force the Job to run every time someone change values and also schedule to run on an interval or force to run if that interval is not met on someone access.
Of course this way you`ll need to change to Web Role, mainly because Hangfire has a web interface to you admin your jobs.

Related

auto refresh cache ASP.NET [duplicate]

This question already has an answer here:
Automatically refresh ASP.NET Output Cache on expiry
(1 answer)
Closed 5 years ago.
I have a website with a lot of data in it.
I use C# .NET MVC4 for development.
I have a big slow page loading problem when the cache is empty.
currently I'm using a cache that contains all the data that I need and when the cache is on the pages loads right away, but when the cache expires it takes about 10s the page to be fully loaded.
I'm looking for an option to auto refresh the cache when it expires,
I've been searching over goolge, but couldn't find anything in that matter
How is it should be done?
Or are there other options to solve this problem?
Thanks
You could cache it on the first call with a TTL, let it invalidate, and then the next call will get it and cache it back again. The problem with this is that you are slowing down your thread while it has to go fetch the data as it is unavailable, and multiple threads will wait for it (assuming you lock the read to prevent flooding).
One way to get around the first load issue is to prime your cache on application start up. This assures that when your application is ready to be used, the data is already loaded up and will be fast. Create a quick interface like ICachePrimer { void Prime() }, scan your assemblies for it, resolve them, then run them.
The way I like to get around the empty cache on invalidation issue is to refresh the data before it is removed. To easily do this in .Net, you can utilize the MemoryCache's CacheItemPolicy callbacks.
UpdateCallback occurs before the item is removed, and allows you to refresh the item.
RemovedCallback occurs after the item has been removed.
In the example below, my CachedRepository will refresh the cached item when it is invalidated. Other threads will continue to receive the "old" value until the refresh completes.
public class MyCachedRepository : IMyRepository
{
private readonly IMyRepository _baseRepository;
private readonly ObjectCache _cache;
public MyCachedRepository(IMyRepository baseRepository, ObjectCache cache)
{
_baseRepository = baseRepository;
_cache = cache;
}
public string GetById(string id)
{
var value = _cache.Get(id) as string;
if (value == null)
{
value = _baseRepository.GetById(id);
if (value != null)
_cache.Set(id, value, GetPolicy());
}
return value;
}
private CacheItemPolicy GetPolicy()
{
return new CacheItemPolicy
{
UpdateCallback = CacheItemRemoved,
SlidingExpiration = TimeSpan.FromMinutes(0.1), //set your refresh interval
};
}
private void CacheItemRemoved(CacheEntryUpdateArguments args)
{
if (args.RemovedReason == CacheEntryRemovedReason.Expired || args.RemovedReason == CacheEntryRemovedReason.Removed)
{
var id = args.Key;
var updatedEntity = _baseRepository.GetById(id);
args.UpdatedCacheItem = new CacheItem(id, updatedEntity);
args.UpdatedCacheItemPolicy = GetPolicy();
}
}
}
Source: http://pdalinis.blogspot.in/2013/06/auto-refresh-caching-for-net-using.html
There is no mechanism to auto refresh a cache when the keys expire. All caching systems employ passive expiration. The keys are invalidated the first time they are requested after the expiration, not automatically at that exact expiration time.
What you're talking about is essentially a cache that never expires, which is easy enough to achieve. Simply either pass no expiration (if the caching mechanism allows it) or a far-future expiration. Then, your only problem is refreshing the cache on some schedule, so that it does not become stale. For that, one option is to create a console application that sets the values in the cache (importantly, without caring if there's something there already) and then use Task Scheduler or similar to schedule it to run at set intervals. Another option is to use something like Revalee to schedule callbacks into your web application at defined intervals. This basically the same as creating a console app, only the code could be integrated into your same website project.
You can also use Hangfire to perform the scheduling directly within your web application, and could use that to run a console application, hit a URL, whatever. The power of Hangfire is that it allow you pretty much schedule any process you want, but that also means you have to actually provide the code for what should happen, i.e. actually connect with HttpClient and fetch the URL, rather than just telling Revallee to hit a particular URL.

Background process to update DB every few seconds with JSON data

I am a complete novice with this but...
I have a small ASP MVC C# application reading an SQL database which I would like to be updated by a background process updating the DB with a JSON request potentially up to every minute or few seconds.
What is the best way to implement the background JSON DB update? In the MVC app on a persistent timer (is that even possible?) or independently (completely outside of the app) in a separate process with an executable running in the background with an internal programmatic timer or else using some kind of scheduler?
EDIT: For the sake of understanding - it is market prices in the JSON string that obviously need to be updated in the DB quite often ie potentially up to every few seconds if desirable or nessesary
I would use a Windows Service combined with the Quartz.net package.
You can run anything you want and on any schedule.
EDIT: From the above discussion I gather that your job would poll for market prices (a web request) that would run every few seconds and on getting the result would update your database.
EDIT2:
This would be your Quartz job:
public class FetchAndSaveFinancialData : IJob
{
public void Execute()
{
//web request to get info
//save to db
}
}
Then your windows service base class:
public class YourFinancialServiceBase : ServiceBase
{
protected override void OnStart(string[] args)
{
ServiceMain();
base.OnStart(args);
}
protected override void OnStop()
{
base.OnStop();
}
protected void ServiceMain()
{
var scheduler = StdSchedulerFactory.GetDefaultScheduler();
var job = JobBuilder.Create<FetchAndSaveFinancialData>().WithIdentity("Job1", "Group1").Build();
ITrigger trigger = TriggerBuilder.Create().WithIdentity("Trigger1","Group1")
.StartNow()
.WithSimpleSchedule(x=>x
.WithIntervalInSeconds(5)
.RepeatForever()
).Build();
scheduler.ScheduleJob(job,trigger);
scheduler.Start();
}
}
EDIT3:
It all depends on what you use to access the data. If you plan on using EntityFramework then I would keep the MVC project and the WindowsService project in the same solution referencing a Library project. The library project would have all your models and allow you to see if changing something effects one or both components.
On the other hand if you rely a lot on stored procedures in your database the above is less relevant. You will have to consolidate any changes in your stored procedures more than in code.
In my experience, I'd rather have to sift through many projects in one solution than trying to find a completely different solution in a different language that is a critical part of your application.

System.Threading.Timer callback not being hit

I have a windows service which, among other things, needs to do some database maintenance every 24 hours. (SQL express, so can't schedule it inside the database)
For this I have created a Timer with a callback to the database maintenance method, but it appears to only get hit once (upon creation of the timer, I assume).
I assumed this was due to the timer itself getting out of scope and being GC'd, but none of the sollutions I've tried seem to be working
The basic layout of the service is like this:
WindowsService.cs:
protected override void OnStart(string[] args)
{
ThreadPool.QueueUserWorkItem(StartServices);
}
private void StartServices() { Manager.Start(); }
Manager.cs:
public class Manager
{
private static Timer MaintenanceTimer;
public static void Start()
{
MaintenanceTimer = new Timer(DoMaintenance);
MaintenanceTimer.Change(new TimeSpan(0), new TimeSpan(24,0,0,0)); //I use 1 minute for testing
}
}
Obviously this code is severely simplified, but this is pretty much what happens.
As stated before, I believe GC is the problem, which made me try the following 2 things:
Use the constructor Timer(callback), so it will provide a
self-reference to the callback. However, this would still not prevent
it from running out of scope, so that's a no go.
Define the timer as
a static variable inside the Manager class. This should prevent it
from ever being GC'd, but still doesn't appear to have it be called
every 24 hours.
Any help in this matter would be greatly appreciated
In the end I used a regular System.Timers.Timer which solved my problems.
Still not sure where I went wrong with the System.Threading.Timer, though.
Since you cannot use the SQL Server agent in SQL Server Express, the best solution is to create a SQL Script, and then run it as a scheduled task.
It i easy to verify and mantain, you could have multiple scheduled tasks to fit in with your backup schedule/retention.
The command I use in the scheduled task is:
C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE" -i"c:\path\to\sqlbackupScript.sql

How do i know if my windows service is working?

I have built a windows service to populate a database with my email inbox every 5 minutes.
I used a class inside my windows service the class gets my emails and writes them to my database, the class has been tested and works.
All i need the windows service to do is use a timer and call the class every 5 minutes, but i have no idea whats going on as i cant even test my windows service.
Please someone tel me what to do to test, if there is a way to test, or just blink luck and pray it works lol.
Also do u have to uninstall and re-install every time you want to test the service or is there an update service option? Please answer this i'm really interested even tho its not my main question.
This is my windows service, if u can point out any errors that would be amazing since i cant test for them. I think my timer might be wrong if some one could look at it?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace EmailWindowsService
{
public partial class MyEmailService : ServiceBase
{
private Timer scheduleTimer1 = null;
private DateTime lastRun;
private bool flag;
public MyEmailService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLogEmail.Source = "MySource";
eventLogEmail.Log = "MyNewLog";
scheduleTimer1 = new Timer();
scheduleTimer1.Interval = 5 * 60 * 1000;
scheduleTimer1.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);
}
protected override void OnStart(string[] args)
{
flag = true;
lastRun = DateTime.Now;
scheduleTimer.Start();
eventLogEmail.WriteEntry("Started");
}
protected override void OnStop()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("Stopped");
}
protected override void OnPause()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("Paused");
}
protected override void OnContinue()
{
scheduleTimer.Start(); ;
eventLogEmail.WriteEntry("Continuing");
}
protected override void OnShutdown()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("ShutDowned");
}
protected void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
RetriveEmailClass Emails = new RetriveEmailClass();
if (flag == true)
{
eventLogEmail.WriteEntry("In getting Email Method");
Emails.ServiceEmailMethod();
lastRun = DateTime.Now;
flag = false;
}
else if (flag == false)
{
if (lastRun.Date < DateTime.Now.Date)
{
Emails.ServiceEmailMethod();
eventLogEmail.WriteEntry("In getting Email Method");
}
}
}
}
}
Surely you can test it. All you need is
start up the service
observe that it triggers the expected call after 5 minutes
(observe that it triggers the expected call every 5 minutes for a couple more times)
You can test this manually, or (preferably) create/use an automated test harness which allows you to test repeatedly and reliably, as many times as you want. This is possible even using a simple batch file.
To detect that the timer works correctly, you can inspect its log file. It also helps of course if you make the called class method configurable instead of hardcoding it. So you can run your automated tests using a dummy worker class which does not flood your inbox :-)
To make it even more testable, you can extract the timing logic from your service class too, so that it becomes runnable from a regular application. Then you can test it even easier, even using a unit test framework such as NUnit. This allows you to do more thorough testing, using different timing intervals etc. And the service class itself becomes an almost empty shell whose only job is to launch and call the other classes. If you have verified that all the classes containing real program logic (i.e. all the code which can fail) is unit tested and works fine, you can have much greater confidence in that your whole app, when integrated from its smaller parts, works correctly too.
Update
Looking through your code, it seems that you don't initialize flag anywhere, so its default value will be false. You should initialize it to true in the constructor, otherwise your email retriever won't ever get called even if the timer fires properly.
To set the interval to 1 minute, my first guess would be
scheduleTimer1.Interval = 1 * 60 * 1000;
James Michael Hare has on his blog written about a really nice template/framework he has made, making it lot easier to develop (and debug) Windows Services: C# Toolbox: A Debuggable, Self-Installing Windows Service Template (1 of 2)
It provides you with all the basics you need to quickly get started. And best of all, it give you a really nice way to debug your service as if it was a regular console application. I could also mention that it provides out of the box functionality to install (and uninstall) your service. Part two of the post can be found at this link.
I've used this myself a couple of times, and can really recommend it.
Refactor you logic in another class.
Write a simple console application invoking this class
Test it like a normal application.
Once it runs standalone, it should run as a service.
Beware on permissions and service registration, there are a couple of issues there (like having a sys user, or a desktop session).
A good practice is to use system logs (e.g. the ones you can inspect with eventvwr)
1.add this line to the place you want to break, then you can debug your service.
System.Diagnostics.Debugger.Break();
or
2.try to attach to your service progress from process explorer, then you can also debug your service.
or
3.use a log file to log what your service is doing.
You can attach a debugger to you running service instance from Visual Studio. Click "Debug" in the main menu, "Attach to Process...", select your service process from the list and click "Attach".
If you need to debug the startup of your service, you need to use System.Diagnostics.Debugger.Break().

HttpModule Init method is called several times - why?

I was creating a http module and while debugging I noticed something which at first (at least) seemed like weird behaviour.
When I set a breakpoint in the init method of the httpmodule I can see that the http module init method is being called several times even though I have only started up the website for debugging and made one single request (sometimes it is hit only 1 time, other times as many as 10 times).
I know that I should expect several instances of the HttpApplication to be running and for each the http modules will be created, but when I request a single page it should be handled by a single http application object and therefore only fire the events associated once, but still it fires the events several times for each request which makes no sense - other than it must have been added several times within that httpApplication - which means it is the same httpmodule init method which is being called every time and not a new http application being created each time it hits my break point (see my code example at the bottom etc.).
What could be going wrong here? Is it because I am debugging and set a breakpoint in the http module?
It have noticed that it seems that if I startup the website for debugging and quickly step over the breakpoint in the httpmodule it will only hit the init method once and the same goes for the eventhandler. If I instead let it hang at the breakpoint for a few seconds the init method is being called several times (seems like it depends on how long time I wait before stepping over the breakpoint). Maybe this could be some build in feature to make sure that the httpmodule is initialized and the http application can serve requests , but it also seems like something that could have catastrophic consequences.
This could seem logical, as it might be trying to finish the request and since I have set the break point it thinks something have gone wrong and try to call the init method again? Soo it can handle the request?
But is this what is happening and is everything fine (I am just guessing), or is it a real problem?
What I am specially concerned about is that if something makes it hang on the "production/live" server for a few seconds a lot of event handlers are added through the init and therefore each request to the page suddenly fires the eventhandler several times.
This behaviour could quickly bring any site down.
I have looked at the "original" .net code used for the httpmodules for formsauthentication and the rolemanagermodule, etc... But my code isn't any different that those modules uses.
My code looks like this.
public void Init(HttpApplication app)
{
if (CommunityAuthenticationIntegration.IsEnabled)
{
FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];
formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate);
}
}
Here is an example how it is done in the RoleManagerModule from the .NET framework:
public void Init(HttpApplication app)
{
if (Roles.Enabled)
{
app.PostAuthenticateRequest += new EventHandler(this.OnEnter);
app.EndRequest += new EventHandler(this.OnLeave);
}
}
Does anyone know what is going on?
(I just hope someone out there can tell me why this is happening and assure me that everything is perfectly fine) :)
UPDATE:
I have tried to narrow down the problem and so far I have found that the init method being called is always on a new object of my http module (contrary to what I thought before).
I seems that for the first request (when starting up the site) all of the HttpApplication objects being created and their modules are all trying to serve the first request and therefore all hit the eventhandler that is being added.
I can't really figure out why this is happening.
If I request another page all the HttpApplication's created (and their modules) will again try to serve the request causing it to hit the eventhandler multiple times.
But it also seems that if I then jump back to the first page (or another one) only one HttpApplication will start to take care of the request and everything is as expected - as long as I don't let it hang at a break point.
If I let it hang at a breakpoint it begins to create new HttpApplication's objects and starts adding HttpApplications (more than 1) to serve/handle the request (which is already in process of being served by the HttpApplication which is currently stopped at the breakpoint).
I guess or hope that it might be some intelligent "behind the scenes" way of helping to distribute and handle load and / or errors. But I have no clue.
I hope some out there can assure me that it is perfectly fine and how it is supposed to be?
It's normal for the Init() method to be called multiple times. When an application starts up, the ASP.NET Worker process will instantiate as many HttpApplication objects as it thinks it needs, then it'll pool them (e.g. reuse them for new requests, similar to database connection pooling).
Now for each HttpApplication object, it will also instantiate one copy of each IHttpModule that is registered and call the Init method that many times. So if 5 HttpApplication objects are created, 5 copies of your IHttpModule will be created, and your Init method called 5 times. Make sense?
Now why is it instantiating 5 HttpApplication objects say? Well maybe your ASPX page has links to other resources which your browser will try to download, css, javascript, WebResource.aspx, maybe an iframe somewhere. Or maybe the ASP.NET Worker Process 'is in the mood' for starting more than 1 HttpApplication object, that's really an internal detail/optimisation of the ASP.NET process running under IIS (or the VS built in webserver).
If you want code that's guaranteed to run just once (and don't want to use the Application_StartUp event in the Global.asax), you could try the following in your IHttpModule:
private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();
public void Init(HttpApplication context)
{
if (!HasAppStarted)
{
lock (_syncObject)
{
if (!HasAppStarted)
{
// Run application StartUp code here
HasAppStarted = true;
}
}
}
}
I've done something similar and it seems to work, though I'd welcome critiques of my work in case I've missed something.
Inspect the HttpContext.Current.Request to see, for what request the module's init is fired. Could be browser sending multiple request.
If you are connected to IIS, do check IIS logs to know whether any request is received for the time you are staying at the break point.
Here is a bit of explanation as to what you should use, when, and how they work.
When to use Application_Start vs Init in Global.asax?
Edit: More reading
The ASP Column: HTTP Modules
INFO: Application Instances, Application Events, and Application State in ASP.NET
Examle above locks the IHttpModule for all requests, and then, it frezes the whole application.
If your IHttpModule calls request several times is needed to call HttpApplication method CompleteRequest and dispose the HttpApplication instance of the IHttpModule in EndRequest event in order to remove instance of the HttpApplication like this:
public class TestModule :IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
app.CompleteRequest();
app.Dispose();
}
void context_BeginRequest(object sender, EventArgs e)
{
//your code here
}
#endregion
}
If you need that IHttpModule requests every time without rerequest on postback use this code above.

Categories

Resources