Why does file creation fail in Application_Start? - asp.net

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();
}
}
}

Related

How to disable a single aspx page in ASP.NET webapplication?

Would like to disable a single aspx page in an ASP.NET web application and show the message 'This page is under maintenance' while the application is still up. Is this possible?
One way to do that on Application_BeginRequest on global.asax. Check the if the specific file is called and show some other static page and End the process there. Here is how:
protected void Application_BeginRequest(Object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string cTheFileName = System.IO.Path.GetFileName(HttpContext.Current.Request.Path);
// if its the file you want to be offline
if (cTheFileName == 'filename.aspx')
{
// the file we look now is the app_offline_alt.htm
string cOffLineFile = HttpRuntime.AppDomainAppPath + "app_offline_alt.htm";
// if exist on root - if not we skip the offline mode.
// this way you can put it offline with just the existing of this file.
if (System.IO.File.Exists(cOffLineFile))
{
using (var fp = System.IO.File.OpenText(cOffLineFile))
{
// read it and send it to the browser
app.Response.Write(fp.ReadToEnd());
fp.Close();
}
// and stop the rest of processing
app.Response.End();
return;
}
}
}
the app_offline_alt.htm contains a simple under maintenance message or what ever you like.

Response.Redirect() Turns Response.RedirectLocation NULL

I have a group of Asp.Net applications that all share a common HttpModule that contains some code like this:
public class MyModule : IHttpModule
{
public void Dispose()
{
}
public void Init( HttpApplication context )
{
context.Error += new EventHandler( context_Error );
}
private void context_Error( object sender, EventArgs e )
{
var lastError = HttpContext.Current.Server.GetLastError();
doSomeStuffWithError(lastError);
var response = HttpContext.Current.Response;
var redirect = GetErrorRedirect(lastError);
response.Redirect(redirect, true);
}
}
This works totally fine for all of my applications except for one. In the case of the one that doesn't work correctly, response.Redirect(...) doesn't seem to work. Instead of the redirect I expect, Asp.Net is redirecting to its standard error page. I've checked the configuration of this application and don't see anything wrong or significantly different from the other applications.
While investigating this issue, I modified the error handler with one more line of code as follows:
private void context_Error( object sender, EventArgs e )
{
var lastError = HttpContext.Current.Server.GetLastError();
doSomeStuffWithError(lastError);
var response = HttpContext.Current.Response;
var redirect = GetErrorRedirect(lastError);
//setting a break point here, i've verified that 'redirect' has a value in all cases
response.Redirect(redirect, true);
var wtf = response.RedirectLocation;
//inspecting the value of 'wtf' here shows that it is null for one application, but equal to 'redirect' in all others.
}
When I set a break point on 'wtf' I'm seeing some strange behavior. For applications that work, wtf contains the same value as redirect. However, for my app that isn't working, wtf is null.
Anyone have any ideas on what would cause wtf to be null in this way?
The overload of Response.Redirect you are using will call Response.End and throw a ThreadAbortException. It says so in the documentation. So, the fact that "it works" in other applications is interesting as it should never execute var wtf = response.RedirectLocation; During a debugging session, it is not surprising that it's null, either, as there is likely some reason that it allows to execute that line during debug.
In addition, it will of course execute the default error page if you have the mode set to On or RemoteOnly for the <customErrors> setting in Web.config unless you clear the error before redirecting. This is by design.
If you need to execute additional code after you have already called Response.Redirect, pass false as the second parameter to avoid the Response.End call and clear the error using HttpContext.Current.ClearError().
Based on your example, I would rewrite your HttpModule like so:
public class MyModule : IHttpModule
{
public void Dispose()
{
}
public void Init( HttpApplication context )
{
context.Error += new EventHandler( context_Error );
}
private void context_Error( object sender, EventArgs e )
{
var context = HttpContext.Current;
var lastError = context.Server.GetLastError();
doSomeStuffWithError(lastError);
var response = context.Response;
var redirect = GetErrorRedirect(lastError);
context.ClearError();
// pass true if execution must stop here
response.Redirect(redirect, false);
// do other stuff here if you pass false in redirect
}
}

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

programatically recycle pool from asp.net application in same pool

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());
}
}
}

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