Add a more functional (i.e. fewer-stubs) implementation of System.Data.Linq.
[mono.git] / mcs / class / System.Web / System.Web / HttpRuntime.cs
1 //
2 // System.Web.HttpRuntime.cs 
3 // 
4 // Author:
5 //      Miguel de Icaza (miguel@novell.com)
6 //
7 //
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 //
31 // TODO: Call HttpRequest.CloseInputStream when we finish a request, as we are using the IntPtr stream.
32 //
33 using System.IO;
34 using System.Text;
35 using System.Globalization;
36 using System.Collections;
37 using System.Reflection;
38 using System.Security;
39 using System.Security.Permissions;
40 using System.Web.Caching;
41 using System.Web.Configuration;
42 using System.Web.UI;
43 using System.Web.Util;
44 #if MONOWEB_DEP
45 using Mono.Web.Util;
46 #endif
47 using System.Threading;
48 #if TARGET_J2EE
49 using Mainsoft.Web;
50 #endif
51
52 #if NET_2_0 && !TARGET_JVM
53 using System.CodeDom.Compiler;
54 using System.Web.Compilation;
55 #endif
56
57 namespace System.Web {
58         
59         // CAS - no InheritanceDemand here as the class is sealed
60         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
61         public sealed class HttpRuntime {
62                 static bool caseInsensitive;
63                 static bool runningOnWindows;
64                 static bool isunc;
65 #if TARGET_J2EE
66                 static QueueManager queue_manager { get { return _runtime._queue_manager; } }
67                 static TraceManager trace_manager { get { return _runtime._trace_manager; } }
68                 static Cache cache { get { return _runtime._cache; } }
69                 static Cache internalCache { get { return _runtime._internalCache; } }
70                 static WaitCallback do_RealProcessRequest;
71                 
72                 QueueManager _queue_manager;
73                 TraceManager _trace_manager;
74                 Cache _cache;
75                 Cache _internalCache;
76
77                 public HttpRuntime ()
78                 {
79                         WebConfigurationManager.Init ();
80                         _queue_manager = new QueueManager ();
81                         _trace_manager = new TraceManager ();
82                         _cache = new Cache ();
83                         _internalCache = new Cache();
84                         _internalCache.DependencyCache = _cache;
85                 }
86
87                 static HttpRuntime _runtimeInstance {
88                         get {
89                                 HttpRuntime runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
90                                 if (runtime == null)
91                                         lock (typeof (HttpRuntime)) {
92                                                 runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
93                                                 if (runtime == null) {
94                                                         runtime = new HttpRuntime ();
95                                                         AppDomain.CurrentDomain.SetData ("HttpRuntime", runtime);
96                                                 }
97                                         }
98                                 return runtime;
99                         }
100                 }
101                 static HttpRuntime _runtime
102                 {
103                         get
104                         {
105                                 if (HttpContext.Current != null)
106                                         return HttpContext.Current.HttpRuntimeInstance;
107                                 else
108                                         return _runtimeInstance;
109                         }
110                 }
111 #else
112                 static QueueManager queue_manager;
113                 static TraceManager trace_manager;
114                 static Cache cache;
115                 static Cache internalCache;
116                 static WaitCallback do_RealProcessRequest;
117                 static Exception initialException;
118                 static bool firstRun;
119                 
120 #if NET_2_0
121                 static bool assemblyMappingEnabled;
122                 static object assemblyMappingLock = new object ();
123                 static object appOfflineLock = new object ();
124 #endif
125                 
126 #if ONLY_1_1
127                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
128 #endif
129                 public HttpRuntime ()
130                 {
131
132                 }
133 #endif
134
135                 static HttpRuntime ()
136                 {
137                         PlatformID pid = Environment.OSVersion.Platform;
138                         runningOnWindows = ((int) pid != 128
139 #if NET_2_0
140                                             && pid != PlatformID.Unix && pid != PlatformID.MacOSX
141 #endif
142                         );
143
144                         if (runningOnWindows) {
145                                 caseInsensitive = true;
146                                 isunc = new Uri (AppDomainAppPath).IsUnc;
147                         } else {
148                                 string mono_iomap = Environment.GetEnvironmentVariable ("MONO_IOMAP");
149                                 if (mono_iomap != null) {
150                                         if (mono_iomap == "all")
151                                                 caseInsensitive = true;
152                                         else {
153                                                 string[] parts = mono_iomap.Split (':');
154                                                 foreach (string p in parts) {
155                                                         if (p == "all" || p == "case") {
156                                                                 caseInsensitive = true;
157                                                                 break;
158                                                         }
159                                                 }
160                                         }
161                                 }
162                         }
163                         
164 #if !TARGET_J2EE
165                         firstRun = true;
166 #if NET_2_0
167                         try {
168                                 WebConfigurationManager.Init ();
169 #if MONOWEB_DEP
170                                 SettingsMappingManager.Init ();
171 #endif
172                         } catch (Exception ex) {
173                                 initialException = ex;
174                         }
175 #endif
176
177                         // The classes in whose constructors exceptions may be thrown, should be handled the same way QueueManager
178                         // and TraceManager are below. The constructors themselves MUST NOT throw any exceptions - we MUST be sure
179                         // the objects are created here. The exceptions will be dealt with below, in RealProcessRequest.
180                         queue_manager = new QueueManager ();
181                         if (queue_manager.HasException)
182                                 initialException = queue_manager.InitialException;
183
184                         trace_manager = new TraceManager ();
185                         if (trace_manager.HasException)
186                                         initialException = trace_manager.InitialException;
187
188                         cache = new Cache ();
189                         internalCache = new Cache ();
190                         internalCache.DependencyCache = cache;
191 #endif
192                         do_RealProcessRequest = new WaitCallback (RealProcessRequest);
193                 }
194                 
195 #region AppDomain handling
196                 //
197                 // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
198                 //
199                 public static string AppDomainAppId {
200                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
201                         get {
202                                 //
203                                 // This value should not change across invocations
204                                 //
205                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".appId");
206                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
207                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
208                                 }
209                                 return dirname;
210                         }
211                 }
212
213                 // Physical directory for the application
214                 public static string AppDomainAppPath {
215                         get {
216                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".appPath");
217                                 if (SecurityManager.SecurityEnabled) {
218                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
219                                 }
220                                 return dirname;
221                         }
222                 }
223
224                 public static string AppDomainAppVirtualPath {
225                         get {
226                                 return (string) AppDomain.CurrentDomain.GetData (".appVPath");
227                         }
228                 }
229
230                 public static string AppDomainId {
231                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
232                         get {
233                                 return (string) AppDomain.CurrentDomain.GetData (".domainId");
234                         }
235                 }
236
237                 public static string AspInstallDirectory {
238                         get {
239                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".hostingInstallDir");
240                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
241                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
242                                 }
243                                 return dirname;
244                         }
245                 }
246 #endregion
247
248                 static string _actual_bin_directory;
249                 public static string BinDirectory {
250                         get {
251                                 if (_actual_bin_directory == null) {
252                                         string[] parts = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath.Split (';');
253                                         string mypath = AppDomainAppPath;
254                                         string tmp;
255                                         
256                                         foreach (string p in parts) {
257                                                 tmp = Path.Combine (mypath, p);
258                                                 if (Directory.Exists (tmp)) {
259                                                         _actual_bin_directory = tmp;
260                                                         break;
261                                                 }
262                                         }
263
264                                         if (_actual_bin_directory == null)
265                                                 _actual_bin_directory = Path.Combine (mypath, "bin");
266
267                                         if (_actual_bin_directory [_actual_bin_directory.Length - 1] != Path.DirectorySeparatorChar)
268                                                 _actual_bin_directory += Path.DirectorySeparatorChar;
269                                 }
270                                 
271                                 if (SecurityManager.SecurityEnabled)
272                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, _actual_bin_directory).Demand ();
273
274                                 return _actual_bin_directory;
275                         }
276                 }
277
278                 public static Cache Cache {
279                         get {
280                                 return cache;
281                         }
282                 }
283
284                 internal static Cache InternalCache {
285                         get {
286                                 return internalCache;
287                         }
288                 }
289                 
290                 public static string ClrInstallDirectory {
291                         get {
292                                 string dirname = Path.GetDirectoryName (typeof (Object).Assembly.Location);
293                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
294                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
295                                 }
296                                 return dirname;
297                         }
298                 }
299
300                 public static string CodegenDir {
301                         get {
302                                 string dirname = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
303                                 if (SecurityManager.SecurityEnabled) {
304                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
305                                 }
306                                 return dirname;
307                         }
308                 }
309
310                 public static bool IsOnUNCShare {
311                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
312                         get {
313                                 return isunc;
314                         }
315                 }
316
317                 public static string MachineConfigurationDirectory {
318                         get {
319                                 string dirname = Path.GetDirectoryName (ICalls.GetMachineConfigPath ());
320                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
321                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
322                                 }
323                                 return dirname;
324                         }
325                 }
326
327                 
328                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
329                 public static void Close ()
330                 {
331                         // Remove all items from cache.
332                 }
333
334                 static void QueuePendingRequests ()
335                 {
336                         HttpWorkerRequest request = queue_manager.GetNextRequest (null);
337                         if (request == null)
338                                 return;
339                         ThreadPool.QueueUserWorkItem (do_RealProcessRequest, request);
340                 }
341
342 #if !TARGET_J2EE
343 #if NET_2_0
344                 static readonly string[] app_offline_files = {"app_offline.htm", "App_Offline.htm", "APP_OFFLINE.HTM"};
345                 static string app_offline_file;
346                 
347                 static bool AppIsOffline (HttpContext context)
348                 {
349                         if (!HttpApplicationFactory.ApplicationDisabled || app_offline_file == null)
350                                 return false;
351
352                         HttpResponse response = context.Response;
353                         response.Clear ();
354                         response.ContentType = "text/html";
355                         response.ExpiresAbsolute = DateTime.UtcNow;
356                         response.StatusCode = 503;
357                         response.TransmitFile (app_offline_file, true);
358                         
359                         context.Request.ReleaseResources ();
360                         context.Response.ReleaseResources ();
361                         HttpContext.Current = null;
362                         HttpApplication.requests_total_counter.Increment ();
363                         
364                         return true;
365                 }
366
367                 static void AppOfflineFileRenamed (object sender, RenamedEventArgs args)
368                 {
369                         AppOfflineFileChanged (sender, args);
370                 }
371
372                 static void AppOfflineFileChanged (object sender, FileSystemEventArgs args)
373                 {
374                         lock (appOfflineLock) {
375                                 bool offline;
376                                 
377                                 switch (args.ChangeType) {
378                                         case WatcherChangeTypes.Created:
379                                         case WatcherChangeTypes.Changed:
380                                                 offline = true;
381                                                 break;
382
383                                         case WatcherChangeTypes.Deleted:
384                                                 offline = false;
385                                                 break;
386
387                                         case WatcherChangeTypes.Renamed:
388                                                 RenamedEventArgs rargs = args as RenamedEventArgs;
389
390                                                 if (rargs != null &&
391                                                     String.Compare (rargs.Name, "app_offline.htm", StringComparison.OrdinalIgnoreCase) == 0)
392                                                         offline = true;
393                                                 else
394                                                         offline = false;
395                                                 break;
396
397                                         default:
398                                                 offline = false;
399                                                 break;
400                                 }
401                                 SetOfflineMode (offline, args.FullPath);
402                         }
403                 }
404
405                 static void SetOfflineMode (bool offline, string filePath)
406                 {
407                         if (!offline) {
408                                 app_offline_file = null;
409                                 if (HttpApplicationFactory.ApplicationDisabled)
410                                         HttpRuntime.UnloadAppDomain ();
411                         } else {
412                                 app_offline_file = filePath;
413                                 HttpApplicationFactory.DisableWatchers ();
414                                 HttpApplicationFactory.ApplicationDisabled = true;
415                                 InternalCache.InvokePrivateCallbacks ();
416                                 HttpApplicationFactory.Dispose ();
417                         }
418                 }
419                 
420                 static void SetupOfflineWatch ()
421                 {
422                         lock (appOfflineLock) {
423                                 FileSystemEventHandler seh = new FileSystemEventHandler (AppOfflineFileChanged);
424                                 RenamedEventHandler reh = new RenamedEventHandler (AppOfflineFileRenamed);
425
426                                 string app_dir = AppDomainAppPath;
427                                 ArrayList watchers = new ArrayList ();
428                                 FileSystemWatcher watcher;
429                                 string offlineFile = null, tmp;
430                                 
431                                 foreach (string f in app_offline_files) {
432                                         watcher = new FileSystemWatcher ();
433                                         watcher.Path = Path.GetDirectoryName (app_dir);
434                                         watcher.Filter = Path.GetFileName (f);
435                                         watcher.NotifyFilter |= NotifyFilters.Size;
436                                         watcher.Deleted += seh;
437                                         watcher.Changed += seh;
438                                         watcher.Created += seh;
439                                         watcher.Renamed += reh;
440                                         watcher.EnableRaisingEvents = true;
441                                         
442                                         watchers.Add (watcher);
443
444                                         tmp = Path.Combine (app_dir, f);
445                                         if (File.Exists (tmp))
446                                                 offlineFile = tmp;
447                                 }
448
449                                 if (offlineFile != null)
450                                         SetOfflineMode (true, offlineFile);
451                         }
452                 }
453 #endif
454 #endif
455                 
456                 static void RealProcessRequest (object o)
457                 {
458 #if TARGET_J2EE
459                         HttpContext context = HttpContext.Current;
460                         if (context == null)
461                                 context = new HttpContext ((HttpWorkerRequest) o);
462                         else
463                                 context.SetWorkerRequest ((HttpWorkerRequest) o);
464 #else
465                         HttpContext context = new HttpContext ((HttpWorkerRequest) o);
466 #endif
467                         HttpContext.Current = context;
468                         bool error = false;
469 #if !TARGET_J2EE
470                         if (firstRun) {
471 #if NET_2_0
472                                 SetupOfflineWatch ();
473 #endif
474                                 firstRun = false;
475                                 if (initialException != null) {
476                                         FinishWithException ((HttpWorkerRequest) o, new HttpException ("Initial exception", initialException));
477                                         error = true;
478                                 }
479                         }
480
481 #if NET_2_0
482                         if (AppIsOffline (context))
483                                 return;
484 #endif
485 #endif
486                         
487                         //
488                         // Get application instance (create or reuse an instance of the correct class)
489                         //
490                         HttpApplication app = null;
491                         if (!error) {
492                                 try {
493                                         app = HttpApplicationFactory.GetApplication (context);
494                                 } catch (Exception e) {
495                                         FinishWithException ((HttpWorkerRequest) o, new HttpException ("", e));
496                                         error = true;
497                                 }
498                         }
499                         
500                         if (error) {
501                                 context.Request.ReleaseResources ();
502                                 context.Response.ReleaseResources ();
503                                 HttpContext.Current = null;
504                         } else {
505                                 context.ApplicationInstance = app;
506
507                                 //
508                                 // Ask application to service the request
509                                 //
510                                 
511 #if TARGET_J2EE
512                                 IHttpAsyncHandler ihah = app;
513                                 if (context.Handler == null)
514                                         ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
515                                 else
516                                         app.Tick ();
517                                 //ihh.ProcessRequest (context);
518                                 IHttpExtendedHandler extHandler = context.Handler as IHttpExtendedHandler;
519                                 if (extHandler != null && !extHandler.IsCompleted)
520                                         return;
521                                 if (context.Error is UnifyRequestException)
522                                         return;
523
524                                 ihah.EndProcessRequest (null);
525 #else
526                                 IHttpHandler ihh = app;
527 //                              IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
528 //                              ihah.EndProcessRequest (appiar);
529                                 ihh.ProcessRequest (context);
530 #endif
531
532                                 HttpApplicationFactory.Recycle (app);
533                         }
534                         
535                         QueuePendingRequests ();
536                 }
537                 
538                 //
539                 // ProcessRequest method is executed in the AppDomain of the application
540                 //
541                 // Observations:
542                 //    ProcessRequest does not guarantee that `wr' will be processed synchronously,
543                 //    the request can be queued and processed later.
544                 //
545                 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
546                 public static void ProcessRequest (HttpWorkerRequest wr)
547                 {
548                         if (wr == null)
549                                 throw new ArgumentNullException ("wr");
550                         //
551                         // Queue our request, fetch the next available one from the queue
552                         //
553                         HttpWorkerRequest request = queue_manager.GetNextRequest (wr);
554                         if (request == null)
555                                 return;
556
557                         RealProcessRequest (request);
558                 }
559
560 #if TARGET_J2EE
561                 //
562                 // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
563                 //
564                 static void request_processed (IAsyncResult iar)
565                 {
566                         HttpContext context = (HttpContext) iar.AsyncState;
567
568                         context.Request.ReleaseResources ();
569                         context.Response.ReleaseResources ();
570                 }
571 #endif
572                 
573 #if TARGET_JVM
574                 [MonoNotSupported ("UnloadAppDomain is not supported")]
575                 public static void UnloadAppDomain ()
576                 {
577                         throw new NotImplementedException ("UnloadAppDomain is not supported");
578                 }
579 #else
580                 //
581                 // Called when we are shutting down or we need to reload an application
582                 // that has been modified (touch global.asax) 
583                 //
584                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
585                 public static void UnloadAppDomain ()
586                 {
587                         //
588                         // TODO: call ReleaseResources
589                         //
590                         ThreadPool.QueueUserWorkItem (new WaitCallback (ShutdownAppDomain), null);
591                 }
592 #endif
593                 //
594                 // Shuts down the AppDomain
595                 //
596                 static void ShutdownAppDomain (object args)
597                 {
598                         queue_manager.Dispose ();
599                         // This will call Session_End if needed.
600                         InternalCache.InvokePrivateCallbacks ();
601                         // Kill our application.
602                         HttpApplicationFactory.Dispose ();
603                         ThreadPool.QueueUserWorkItem (new WaitCallback (DoUnload), null);
604                 }
605
606                 static void DoUnload (object state)
607                 {
608                         if (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") == null)
609                                 System.Web.Hosting.ApplicationHost.ClearDynamicBaseDirectory (
610                                         AppDomain.CurrentDomain.SetupInformation.DynamicBase
611                                 );
612 #if TARGET_J2EE
613                         // No unload support for appdomains under Grasshopper
614 #else
615                         AppDomain.Unload (AppDomain.CurrentDomain);
616 #endif
617                 }
618
619                 static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
620                         "<html><head>\n<title>503 Server Unavailable</title>\n</head><body>\n" +
621                         "<h1>Server Unavailable</h1>\n" +
622                         "</body></html>\n";
623
624                 static void FinishWithException (HttpWorkerRequest wr, HttpException e)
625                 {
626                         int code = e.GetHttpCode ();
627                         wr.SendStatus (code, HttpWorkerRequest.GetStatusDescription (code));
628                         wr.SendUnknownResponseHeader ("Connection", "close");
629                         Encoding enc = Encoding.ASCII;
630                         wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
631                         string msg = e.GetHtmlErrorMessage ();
632                         byte [] contentBytes = enc.GetBytes (msg);
633                         wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
634                         wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
635                         wr.FlushResponse (true);
636                         wr.CloseConnection ();
637                         HttpApplication.requests_total_counter.Increment ();
638                 }
639
640                 //
641                 // This is called from the QueueManager if a request
642                 // can not be processed (load, no resources, or
643                 // appdomain unload).
644                 //
645                 static internal void FinishUnavailable (HttpWorkerRequest wr)
646                 {
647                         wr.SendStatus (503, "Service unavailable");
648                         wr.SendUnknownResponseHeader ("Connection", "close");
649                         Encoding enc = Encoding.ASCII;
650                         wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
651                         byte [] contentBytes = enc.GetBytes (content503);
652                         wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
653                         wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
654                         wr.FlushResponse (true);
655                         wr.CloseConnection ();
656                         HttpApplication.requests_total_counter.Increment ();
657                 }
658
659 #if NET_2_0 
660 #if !TARGET_J2EE
661                 static internal void WritePreservationFile (Assembly asm, string genericNameBase)
662                 {
663                         if (asm == null)
664                                 throw new ArgumentNullException ("asm");
665                         if (String.IsNullOrEmpty (genericNameBase))
666                                 throw new ArgumentNullException ("genericNameBase");
667
668                         string compiled = Path.Combine (AppDomain.CurrentDomain.SetupInformation.DynamicBase,
669                                                         genericNameBase + ".compiled");
670                         PreservationFile pf = new PreservationFile ();
671                         try {
672                                 pf.VirtualPath = String.Concat ("/", genericNameBase, "/");
673
674                                 AssemblyName an = asm.GetName ();
675                                 pf.Assembly = an.Name;
676                                 pf.ResultType = BuildResultTypeCode.TopLevelAssembly;
677                                 pf.Save (compiled);
678                         } catch (Exception ex) {
679                                 throw new HttpException (
680                                         String.Format ("Failed to write preservation file {0}", genericNameBase + ".compiled"),
681                                         ex);
682                         }
683                 }
684                 
685                 static Assembly ResolveAssemblyHandler(object sender, ResolveEventArgs e)
686                 {
687                         AssemblyName an = new AssemblyName (e.Name);
688                         string dynamic_base = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
689                         string compiled = Path.Combine (dynamic_base, an.Name + ".compiled");
690
691                         if (!File.Exists (compiled))
692                                 return null;
693
694                         PreservationFile pf;
695                         try {
696                                 pf = new PreservationFile (compiled);
697                         } catch (Exception ex) {
698                                 throw new HttpException (
699                                         String.Format ("Failed to read preservation file {0}", an.Name + ".compiled"),
700                                         ex);
701                         }
702                         
703                         Assembly ret = null;
704                         try {
705                                 string asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
706                                 ret = Assembly.LoadFrom (asmPath);
707                         } catch (Exception) {
708                                 // ignore
709                         }
710                         
711                         return ret;
712                 }
713                 
714                 internal static void EnableAssemblyMapping (bool enable)
715                 {
716                         lock (assemblyMappingLock) {
717                                 if (assemblyMappingEnabled == enable)
718                                         return;
719                                 if (enable)
720                                         AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyHandler);
721                                 else
722                                         AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler (ResolveAssemblyHandler);
723                         }
724                 }
725 #endif // #if !TARGET_J2EE
726 #endif
727                 internal static bool RunningOnWindows {
728                         get { return runningOnWindows; }
729                 }
730
731                 internal static bool CaseInsensitive {
732                         get { return caseInsensitive; }
733                 }
734
735         
736                 internal static TraceManager TraceManager {
737                         get {
738                                 return trace_manager;
739                         }
740                 }
741         }
742 }