This question already has answers here:
How can I programmatically stop or start a website in IIS (6.0 and 7.0) using MsBuild?
(3 answers)
Closed 7 years ago.
I am using the MVC5 for an web application. The web app runs in IIS7 or greater.
In the Global.asax on application_start, the number of licenses will be set:
protected void Application_Start()
{
try
{
MyApp.cNumberOfLicenses = COM.GetNumberOfLicenses();
}
catch(Exception e)
{
// log exception
// stop web site.
}
}
If any expection will be thrown in this context, the web site should shut down as you can do that in the IIS-Manager:
How can I stop the current web site in my Application_Start ?
You can do it with the help of "Microsoft.Web.Administration.dll"
using Microsoft.Web.Administration;
After adding the reference of "Microsoft.Web.Administration.dll" write below code in Global.asax
protected void Application_Start(object sender, EventArgs e)
{
try
{
MyApp.cNumberOfLicenses = COM.GetNumberOfLicenses();
}
catch (Exception e)
{
// get the web site name
var lWebSiteName = System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName();
// log exception
// stop web site.
using (ServerManager smg = new ServerManager())
{
var site = smg.Sites.FirstOrDefault(s => s.Name == lWebSiteName);
if (site != null)
{
//stop the site...
site.Stop();
}
}
}
}
I will go not with stop it, but to show some message if you do not have license.
This is an example, and an idea.
You can use this code on global.asax where if you do not have licenses the moment you start, you open a flag, and after that you do not allow any page to show, and you send a page that you can keep on an html file.
private static bool fGotLicense = true;
protected void Application_Start()
{
try
{
MyApp.cNumberOfLicenses = COM.GetNumberOfLicenses();
}
catch(Exception e)
{
// log exception
// stop web site.
fGotLicense = false;
}
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
// if not have license - let show some infos
if (!fGotLicens)
{
// the file we look now is the app_offline_alt.htm
string cOffLineFile = HttpRuntime.AppDomainAppPath + "app_offline_alt.htm";
// if exist on root
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;
}
}
You can have a file named app_offline.htm with content say This website is offline now in web server and copy that to root directoy of website you want for any event.
It will directly show that message, but yes, App pool will be still ON, when you need to start , you just need to rename that to something else.
Related
namespace RunMyExe
{
public partial class runEXE: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
AppDomain sandbox = AppDomain.CreateDomain("sandbox");
try
{
string exeFile = Request.MapPath("myEXE.exe");
sandbox.ExecuteAssembly(exeFile);
System.Threading.Thread.Sleep(5000);
}
catch (Exception ex)
{
string error = ex.Message;
lblerror.Text = error;
}
}
}
}
I publish this aspx page/site on IIS7 on windows2008r2, when I browse the URL of the published page eg. https://myserver/runEXE.aspx, the exe does run as I can verify the output, but I get this on the browser "This web page is not available ERR_INVALID_HANDLE" and the application pool stops running, I have to go to the server and start the application pool every time I attempt to browse this URL.
I've written a simple managed HttpModule for IIS 8.5 in C# and have installed this into the global-assembly cache (CLR version 4.0.30319). This is detected as present by IIS and I've installed it as a module at the application host level.
Unfortunately it doesn't seem to be executed at all. We're only serving up static content, but since IIS in running in integrated mode I was under the impression that HttpModules were executed for all requests, not just those in the ASP.NET pipeline.
The HttpModule has been reduced to the simplest possible level - logging when the module is created, disposed of, a request begins and a request ends, as below:
using System;
using System.Web;
using System.Collections.Specialized;
using System.IO;
public class ServerLoggingModule : IHttpModule
{
public ServerLoggingModule()
{
using (StreamWriter file = new StreamWriter(#"C:\LocalIISAuth\logs\iis.log"))
{
file.WriteLine("Created module");
}
}
public string ModuleName
{
get { return "ServerMaskModule"; }
}
public void Dispose()
{
using (StreamWriter file = new StreamWriter(#"C:\LocalIISAuth\logs\iis.log"))
{
file.WriteLine("Disposed of module");
}
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(ServerLoggingModule.BeginRequestHandler);
context.EndRequest += new EventHandler(ServerLoggingModule.EndRequestHandler);
}
protected static void BeginRequestHandler(Object sender, EventArgs e)
{
using (StreamWriter file = new StreamWriter(#"C:\LocalIISAuth\logs\iis.log"))
{
file.WriteLine("BeginRequest");
}
}
protected static void EndRequestHandler(Object sender, EventArgs e)
{
using (StreamWriter file = new StreamWriter(#"C:\LocalIISAuth\logs\iis.log"))
{
file.WriteLine("EndRequest");
}
}
}
The request reaches the point in the pipeline the module resides at, but just seems to skip the module. There are no errors displayed and the page displays fine.
Thanks in advance
As it turns out we hadn't enabled the .NET extensibility Windows features which resulted in the module not being loaded. Unfortunately IIS does let you add the managed module to it, despite it surely knowing it would never be able to launch it!
To add these modules with PowerShell use:
Install-WindowsFeature Web-Net-Ext
Install-WindowsFeature Web-Net-Ext45
Sometimes pools get corrupted in some way, recreating pool fixes such problem. Hope it helps someone.
Problem Background
I have few web applications which were developed using Microsoft .net framework 4.0 and running on the IIS 7.0 .so now i need to track traffic information(requested user,ip,application name ,address,request time etc..) for all these application and persist into a database or text file etc.
while i was searching on this i found HTTP handlers concept.
Is this handy to use my case ? or are there any alternatives which can fulfill my requirement?
I need to write this component as plug-abbe one.because i need connect this component easily to another web application also.
appreciate your ideas
Use an HttpModule to intercept all requests via the BeginRequest event, like this:
public class RequestLoggingModule : IHttpModule
{
private HttpApplication httpApp;
public void Init(HttpApplication httpApp)
{
this.httpApp = httpApp;
httpApp.BeginRequest += new EventHandler(OnBeginRequest);
}
void OnBeginRequest(object sender, EventArgs e)
{
// Get the user that made the request
HttpApplication application = (HttpApplication)sender;
HttpResponse response = application.Context.Response;
WindowsIdentity identity =
(WindowsIdentity)application.Context.User.Identity;
LogInformation(identity.Name);
// Do this for other information you want to log here
}
private void LogInformation(string data)
{
EventLog log = new EventLog();
log.Source = "Application XYZ Request Logging";
log.WriteEntry(data, EventLogEntryType.Information);
}
public void Dispose()
{
}
}
All,
I have a ~/temp dir on my web root in the web server. Let's say:
C:\inetpub\myapp\temp
and I have a method in the code behind class of a page that deletes all the files there. Everything works well.
protected CleanTemp() {
// clean all the files in tmp dir
Array.Foreach...
}
The problems is that if I create a timer in my Global.aspx that tries to execute such clean in the same way, the system lists the files in the temp dir but for each of them it returns an exception saying the user does not have the proper access rights:
[Global.aspx]
void Application_Start(object sender, EventArgs e) {
PhisicalTmpFolder = Server.MapPath(~/temp);
// create new timer
System.Timers.Timer timScheduledTask = new System.Timers.Timer();
timScheduledTask.Interval = 20 * 60 * 1000.0;
timScheduledTask.Enabled = true;
timScheduledTask.Elapsed += new System.Timers.ElapsedEventHandler(timScheduledTask_Elapsed);
}
void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
// clean all the files in tmp dir
Array.ForEach(
Directory.GetFiles(PhisicalTmpFolder),
delegate(string path) {
try {
File.Delete(path); i++;
} catch (Exception ex) {
if (_logger != null) _logger.Error(ex.Message, ex);
}
}
);
}
How can I tell to the timer that it must run with the same access right of the application?
Thank you in advance,
Gianpiero
I think the problem you have here is that the ASP.NET process account does not have the appropriate rights and you have user impersonation enabled so when the operation is initiated during a page request it is done so under the request user account which does have rights.
Try granting the ASP.NET process account rights to that directory.
Can you use impersonation inside your timScheduledTask_Elapsed method to change to an identity that has the necessary elevated permissions?
There is an excellent post here that describes how you can easily create an impersonation context in a try / finally block.
Check if the user configured in the Application Pool (usually NETWORK SERVICE) has permission to delete them.
I'm building a small web application with ASP.NET MVC 2, using db4o as a datastore.
I have added an HttpModule—as per the example here—to give the application access to the db4o database, and everything is working perfectly on my development machine under the VS2008 ASP.NET Development Server.
However, when I deploy the app to my web host and try to access it, I get a DatabaseFileLockedException at the line where the HttpModule tries to open the database file. But there should be nothing else accessing the file; indeed on first run of the app it will only just have been created when this exception gets thrown.
The web host's servers are running IIS 7 on Windows Server 2008, and the application is running under Full Trust. It is a sub-application, in case that makes any difference.
I can't work out why this error is occurring on the live server, but not locally on my development server. Can anyone help me out or suggest what I should do next?
That's a mistake in the example-code. It assumes that the HttpModule.Init is only called once, which isn't necessarily true. Depending how your application is configured, it can be called multiple times. To fix this, check in the HttpModule-Handler if the instance is already there:
using System;
using System.Configuration;
using System.Web;
using Db4objects.Db4o;
namespace Db4oDoc.WebApp.Infrastructure
{
public class Db4oProvider : IHttpModule
{
private const string DataBaseInstance = "db4o-database-instance";
private const string SessionKey = "db4o-session";
// #example: open database when the application starts
public void Init(HttpApplication context)
{
if (null==HttpContext.Current.Application[DataBaseInstance])
{
HttpContext.Current.Application[DataBaseInstance] = OpenDatabase();
}
RegisterSessionCreation(context);
}
private IEmbeddedObjectContainer OpenDatabase()
{
string relativePath = ConfigurationSettings.AppSettings["DatabaseFileName"];
string filePath = HttpContext.Current.Server.MapPath(relativePath);
return Db4oEmbedded.OpenFile(filePath);
}
// #end example
// #example: close the database when the application shuts down
public void Dispose()
{
IDisposable toDispose = HttpContext.Current.Application[DataBaseInstance] as IDisposable;
if (null != toDispose)
{
toDispose.Dispose();
}
}
// #end example
// #example: provide access to the database
public static IObjectContainer Database
{
get { return (IObjectContainer)HttpContext.Current.Items[SessionKey]; }
}
// #end example
// #example: A object container per request
private void RegisterSessionCreation(HttpApplication httpApplication)
{
httpApplication.BeginRequest += OpenSession;
httpApplication.EndRequest += CloseSession;
}
private void OpenSession(object sender, EventArgs e)
{
IEmbeddedObjectContainer container =
(IEmbeddedObjectContainer)HttpContext.Current.Application[DataBaseInstance];
IObjectContainer session = container.OpenSession();
HttpContext.Current.Items[SessionKey] = session;
}
private void CloseSession(object sender, EventArgs e)
{
if (HttpContext.Current.Items[SessionKey] != null)
{
IObjectContainer session = (IObjectContainer)HttpContext.Current.Items[SessionKey];
session.Dispose();
}
}
// #end example
}
}
As alternative you could use the Application_Start from the Global.apsx, which is called only once for sure.
You have another problem here.
When AppPools restart there can be an overlap when the old AppPool is finishing request and the new AppPool is servicing new requests.
During this time you will have two processes trying to access the same db4o file
To get around this you can use something like the hack below.
Note the use of Db4oFactory.OpenServer instead of Db4oEmbedded.OpenFile. This allows the use of transactions on a more fine grained basis.
public IObjectServer OpenServer()
{
Logger.Debug("Waiting to open db4o server.");
var attempts = 0;
do
{
try
{
return Db4oFactory.OpenServer(fileName, 0);
}
catch (DatabaseFileLockedException ex)
{
attempts++;
if (attempts > 10)
{
throw new Exception("Couldn't open db4o server. Giving up!", ex);
}
Logger.Warn("Couldn't open db4o server. Trying again in 5sec.");
Thread.Sleep(5.Seconds());
}
} while (true);
}
Hope this helps
Sounds like permission issues if it works on dev. Stick a notepad file in the same directory and try to open that with some bare bones file code. I bet you'll have the same issue.