Whenever I update my web app on IIS, any user who currently using it, will see the page be unresponsive and it won't work again until they refresh the browser. (The update process last for about 30 seconds)
I would like to show up a notification, such as a javascript alert, for user to know that the page is being udpated and please try to refresh the page after 30 seconds, etc.
I tried to catch the Exception in Global.ascx but no exception was thrown in this case.
Consider using app_offline.htm. It is a page that will cause clients to see your IIS app as being down. When you're through updating, just remove the page.
You could create a FileSystemWatcher in global.ascx then bubble up (update a js for instance) an exception when a file is updated. You could start with this:
using System.IO;
namespace WebApplication1
{
public class Global : System.Web.HttpApplication
{
FileSystemWatcher watcher;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
watcher = new FileSystemWatcher(this.Context.Server.MapPath("/"));
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
}
void watcher_Changed(object sender, FileSystemEventArgs e)
{
//set a value in js file
FileInfo jsFilesChanged = new FileInfo(Path.Combine(this.Context.Server.MapPath("/"), "scripts", "files_changed.js"));
using (StreamWriter jsWriter = (!jsFilesChanged.Exists) ? new StreamWriter(jsFilesChanged.Create()) : new StreamWriter(jsFilesChanged.FullName, false))
{
jsWriter.WriteLine("var changed_file = \"" + e.Name + "\";");
}
}
//.......
}
}
Then in client code include files_changed.js and create a periodic timeout call to check the var changed_file. Also, make sure watcher doesn't get garbage collected.
Some references:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
http://www.developerfusion.com/article/84362/extending-filesystemwatcher-to-aspnet/
How the big boys do this:
You need to have a way of posting an alert on a page. Typically this is done by having a table in your database for these alerts. Basically you are just storing some text in there like "hey, the site is going down for maintenance between 8:00am and 8:01am"..
On each page load, you check that table and display any messages found in a conspicuous place (like the top).
Prior to pushing an update you add the alert, while giving them enough time to wrap up whatever it is that they are doing.
After the push is complete you clear out the alerts table.
Honestly the main issue you have is simply one of scheduling updates and communicating to the users what's about to happen. You want to do so in a way that isn't a surprise. That said, you might consider enabling the optimizeCompilations flag in order to try and speed up the compilation time of your website when it is first hit after pushing an update.
Related
I implemented windows service with eventLog and FileSystemWatcher that looks for changes in specific directory and writes messages into MyLog.
strange thing 1:
I install it via installUtil.exe (since the VS2012 doesn't have installer templates) and in some situations when I go to "Services" and start the service I get:
The [service name] service on local computer started and then stopped. Some Services stop automatically if they are not in use by another services or programs.
I've already seen this question. 2 answeres from this post why it can be so:
1) There is no thread starting in OnStart() method.
I use the designer and set most of the properties in the Properties window and I never started any thread manually, but in some cases everything was working, so I think this is not the case.
2) An exception occures in OnStart() method. I think it's not the case cause I don't change the code. I just uninstall, build and install again the same service and in some cases it runs, in some not.
When I was stuck for mabby 2 hours with this thing I noticed that the Source property of eventLog is too long: "FilesMonitoringServices". I changed it to "MonitorSource" and everything started to work. Than I reinstalled it cauple of times and got the same warning as the above. I changed the Source property again and now the service runs.
This is the first strange thing.
strange thing 2: worse. Even if it runs it logs only OnStart() and OnStop() methods, I mean the fileSystemWatcher event handler never excutes. It is strange because today I reinstalled this service mabby hundred times and 3 times it was working but after I reinstalled it once again it stoped. And I haven't changed the code between the reinstallations at all.
Here is the methods and constructor from my class (MonitoringService) that inherits ServiceBase:
public MonitoringService()
{
InitializeComponent();
if (!EventLog.SourceExists(eventLog.Source))
{
EventLog.CreateEventSource(eventLog.Source, eventLog.Log);
}
// haven't changed it between the reinstallations
fileWatcher.Path = #"path";
}
protected override void OnStart(string[] args)
{
fileWatcher.EnableRaisingEvents = true;
eventLog.WriteEntry("start", EventLogEntryType.Information);
base.OnStart(args);
}
protected override void OnStop()
{
fileWatcher.EnableRaisingEvents = false;
fileWatcher.Dispose();
eventLog.WriteEntry("stop", EventLogEntryType.Information);
base.OnStop();
}
And file system watcher event handler:
private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
using (var conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
const string cmd = "UPDATE Products SET ImageModifiedDate=#date WHERE ProductId=#productId";
using (var command = new SqlCommand(cmd, conn))
{
command.Parameters.AddWithValue("#productId", productId);
command.Parameters.AddWithValue("#date", DateTime.Now);
command.ExecuteNonQuery();
}
}
eventLog.WriteEntry(string.Format("{0} has been changed: {1}", e.Name, DateTime.Now), EventLogEntryType.Information);
}
Question: it seems to me that this behavior is caused not by my code but rather by operation system settings . Can it be so?
****Edits: just discovered more specific stuff:**
1) If it shows the message (when I want to start the service):
The [service name] service on local computer started and then stopped. ....
I need to change Source property of eventLog, rebuild and reinstall. And this message will not show up; mabby next time.
2) I have the following folders hierarchy: images/prod-images. images and prod-images directories both contain image files. When the service is runing and I change the image from prod-images folder the message is written into the log as I wanted and the database is updated. But after one this event the service stops! (I checked this 3 times). And when I restart it and repeat this again a couple of times it updates database, writes logs and on the 3d time I get
The [service name] service on local computer started and then stopped. ....
But this is not the best part) If I change the image that is in images directory I can do it multiple times and the service doesn't stop. (only images from images/prod-images are bound to entries in the database).
So, mabbe this feature somehow referes to the database accessing?
Edits 2: in visual studio I use DEBUG -> Attach to Process to debug the service. I set up the breakpoints and change the image. First time the event handler executes flawlessly: the database is updated and the log message is written. But than I continue to press F11 (Step Into) and this event handler executes second time. At the line
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
I get "FormatException was unhandled". After this I stop debugging and the service stops! That's it: the exception occures in event handler.
Do You have any idea why it executes second time? Thanks!
P.S. I've already submited Davut Gürbüz answer cause he pointed me in the right direction.
Anyway, check out my own answer that explains the actual problem.
If you got start-stop error, this means you have an error in constructor.
Put a try catch into your ctor. You may log the error to eventlog in catch block.
Beside this I create a main method and start win service as a console app. If I get an instance of service in my main method I can also Debug it.
//You should select Console Application from Application properties
static void Main(string[] args)
{
MyWindowsService service = new MyWindowsService();
if (Environment.UserInteractive)
{
service.OnStart(args);
Console.WriteLine("Press any key to stop program");
Console.Read();
service.OnStop();
}
else
{
ServiceBase.Run(service);
}
}
Hope helps
The reason why the fileSystemWatcher1_Changed event handler method was executing twice is because I was monitoring images folder included subdirectories. And this event handler was monitoring all LastWrite events.
So, when I changed the image in images/prod-images directory this handler reacted to the image changing and also to the folder changing.
In this situation I either can change the monitoring path to prod-images or insert an if statement when updating the DB.
Such a silly mistake took me a couple of days to find it out))
I want to poll a directory to check whether new file is added to the directory in ASP.NET web application (C#). If any new file is added I want to read that file.
Can anybody give me an idea how to do that?
Thanks.
Normally you would use the FileSystemWatcher class. However, you have another problem. A web application isn't really suited for background processes. You can get away with it by using a background task and threading in general, but it's probably not a good idea. Always assume that your web application is stateless and can be re-started by the server at any time.
Ask yourself:
What is going to trigger this polling?
How is the application going to respond to this polling?
A web application is essentially a request/response system. Thus, any server-side logic (such as the polling) should be triggered by a request. But once the response is given, what is going to become of the polling? Suppose you fork off a thread in the web application which will poll in the background. What is it going to do when it finds something? There's no request/response interacting with it at that point.
Could this polling perhaps be delegated to another application? Perhaps a Windows Service? Then, in response to finding something during the polling, it can modify values in the web application's database. That way future requests to the web application would see the updated state.
This would more cleanly separate the concerns on an architectural level.
you can use FileSystemWatcher and create the instance in Application_Start event.
Sample code:
protected void Application_Start(
Object sender, EventArgs e)
{
FileSystemWatcher fsw =
new FileSystemWatcher(
Server.MapPath( “.” ) );
Application.Add( “myfsw” , fsw );
// Add event handlers here
fsw.EnableRaisingEvents = true;
}
Dispose this when application ends.
protected void Application_End(
Object sender, EventArgs e)
{
FileSystemWatcher fsw =
(FileSystemWatcher
)Application[“myfsw”];
Application.Remove( “myfsw” );
fsw.Dispose();
}
First after your program loads check the directory content and keep it as a list.After that add a timer. The timer will check the content of the directory and compare the current content with the last logged content. After comparing you can see which files are changed in the directory.
you can change the frequency of the timer based on your needs.
Hope it helps.
edit:
call GetDirectoryContent(); in your program's onload.
FileInfo[] lastUpdatedFies;
FileInfo[] temporaryFiles;
private void GetDirectoryContent()
{
DirectoryInfo di = new DirectoryInfo("c:/mydirectorypath/");
lastUpdatedFies = di.GetFiles(".");
}
private void GetDirectoryContent()
{
DirectoryInfo di = new DirectoryInfo("c:/mydirectorypath/");
lastUpdatedFies = di.GetFiles("*.*");
}
protected void tmrDirectory_Tick(object sender, EventArgs e)
{
DirectoryInfo di = new DirectoryInfo("c:/mydirectorypath/");
temporaryFiles = di.GetFiles("*.*");
foreach (FileInfo f in lastUpdatedFies)
{
//compare the list of files and do whatever you want.
// you can track any kind of data this way.
}
}`
you can also adjust the timer frequency. In this example i just kept track of files.so you will learn only if a file is deleted or added. if you want to keep track of the file size you can also do it in the same way.
Add Filewatcher in global.asmx when the application start event.
It's not clear, what do you want to do with these files. If you want read these files and cache them for future output, you can use ASP.NET Cache with CacheDependency on specific directory and a callback which will re-read the directory and add new file to cache. You should take a look at Cache.Insert method and CacheDependency constructor
I created a ASP.NET Website with Visual Studio 2010 C#.
My program reads a config file to create some classes and display informations.
The config file is not included in the project (does not appear in the solution explorer). If I modify the file while my application is not running, and run it afterwards, it still reads the old version like it keep it in cache. I have to close Visual Studio for it to accept the changes.
My second problem is related to (if not caused by) my first problem. I am using FileSystemWatcher to see if the config file is modified while the application is running, but the Changed event is never called.
private string _configFilePath;
private FileSystemWatcher _watcher;
protected void Page_Load(object sender, EventArgs e)
{
//Gets the config file in the application's parent directory
string appPath = this.MapPath("~");
string[] split = appPath.Split('\\');
_configFilePath = appPath.Substring(0, appPath.Length - split[split.Length-1].Length);
Application.Add("watcher", new FileSystemWatcher(_configFilePath.Substring(0, _configFilePath.Length-1), "*.xml"));
_watcher = (FileSystemWatcher)Application["watcher"];
_watcher.NotifyFilter = NotifyFilters.FileName;
_watcher.Changed += new System.IO.FileSystemEventHandler(Watcher_Changed);
_configFilePath += "ProductsConfig.xml";
UpdateDisplay();
}
private void Watcher_Changed(object source, FileSystemEventArgs e)
{
UpdateDisplay();
}
How can I solve this?
Thank you
My second problem is related to (if not caused by) my first problem. I
am using FileSystemWatcher to see if the config file is modified while
the application is running, but the Changed event is never called.
It's never called because at that point the Thread that's servicing the request is already returned to the pool and the request has ended. The Watcher_Changed event will never fire.
You need to tackle this in a different manner, remember that HTTP is a "disconnected" protocol, after the request has been served, don't expect any of the page events to fire "automagically" when something happens on the server side that would notify all connected users.
One way to do this is via Ajax. You'd need to constantly "ask" the server whether there's new information or not and update the sections of the page that need to be updated as a result of the change on the server.
There are 2 problems here.
1. You never called _watcher.EnableRaisingEvents = true;
2. You try to go to the parent folder of your root folder, which might not be allowed.
/ Tibi
I'm using WebKitDotNet to simulate and automate a web browser. This is really nifty and works in most respects. However, when I try to implement this code, WebKit doesn't trigger a download:
WebKitBrowser _b = null;
private void button1_Click(object sender, EventArgs e)
{
_b = new WebKitBrowser();
_b.DownloadBegin += new FileDownloadBeginEventHandler(b_DownloadBegin);
_b.Error += new WebKitBrowserErrorEventHandler(_b_Error);
_b.AllowDownloads = true;
_b.Navigate("http://sourceforge.net/projects/webkitdotnet/files/WebKit%20.NET%200.x/0.5/WebKit.NET-0.5-bin-cairo.zip/download");
}
void _b_Error(object sender, WebKitBrowserErrorEventArgs e)
{
MessageBox.Show("error!");
}
void b_DownloadBegin(object sender, FileDownloadBeginEventArgs e)
{
MessageBox.Show("hi");
}
Neither the "Error" nor the "DownloadBegin" events fire. I would expect at least one of them to do so - is there a setting that I'm missing?
EDIT: I know this is an old question, but here's the update. When I wrote this question, I was trying to automate a process that required a human being - once per day - to log onto a website, provide credentials, and click a download link. We were hoping to be able to do this programmatically to relieve the monotony for the poor person tasked with doing this job.
Unfortunately, WebKitDotNet did not succeed in this task. Although, in a webkit based browser, you can click on the link and trigger a download, in the embedded WebKitDotNet clicking on the link did nothing. My guess is that something within WebKitDotNet lost the event. If anyone wants to test this, you can use the Sourceforge download link to test.
One of the guys on my team did eventually solve this problem by using an Internet Explorer automation tool called "IMacros". We selected this product because 1) We could guarantee that IE was installed on every computer that would run the program, and 2) IMacros could correctly receive the event from the website and trigger the file download.
On the Issue tracker there is a post date from March 24, 2011 in which is stated that download does not work yet:
https://github.com/webkitdotnet/webkitdotnet/issues/7
Since there are few issues in the tracker, it would have probably been marked as resolved if the feature was added meantime.
I am using ASP.Net + .Net 3.5 + VSTS 2008 + IIS 7.0 + C# to develop a web application. I am creating a very simple web application, and I just modified page_load, Session_Start and Session_End. Here are my code, my question is I find session ends message is written to file immediately after session start message. My test method is just open IE to access this page. I think session should last for a long time, like several mins. Why session ends so quickly? Why seesion ends even if I do not close the page?
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Hello World! ");
Session["SomeUserData"] = DateTime.Now;
}
protected void Session_Start(object sender, EventArgs e)
{
using (TextWriter tw = new StreamWriter(#"C:\TestSession\bin\session.txt", true))
{
// write a line of text to the file
tw.WriteLine(DateTime.Now + " Session Started.");
}
}
protected void Session_End(object sender, EventArgs e)
{
using (TextWriter tw = new StreamWriter(#"C:\TestSession\bin\session.txt", true))
{
// write a line of text to the file
tw.WriteLine(DateTime.Now + " Session Ended.");
}
}
I met with the same issue even if add Session manipulation code into Page_Load method, here is output file content, which you can see session ends event is called immediately after session start.
2010/7/15 0:11:14 Session Started.
2010/7/15 0:11:14 Session Ended.
2010/7/15 0:11:28 Session Started.
2010/7/15 0:11:28 Session Ended.
thanks in advance,
George
If I remember correctly, you need to actually assign something to Session to activate it. Otherwise ASP.NET will regenerate a new session (new session id if you use fiddler to check) every time.
EDIT: Because session.txt is located inside the bin directory. Once you write to the bin directory the application will restart so the Session_End event fired immediately. Move session.txt out of bin directory to somewhere else will resolve your issue.
This kind of behaviour is sometimes caused by an overzealous anti-virus program. Try disabling the anti-virus and see if that helps. If it helped, then add the site's directory to the exclusion list.
Also closing the browser doesn't have any effect on your session either way.