using System.Web.SessionState;
using System.Web.Configuration;
-#if !TARGET_J2EE
using System.Web.Compilation;
-#else
+#if TARGET_J2EE
using vmw.common;
#endif
+#if NET_2_0 && !TARGET_J2EE
+using System.CodeDom.Compiler;
+#endif
+
namespace System.Web {
class HttpApplicationFactory {
+ object this_lock = new object ();
+
// Initialized in InitType
#if TARGET_J2EE
static HttpApplicationFactory theFactory {
#else
static HttpApplicationFactory theFactory = new HttpApplicationFactory();
#endif
-
MethodInfo session_end;
bool needs_init = true;
bool app_start_needed = true;
Type app_type;
HttpApplicationState app_state;
Hashtable app_event_handlers;
-#if !TARGET_JVM
- FileSystemWatcher app_file_watcher;
- FileSystemWatcher bin_watcher;
- FileSystemWatcher config_watcher;
+ static ArrayList watchers = new ArrayList();
+ static object watchers_lock = new object();
+ static bool app_shutdown = false;
+#if NET_2_0
+ static bool app_disabled = false;
+ static string[] app_browsers_files = new string[0];
#endif
Stack available = new Stack ();
Stack available_for_end = new Stack ();
- // Watch this thing out when getting an instance
- IHttpHandler custom_application;
-
bool IsEventHandler (MethodInfo m)
{
int pos = m.Name.IndexOf ('_');
list.Add (method);
}
+
+ ArrayList GetMethodsDeep (Type type)
+ {
+ ArrayList al = new ArrayList ();
+ MethodInfo[] methods = type.GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
+ al.AddRange (methods);
+
+ Type t = type.BaseType;
+ while (t != null) {
+ methods = t.GetMethods (BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ al.AddRange (methods);
+ t = t.BaseType;
+ }
+
+ return al;
+ }
Hashtable GetApplicationTypeEvents (Type type)
{
- lock (this) {
+ lock (this_lock) {
if (app_event_handlers != null)
return app_event_handlers;
app_event_handlers = new Hashtable ();
- BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
- BindingFlags.Instance | BindingFlags.Static;
-
- MethodInfo [] methods = type.GetMethods (flags);
- foreach (MethodInfo m in methods) {
- if (m.DeclaringType != typeof (HttpApplication) && IsEventHandler (m))
+ ArrayList methods = GetMethodsDeep (type);
+ Hashtable used = null;
+ MethodInfo m;
+ string mname;
+
+ foreach (object o in methods) {
+ m = o as MethodInfo;
+ if (m.DeclaringType != typeof (HttpApplication) && IsEventHandler (m)) {
+ mname = m.ToString ();
+ if (used == null)
+ used = new Hashtable ();
+ else if (used.ContainsKey (mname))
+ continue;
+ used.Add (mname, m);
AddEvent (m, app_event_handlers);
+ }
}
+ used = null;
}
return app_event_handlers;
Hashtable GetApplicationTypeEvents (HttpApplication app)
{
- lock (this) {
+ lock (this_lock) {
if (app_event_handlers != null)
return app_event_handlers;
context.ApplicationInstance = app;
app.SetContext (context);
object [] args = new object [] {app, EventArgs.Empty};
+ app.InApplicationStart = true;
FireEvent ("Application_Start", app, args);
+ app.InApplicationStart = false;
return app;
}
HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true);
FireEvent ("Application_End", app, new object [] {new object (), EventArgs.Empty});
- app.Dispose ();
+ app.DisposeInternal ();
+ app_type = null;
}
//
theFactory.FireOnAppEnd ();
}
-#if !TARGET_JVM
static FileSystemWatcher CreateWatcher (string file, FileSystemEventHandler hnd, RenamedEventHandler reh)
{
FileSystemWatcher watcher = new FileSystemWatcher ();
watcher.Path = Path.GetFullPath (Path.GetDirectoryName (file));
watcher.Filter = Path.GetFileName (file);
-
+
+ // This will enable the Modify flag for Linux/inotify
+ watcher.NotifyFilter |= NotifyFilters.Size;
+
watcher.Changed += hnd;
watcher.Created += hnd;
watcher.Deleted += hnd;
return watcher;
}
- void OnAppFileRenamed (object sender, RenamedEventArgs args)
- {
- OnAppFileChanged (sender, args);
- }
-
- void OnAppFileChanged (object sender, FileSystemEventArgs args)
- {
- if (config_watcher != null)
- config_watcher.EnableRaisingEvents = false;
- if (bin_watcher != null)
- bin_watcher.EnableRaisingEvents = false;
- if (app_file_watcher != null)
- app_file_watcher.EnableRaisingEvents = false;
- HttpRuntime.UnloadAppDomain ();
- }
-#endif
-
internal static void AttachEvents (HttpApplication app)
{
HttpApplicationFactory factory = theFactory;
int length = method.GetParameters ().Length;
if (length == 0) {
- NoParamsInvoker npi = new NoParamsInvoker (app, method.Name);
+ NoParamsInvoker npi = new NoParamsInvoker (app, method);
evt.AddEventHandler (target, npi.FakeDelegate);
} else {
evt.AddEventHandler (target, Delegate.CreateDelegate (
- evt.EventHandlerType, app, method.Name));
+ evt.EventHandlerType, app,
+#if NET_2_0
+ method
+#else
+ method.Name
+#endif
+ ));
}
+
}
internal static void InvokeSessionEnd (object state)
+ {
+ InvokeSessionEnd (state, null, EventArgs.Empty);
+ }
+
+ internal static void InvokeSessionEnd (object state, object source, EventArgs e)
{
HttpApplicationFactory factory = theFactory;
MethodInfo method = null;
app.SetSession ((HttpSessionState) state);
try {
- method.Invoke (app, new object [] {app, EventArgs.Empty});
+ method.Invoke (app, new object [] {(source == null ? app : source), e});
} catch (Exception) {
// Ignore
}
#endif
}
- public static void SetCustomApplication (IHttpHandler customApplication)
- {
- theFactory.custom_application = customApplication;
- }
-
internal static Type AppType {
get {
return theFactory.app_type;
}
}
-
+
void InitType (HttpContext context)
{
- lock (this) {
+ lock (this_lock) {
if (!needs_init)
return;
-
- string physical_app_path = context.Request.PhysicalApplicationPath;
- string app_file;
-
- app_file = Path.Combine (physical_app_path, "Global.asax");
- if (!File.Exists (app_file))
- app_file = Path.Combine (physical_app_path, "global.asax");
-
#if NET_2_0
- WebConfigurationManager.Init ();
-#else
- WebConfigurationSettings.Init (context);
+ try {
#endif
-
- if (File.Exists (app_file)) {
-#if TARGET_J2EE
- app_type = System.Web.J2EE.PageMapper.GetObjectType(app_file);
-#else
- app_type = ApplicationFileParser.GetCompiledApplicationType (app_file, context);
- if (app_type == null) {
- string msg = String.Format ("Error compiling application file ({0}).", app_file);
- throw new ApplicationException (msg);
+ string physical_app_path = HttpRuntime.AppDomainAppPath;
+ string app_file = null;
+
+ app_file = Path.Combine (physical_app_path, "Global.asax");
+ if (!File.Exists (app_file)) {
+ app_file = Path.Combine (physical_app_path, "global.asax");
+ if (!File.Exists (app_file))
+ app_file = null;
}
+
+#if !NET_2_0
+ WebConfigurationSettings.Init (context);
#endif
- } else {
- app_type = typeof (System.Web.HttpApplication);
- app_state = new HttpApplicationState ();
- }
-
-#if !TARGET_JVM
- FileSystemEventHandler fseh = new FileSystemEventHandler (OnAppFileChanged);
- RenamedEventHandler reh = new RenamedEventHandler (OnAppFileRenamed);
- app_file_watcher = CreateWatcher (app_file, fseh, reh);
+
+#if NET_2_0 && !TARGET_J2EE
+ AppResourcesCompiler ac = new AppResourcesCompiler (context);
+ ac.Compile ();
- string config_file = Path.Combine (physical_app_path, "Web.config");
- if (!File.Exists (config_file))
- config_file = Path.Combine (physical_app_path, "web.config");
+#if WEBSERVICES_DEP
+ AppWebReferencesCompiler awrc = new AppWebReferencesCompiler ();
+ awrc.Compile ();
+#endif
+
+ // Todo: Generate profile properties assembly from Web.config here
+
+ AppCodeCompiler acc = new AppCodeCompiler ();
+ acc.Compile ();
+
+ // Note whether there are any App_Browsers/*.browser files. If there
+ // are we will be using *.browser files for sniffing in addition to browscap.ini
+ string app_browsers_path = Path.Combine (physical_app_path, "App_Browsers");
+ app_browsers_files = new string[0];
+ if (Directory.Exists (app_browsers_path)) {
+ app_browsers_files = Directory.GetFiles (app_browsers_path, "*.browser");
+ }
+#endif
- config_watcher = CreateWatcher (config_file, fseh, reh);
+ if (app_file != null) {
+#if TARGET_J2EE
+ app_file = System.Web.Util.UrlUtils.ResolveVirtualPathFromAppAbsolute("~/" + Path.GetFileName(app_file));
+ app_type = System.Web.J2EE.PageMapper.GetObjectType(context, app_file);
+#else
+#if NET_2_0
+ app_type = BuildManager.GetCompiledType ("~/" + Path.GetFileName (app_file));
+#else
+ app_type = ApplicationFileParser.GetCompiledApplicationType (app_file, context);
#endif
- needs_init = false;
+#endif
+ if (app_type == null) {
+ string msg = String.Format ("Error compiling application file ({0}).", app_file);
+ throw new ApplicationException (msg);
+ }
+ } else {
+ app_type = typeof (System.Web.HttpApplication);
+ app_state = new HttpApplicationState ();
+ }
+ WatchLocationForRestart("Global.asax");
+ WatchLocationForRestart("global.asax");
+ WatchLocationForRestart("Web.config");
+ WatchLocationForRestart("web.config");
+ WatchLocationForRestart("Web.Config");
+ needs_init = false;
+#if NET_2_0
+ } catch (Exception) {
+ if (BuildManager.CodeAssemblies != null)
+ BuildManager.CodeAssemblies.Clear ();
+ if (BuildManager.TopLevelAssemblies != null)
+ BuildManager.TopLevelAssemblies.Clear ();
+ if (WebConfigurationManager.ExtraAssemblies != null)
+ WebConfigurationManager.ExtraAssemblies.Clear ();
+ throw;
+ }
+#endif
+
//
// Now init the settings
//
//
internal static HttpApplication GetApplication (HttpContext context)
{
+#if TARGET_J2EE
+ if (context.ApplicationInstance!=null)
+ return context.ApplicationInstance;
+#endif
HttpApplicationFactory factory = theFactory;
HttpApplication app = null;
if (factory.app_start_needed){
factory.InitType (context);
lock (factory) {
if (factory.app_start_needed) {
-#if !TARGET_JVM
- string bin = HttpRuntime.BinDirectory;
- if (Directory.Exists (bin))
- bin = Path.Combine (bin, "*.dll");
-
- FileSystemEventHandler fseh = new FileSystemEventHandler (factory.OnAppFileChanged);
- RenamedEventHandler reh = new RenamedEventHandler (factory.OnAppFileRenamed);
- // We watch bin or bin/*.dll if the directory exists
- factory.bin_watcher = CreateWatcher (bin, fseh, reh);
+ foreach (string dir in HttpApplication.BinDirs)
+ WatchLocationForRestart (dir, "*.dll");
+#if NET_2_0
+ // Restart if the App_* directories are created...
+ WatchLocationForRestart (".", "App_Code");
+ WatchLocationForRestart (".", "App_Browsers");
+ WatchLocationForRestart (".", "App_GlobalResources");
+ // ...or their contents is changed.
+ WatchLocationForRestart ("App_Code", "*", true);
+ WatchLocationForRestart ("App_Browsers", "*");
+ WatchLocationForRestart ("App_GlobalResources", "*");
#endif
- app = factory.FireOnAppStart (context);
+ app = factory.FireOnAppStart (context);
factory.app_start_needed = false;
return app;
}
internal static bool ContextAvailable {
get { return theFactory != null && !theFactory.app_start_needed; }
}
+
+
+ internal static bool WatchLocationForRestart (string filter)
+ {
+ return WatchLocationForRestart ("", filter, false);
+ }
+
+ internal static bool WatchLocationForRestart (string virtualPath, string filter)
+ {
+ return WatchLocationForRestart (virtualPath, filter, false);
+ }
+
+ internal static bool WatchLocationForRestart(string virtualPath, string filter, bool watchSubdirs)
+ {
+ // map the path to the physical one
+ string physicalPath = HttpRuntime.AppDomainAppPath;
+ physicalPath = Path.Combine(physicalPath, virtualPath);
+ bool isDir = Directory.Exists(physicalPath);
+ bool isFile = isDir ? false : File.Exists(physicalPath);
+
+ if (isDir || isFile) {
+ // create the watcher
+ FileSystemEventHandler fseh = new FileSystemEventHandler(OnFileChanged);
+ RenamedEventHandler reh = new RenamedEventHandler(OnFileRenamed);
+ FileSystemWatcher watcher = CreateWatcher(Path.Combine(physicalPath, filter), fseh, reh);
+ if (isDir)
+ watcher.IncludeSubdirectories = watchSubdirs;
+
+ lock (watchers_lock) {
+ watchers.Add(watcher);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+#if NET_2_0
+ internal static bool ApplicationDisabled {
+ get { return app_disabled; }
+ set { app_disabled = value; }
+ }
+
+ internal static string[] AppBrowsersFiles {
+ get { return app_browsers_files; }
+ }
+
+ static System.Web.Configuration.nBrowser.Build capabilities_processor = null;
+ static object capabilities_processor_lock = new object();
+ internal static System.Web.Configuration.ICapabilitiesProcess CapabilitiesProcessor {
+ get {
+ lock (capabilities_processor_lock) {
+ if (capabilities_processor == null) {
+ capabilities_processor = new System.Web.Configuration.nBrowser.Build();
+ string machine_browsers_path = Path.Combine (HttpRuntime.MachineConfigurationDirectory, "Browsers");
+ if (Directory.Exists (machine_browsers_path)) {
+ string[] machine_browsers_files
+ = Directory.GetFiles (machine_browsers_path, "*.browser");
+ foreach (string f in machine_browsers_files) {
+ capabilities_processor.AddBrowserFile(f);
+ }
+ }
+ foreach (string f in app_browsers_files) {
+ capabilities_processor.AddBrowserFile(f);
+ }
+ }
+ }
+ return capabilities_processor;
+ }
+ }
+#endif
+
+ internal static void DisableWatchers ()
+ {
+ lock (watchers_lock) {
+ foreach (FileSystemWatcher watcher in watchers)
+ watcher.EnableRaisingEvents = false;
+ }
+ }
+
+ internal static void EnableWatchers ()
+ {
+ lock (watchers_lock) {
+ foreach (FileSystemWatcher watcher in watchers)
+ watcher.EnableRaisingEvents = true;
+ }
+ }
+
+ static void OnFileRenamed(object sender, RenamedEventArgs args)
+ {
+ OnFileChanged(sender, args);
+ }
+
+ static void OnFileChanged(object sender, FileSystemEventArgs args)
+ {
+ lock (watchers_lock) {
+ if(app_shutdown)
+ return;
+ app_shutdown = true;
+
+ // Disable event raising to avoid concurrent restarts
+ DisableWatchers ();
+
+ // Restart application
+ HttpRuntime.UnloadAppDomain();
+ }
+ }
}
}