programatically recycle pool from asp.net application in same pool - asp.net

Have an ASP.net web app which works fine for a few days, but then randomly throws some database connection string exception and as a result 0 records are listed in a table (should show hundreds). I've spent many weeks debugging, memory is fine, the database exists and it's fixed by doing anything which would cause the application to recycle. It takes many days of waiting to even reproduce.
So I was thinking since I know there should never be 0 records, how can I force the application pool running the web app to recycle (when I get this database exception or 0 records). At least this way the web site will work for the next user and I don't have to manually restart it.

I've never been entirely comfortable with this solution because of the complexity, but also because the security requirements are unclear (and if you have to grant rights to the application user for this, that's not only yet another configuration step, but also a security risk, and it seems like letting the application user have rights to recycle the application pool indiscriminately, especially over the network, could be leveraged in a DOS attack).
In my limited situation where I've found critical conditions that I was able to resolve with a restart and detect during execution but was not yet able to prevent through more palatable code changes, and after much research, I went through several other solutions (OK--hacks) to get this done. 1. Throw an unhandled exception on a newly spawned thread, 2. Environment.Exit(), and 3. System.Web.HttpRuntime.UnloadAppDomain(). These have the rather nasty side-effect of terminating all in-progress requests, which is admittedly a terrible hack, but is tolerable in some cases (like where the condition discovered prevents proper handling of the vast majority of requests anyway).
The distaste for this hack has remained with me for years until I recently stumbled across this little gem that is much simpler and avoids WMI entirely:
System.Web.Hosting.HostingEnvironment.InitiateShutdown();
My testing has shown that it does exactly what I needed, and I believe it's what you wanted as well. According to the documentation, it's been around since .NET 2.0, but I never came across it in my research until a couple of days ago.

Hi in this article you can find relevant code to restart application pool from Asp.net
Restart IIS application pool from ASP.NET page
using System;
using System.Web;
using System.Web.UI;
using System.Management;
using System.DirectoryServices;
using System.Web.UI.WebControls;
public partial class iis : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(System.Environment.MachineName);
status();
}
protected void status()
{
string appPoolName = "dev.somesite.com";
string appPoolPath = #"IIS://" + System.Environment.MachineName + "/W3SVC/AppPools/" + appPoolName;
int intStatus = 0;
try
{
DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);
intStatus = (int)w3svc.InvokeGet("AppPoolState");
switch (intStatus)
{
case 2:
lblStatus.Text = "Running";
break;
case 4:
lblStatus.Text = "Stopped";
break;
default:
lblStatus.Text = "Unknown";
break;
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
protected void stopAppPool(object sender, EventArgs e)
{
Button btn = (Button)sender;
string appPoolName = btn.CommandArgument;
string appPoolPath = #"IIS://" + System.Environment.MachineName + "/W3SVC/AppPools/" + appPoolName;
try
{
DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);
w3svc.Invoke("Stop", null);
status();
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
protected void startAppPool(object sender, EventArgs e)
{
Button btn = (Button)sender;
string appPoolName = btn.CommandArgument;
string appPoolPath = #"IIS://" + System.Environment.MachineName + "/W3SVC/AppPools/" + appPoolName;
try
{
DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);
w3svc.Invoke("Start", null);
status();
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
}

Related

How to count the number of times a website is visited and the number of online users in MVC

I need to find out the number of times a website has been visited and how many online users it has.
My code is this:
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Code that runs on application startup
Application["SiteVisitedCounter"] = 0;
//to check how many users have currently opened our site write the following line
Application["OnlineUserCounter"] = 0;
}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
Application.Lock();
Application["SiteVisitedCounter"] = Convert.ToInt32(Application["SiteVisitedCounter"]) + 1;
//to check how many users have currently opened our site write the following line
Application["OnlineUserCounter"] = Convert.ToInt32(Application["OnlineUserCounter"]) + 1;
Application.UnLock();
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
Application.Lock();
Application["OnlineUserCounter"] = Convert.ToInt32(Application["OnlineUserCounter"]) - 1;
Application.UnLock();
}
The HomeController class contains the following code.
I got an error on System.Net.Mime.MediaTypeNames.Application.
[HttpGet]
public ActionResult Index()
{
ViewBag.noofsitesvisited = "No of times site visited=" + System.Net.Mime.MediaTypeNames.Application["SiteVisitedCounter"].ToString();
ViewBag.onlineusers = "No of users online on the site=" + System.Net.Mime.MediaTypeNames.Application["OnlineUserCounter"].ToString();
}
You don't want to do it this way. One, reading and writing data from anything global in web environment is dangerous and inadvisable from the get go, and two, this will only store the count while the AppPool is active anyways. If the server restarts or the AppPool restarts or even just recycles, your counts all go away and you start over from zero.
If you want to store a count that needs to persist, then you need to use a persistent medium: database, text file, etc. Not only is this safer in general, it is also the only way to have a true persistent count.
That said, why not just use Google Analytics or some other form of website analytics. Not only are you reinventing the wheel, but actual analytics tracking will be more accurate and provide more useful statistics than anything you can do on your own.
You need to change the code in the controller as follows:
[HttpGet]
public ActionResult Index()
{
ViewBag.noofsitesvisited = "No of times site visited=" + HttpContext.Application["SiteVisitedCounter"].ToString();
ViewBag.onlineusers = "No of users online on the site=" + HttpContext.Application["OnlineUserCounter"].ToString();
}
In MVC Application variables are accessible via HttpContext

Why does file creation fail in Application_Start?

I have some code which attempts to create and write to a log file in a subdirectory of my website (shown below). If I put the first call to this code in the Page_Load() event of Default.aspx, it works fine every time. If, however, I make the first call to this code inside the Global.asax Application_Start() event, I get an access denied exception from .NET IO library, even though the path displayed in the exception message is correct.
Has anyone encountered anything like this? It is as if the code running from Application_Start() has a more limited set of permissions than code running later.
Kind wishes ~ Patrick
using( StreamWriter writer = new StreamWriter( FullPathAndNameData, true ) )
{
string logEntry = DateTime.Now.ToString() + ": " + formattedMessage;
writer.WriteLine( logEntry );
writer.Flush();
}
As far as I know, Application_Start doesn't have special permission.
Only thing I can think of is if you move the code inside Application_Start, the file path is moved outside of Web Application and it needs permission.
You can try using HttpRuntime.AppDomainAppPath.
public class Global : HttpApplication
{
private void Application_Start(object sender, EventArgs e)
{
var fullPathAndNameData = string.Format("{0}App_Data\\Log.txt",
HttpRuntime.AppDomainAppPath);
using (var writer = new StreamWriter(fullPathAndNameData, true))
{
string logEntry = DateTime.Now + ": " + "Inside Application_Start";
writer.WriteLine(logEntry);
writer.Flush();
}
}
}

How can i create a webservice which is checking table for some periodically in database in asp.net?

I wanted to checking my database table for periodically.So how can i create a webservice and how can i configure it.
basically what you need is, something which is always running and hence can make periodic calls.
There are a number of ways to do it
(Since ASP.NET hence) You can make a Windows Service, and host this service on your server, since server is always running, this Windows Service will make request to your webservice, update database or watever you want
You can use SQL Jobs to do it. You can call a webservice from a job, through a SSIS (Sql Server Integration Service) Package. These packages are very very robust in nature, they can do almost any db activity that you want them to do, including webservice request.
And finally, you can use third party tools such as Quartz.Net
References:
this is how you can call a webservice through a windows service.
this is how you can call a webservice through a ssis package.
this is how you can integrate a SSIS package in a SQL Job
this is how you can create a windows service
this is how you can create a SSIS package
this is how you can get answer/tutorial of almost anything
Example:
simplest of all of these would be a Windows Service. Making a windows service and hosting it on the machine(server) is very easy, use one of the given links (specially the last link). Usually, in Windows Service, you do some activity in OnStart event. you can place a timer inside this OnStart and upon TimerTick(), you can request your webservice.
something like this:
class Program : ServiceBase
{
System.Timers.Timer timer;
static void Main(string[] args)
{
ServiceBase.Run(new Program());
}
public Program()
{
this.ServiceName = "My Service";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
InitializeTimer();
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
protected void InitializeTimer()
{
try
{
if (timer == null)
{
timer = new System.Timers.Timer();
timer.Enabled = true;
timer.AutoReset = true;
timer.Interval = 60000 * 1;
timer.Enabled = true;
timer.Elapsed += timer_Elapsed;
}
}
catch (Exception ex)
{
Utility.WriteLog("Exception InitialiseTimer : " + ex.Message.ToString());
}
finally
{
}
}
protected void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
TimerTick();
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["TimerInerval"]);
}
private void TimerTick()
{
try
{
DownloadFromFTPandValidate objDownLoadandValidate = new DownloadFromFTPandValidate();
objDownLoadandValidate.ProcessMain();
}
catch (Exception ex)
{
Utility.WriteLog("Exception InitialiseTimer : " + ex.Message.ToString());
}
}
}
Here, class DownloadFromFTPandValidate wraps the code to db activity. It shd give you an idea.
You will need a job scheduler for periodical task. I recommend you a good one. Check out this link: http://quartznet.sourceforge.net/
Why not using a trigger on your table which runs a stored procedure once data was modified, then use the xp_cmdshell to access the commandline form your stored procedure so you can run for example a batch file or whatever.

Asp.net global output cache

Last few days I thinkin about output cache in asp.net. In my task I need to implement output cache for the very big project. After hours of searching I did not find any examples.
Most popular way to use output cache is declarative, in this case you need to write something like this on the page which you want to cache.
But if you need to cache whole site you must write this on all pages or master pages on project. It is madness. In this case you cant store all configuration in one place. All page have his own configurations..
Global.asax could help me, but my site contains about 20 web progects and ~20 global.asax files. And i don't want copy same code to each project.
For these reasons, i made decision to create HTTPModule.
In Init method i subscribe to two events :
public void Init(HttpApplication app)
{
app.PreRequestHandlerExecute += new EventHandler(OnApplicationPreRequestHandlerExecute);
app.PostRequestHandlerExecute += new EventHandler(OnPostRequestHandlerExecute);
}
In method "OnPostRequestHandlerExecute" I set up output caching parameters for each new request :
public void OnPostRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpCachePolicy policy = app.Response.Cache;
policy.SetCacheability(HttpCacheability.Server);
policy.SetExpires(app.Context.Timestamp.AddSeconds((double)600));
policy.SetMaxAge(new TimeSpan(0, 0, 600));
policy.SetValidUntilExpires(true);
policy.SetLastModified(app.Context.Timestamp);
policy.VaryByParams.IgnoreParams = true;
}
In "OnApplicationPreRequestHandlerExecute" method I set calback method to cache validation:
public void OnApplicationPreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
app.Context.Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), app);
}
And last part - callback validation method :
public void Validate(HttpContext context, Object data, ref HttpValidationStatus status)
{
if (context.Request.QueryString["id"] == "5")
{
status = HttpValidationStatus.IgnoreThisRequest;
context.Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), "somecustomdata");
}
else
{
status = HttpValidationStatus.Valid;
}
}
To attach my HttpModule I use programmatically attach method :
[assembly: PreApplicationStartMethod(typeof(OutputCacheModule), "RegisterModule")]
This method works perfectly, but I want to know is there other ways to do this.
Thanks.
Try seeing if IIS caching provides what you need.
http://www.iis.net/configreference/system.webserver/caching

Restarting a website from its own webpage

Well, just to keep it simple: I have a webform. On it a button called "Restart". I click on this button and IIS will restart itself.
Now, what would be the C# code that I would need to write behind the OnClick event of this web button? (If it's even possible?)
Then a second button is added. It's called "Reset" and should just reset the AppDomain for the current web application. What would be the code for this?
protected void Reload_Click(object sender, EventArgs e)
{
HttpRuntime.UnloadAppDomain();
}
protected void Restart_Click(object sender, EventArgs e)
{
using (var sc = new System.ServiceProcess.ServiceController("IISAdmin"))
{
sc.Stop();
sc.Start();
}
}
Process iisreset = new Process();
iisreset.StartInfo.FileName = "iisreset.exe";
iisreset.StartInfo.Arguments = "computer name";
iisreset.Start();
//iisreset.exe is located in the windows\system32 folder.
(http://www.velocityreviews.com/forums/t300488-how-can-i-restart-iis-or-server-from-aspx-page-or-web-service.html)
string processName = "aspnet_wp";
System.OperatingSystem os = System.Environment.OSVersion;
//Longhorn and Windows Server 2003 use w3wp.exe
if((os.Version.Major == 5 && os.Version.Minor > 1) || os.Version.Major ==6)
processName = "w3wp";
foreach(Process process in Process.GetProcessesByName(processName))
{
Response.Write("Killing ASP.NET worker process (Process ID:" +
process.Id + ")");
process.Kill();
}
Is there more than one web site hosted on the server where this code will run? If so, you may want to look at the System.DirectoryServices namespace, and restart the individual web site

Resources