/// <summary> /// Stops the hosted ASP.NET application if one is running. /// </summary> public void Close() { lock (syncLock) { if (listener != null) { try { var lease = (ILease)listener.GetLifetimeService(); lease.Unregister(sponser); sponser = null; listener.Stop(); listener = null; } catch (AppDomainUnloadedException) { // Ignore these } } } }
/// <summary> /// Starts an in-process hosted ASP.NET application using explicit settings /// passed as parameters. /// </summary> /// <param name="uris">One or more external URIs specifying the ASP.NET application endpoints.</param> /// <param name="physicalPath">Path to the folder holding the ASP.NET application files.</param> /// <param name="copyBinAssemblies"> /// Specifies whether or not the <see cref="WebHost" /> instance should /// copy the <see cref="LillTek.Web" /> and any non-GAC referenced assemblies /// to a <b>Bin</b> folder immediately within the ASP.NET application's /// <paramref name="physicalPath" />. /// </param> private void Start(string[] uris, string physicalPath, bool copyBinAssemblies) { string virtualPath; // Make sure that all URIs passed end with "/". for (int i = 0; i < uris.Length; i++) { if (!uris[i].EndsWith("/")) { uris[i] += "/"; } } // Verify that the virtual path for all of the URIs are the same. // // Note that I'm replacing any embedded "*" or "+" HttpListener wildcards // in the URI string with the "a" character so the Uri() constructor won't // throw exceptions. virtualPath = new Uri(ConvertHostWildcards(uris[0])).AbsolutePath; for (int i = 1; i < uris.Length; i++) { if (virtualPath != new Uri(ConvertHostWildcards(uris[i])).AbsolutePath) { throw new ArgumentException("The virtual path for all URIs must be identical."); } } // Make sure the physical path ends with a slash. physicalPath = Helper.AddTrailingSlash(physicalPath); // Handle the assembly copying if requested. if (copyBinAssemblies) { var assemblies = new List <Assembly>(); var curAssembly = Assembly.GetExecutingAssembly(); // $todo(jeff.lill): // // If I was going to be really tricky here, I'd look // recursively for referenced assemblies as well. // This isn't going to be an issue right at the // moment so I'm not going to worry about this. assemblies.Add(curAssembly); foreach (AssemblyName assemblyName in curAssembly.GetReferencedAssemblies()) { var reference = Assembly.Load(assemblyName); if (reference.GlobalAssemblyCache) { continue; } assemblies.Add(reference); } if (!Directory.Exists(physicalPath + Helper.PathSepString + "Bin")) { Directory.CreateDirectory(physicalPath + Helper.PathSepString + "Bin"); } foreach (Assembly assembly in assemblies) { var srcPath = Helper.GetAssemblyPath(assembly); var dstPath = physicalPath + "Bin" + Helper.PathSepString + Path.GetFileName(srcPath); if (File.Exists(dstPath)) { File.Delete(dstPath); } File.Copy(srcPath, dstPath); } } // Crank up a HttpListenerWrapper instance in its own AppDomain. physicalPath = physicalPath.Replace('/', Helper.PathSepChar); listener = (HttpListenerWrapper)ApplicationHost.CreateApplicationHost(typeof(HttpListenerWrapper), virtualPath, physicalPath); listener.Start(uris, virtualPath, physicalPath); // Configure the client side sponser to manage // lifetime lease renewal requests from the server's // application domain. ILease lease; sponser = new ClientSponsor(TimeSpan.FromMinutes(1)); lease = (ILease)listener.GetLifetimeService(); lease.Register(sponser); }