/// <summary> /// ISU and internal use only. /// </summary> public static void StopIisAppPool(string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var pool = serverManager.ApplicationPools[name]; if (pool != null) { // Stop throws an exception if the pool isn't started. if (pool.State != enumGetter("Microsoft.Web.Administration.ObjectState", "Stopped") && pool.State != enumGetter("Microsoft.Web.Administration.ObjectState", "Stopping")) { pool.Stop(); } while (pool.State != enumGetter("Microsoft.Web.Administration.ObjectState", "Stopped")) { Thread.Sleep(1000); } pool.AutoStart = false; } })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void UpdateIisAppPool(string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var pool = serverManager.ApplicationPools[name] ?? serverManager.ApplicationPools.Add(name); pool.AutoStart = false; })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void DeleteIisAppPool(string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var pool = serverManager.ApplicationPools[name]; if (pool != null) { serverManager.ApplicationPools.Remove(pool); } })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void DeleteIisSite(string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var site = serverManager.Sites[name]; if (site != null) { serverManager.Sites.Remove(site); } })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void DeleteIisVirtualDirectory(string site, string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var iisSite = serverManager.Sites[site]; var path = "/{0}".FormatWith(name); var app = iisSite.Applications[path]; if (app != null) { iisSite.Applications.Remove(app); } })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void StartIisAppPool(string name) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var pool = serverManager.ApplicationPools[name]; pool.Start(); while (pool.State != enumGetter("Microsoft.Web.Administration.ObjectState", "Started")) { Thread.Sleep(1000); } pool.AutoStart = true; })); }
/// <summary> /// ISU and internal use only. /// </summary> public static void UpdateIisVirtualDirectory(string site, string name, string appPool, string physicalPath) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { var iisSite = serverManager.Sites[site]; var path = "/{0}".FormatWith(name); var app = iisSite.Applications[path] ?? iisSite.Applications.Add(path, physicalPath); app.ApplicationPoolName = appPool; app["preloadEnabled"] = true; var rootVd = app.VirtualDirectories["/"]; rootVd.PhysicalPath = physicalPath; })); }
/// <summary> /// Standard Library and RSIS use only. /// </summary> public static void ConfigureIis(bool iisExpress) { // Overlapping commitment of changes to server manager do not end well. AppTools.ExecuteAsCriticalRegion( "{1BC5B312-F0F0-11DF-B6B9-118ADFD72085}", false, delegate { try { IisConfigurationStatics.ConfigureIis(iisExpress); } catch (Exception e) { const string message = "Failed to configure IIS."; if (e is UnauthorizedAccessException) { throw new UserCorrectableException(message, e); } throw new ApplicationException(message, e); } }); }
private static void configureIis(bool iisExpress, bool useServerAppPoolSettings) { IisConfigurationStatics.ExecuteInServerManagerTransaction( iisExpress, (serverManager, enumGetter) => { if (!iisExpress) { var poolDefaults = serverManager.ApplicationPoolDefaults; poolDefaults.StartMode = enumGetter("Microsoft.Web.Administration.StartMode", useServerAppPoolSettings ? "AlwaysRunning" : "OnDemand"); // We use this because it's a consistent account name across all machines, which allows our SQL Server databases [which must grant access to the // app pool] to be portable. poolDefaults.ProcessModel.IdentityType = enumGetter("Microsoft.Web.Administration.ProcessModelIdentityType", "NetworkService"); // Disable idle time-out. poolDefaults.ProcessModel.IdleTimeout = useServerAppPoolSettings ? TimeSpan.Zero : new TimeSpan(0, 5, 0); // Disable regular time interval recycling. poolDefaults.Recycling.PeriodicRestart.Time = TimeSpan.Zero; poolDefaults.Recycling.PeriodicRestart.Schedule.Clear(); if (useServerAppPoolSettings) { poolDefaults.Recycling.PeriodicRestart.Schedule.Add(new TimeSpan(23, 55, 0)); } } var config = serverManager.GetApplicationHostConfiguration(); var modulesSection = config.GetSection("system.webServer/modules", ""); foreach (var element in modulesSection.GetCollection()) { element.SetMetadata("lockItem", null); } var serverRuntimeSection = config.GetSection("system.webServer/serverRuntime", ""); serverRuntimeSection.OverrideMode = enumGetter("Microsoft.Web.Administration.OverrideMode", "Allow"); }); }
/// <summary> /// ISU and internal use only. /// </summary> public static void UpdateIisSite(string name, string appPool, string physicalPath, IReadOnlyCollection <IisHostName> hostNames) { executeInIisServerManagerTransaction( () => IisConfigurationStatics.ExecuteInServerManagerTransaction( false, (serverManager, enumGetter) => { const int dummyPort = 80; var site = serverManager.Sites[name] ?? serverManager.Sites.Add(name, physicalPath, dummyPort); var rootApp = site.Applications["/"]; rootApp.ApplicationPoolName = appPool; rootApp["preloadEnabled"] = true; var rootVd = rootApp.VirtualDirectories["/"]; rootVd.PhysicalPath = physicalPath; var bindings = hostNames.SelectMany( i => { var nonsecureBinding = Tuple.Create(false, i.NonsecurePortSpecified ? i.NonsecurePort : 80, i.Name); return(i.SecureBinding != null ? new[] { nonsecureBinding, Tuple.Create(true, i.SecureBinding.PortSpecified ? i.SecureBinding.Port : 443, i.Name) } : nonsecureBinding.ToCollection()); }) .ToList(); var unrecognizedBindings = new List <dynamic>(); foreach (var iisBinding in site.Bindings) { if (iisBinding.Protocol != "http" && iisBinding.Protocol != "https") { continue; } var bindingInfo = ((string)iisBinding.BindingInformation).Separate(":", false); var binding = Tuple.Create((string)iisBinding.Protocol == "https", int.Parse(bindingInfo[1]), bindingInfo[2]); if (bindings.Contains(binding) && (!binding.Item1 || iisBinding.SslFlags == enumGetter("Microsoft.Web.Administration.SslFlags", "3"))) { bindings.Remove(binding); } else { unrecognizedBindings.Add(iisBinding); } } foreach (var i in unrecognizedBindings) { site.Bindings.Remove(i); } foreach (var i in bindings) { if (i.Item1) { site.Bindings.Add( "*:{0}:{1}".FormatWith(i.Item2, i.Item3), (byte[])null, (string)null, enumGetter("Microsoft.Web.Administration.SslFlags", "3")); } else { site.Bindings.Add("*:{0}:{1}".FormatWith(i.Item2, i.Item3), "http"); } } })); }
/// <summary> /// Call this from Application_Start in your Global.asax.cs file. Besides this call, there should be no other code in the method. /// </summary> /// <param name="globalInitializer">The system's global initializer. Do not pass null.</param> /// <param name="appInitializer">The application initializer, which performs web-site specific initialization and cleanup. If you have one of these you /// should name the class AppInitializer.</param> public static void InitStatics(SystemInitializer globalInitializer, SystemInitializer appInitializer = null) { // This is a hack to support data-access state in WCF services. var wcfDataAccessState = new ThreadLocal <DataAccessState>(() => new DataAccessState()); // Initialize system. var initTimeDataAccessState = new ThreadLocal <DataAccessState>(() => new DataAccessState()); try { GlobalInitializationOps.InitStatics( globalInitializer, Path.GetFileName(Path.GetDirectoryName(HttpRuntime.AppDomainAppPath)), false, mainDataAccessStateGetter: () => { return(EwfApp.Instance != null ? EwfApp.Instance.RequestState != null ? EwfApp.Instance.RequestState.DataAccessState : initTimeDataAccessState.Value : System.ServiceModel.OperationContext.Current != null ? wcfDataAccessState.Value : null); }); } catch { // Suppress all exceptions since there is no way to report them. return; } ewlInitialized = true; // Initialize web application. if (!GlobalInitializationOps.SecondaryInitFailed) { EwfApp.ExecuteWithBasicExceptionHandling( () => { EwfConfigurationStatics.Init(); GlobalConfiguration.Configure(WebApiStatics.ConfigureWebApi); // Prevent MiniProfiler JSON exceptions caused by pages with hundreds of database queries. MiniProfiler.Settings.MaxJsonResponseSize = int.MaxValue; var globalType = BuildManager.GetGlobalAsaxType().BaseType; if (!(globalType.Assembly.CreateInstance("EnterpriseWebLibrary.EnterpriseWebFramework." + globalType.Namespace + ".MetaLogicFactory") is AppMetaLogicFactory metaLogicFactory)) { throw new ApplicationException("Meta logic factory not found."); } EwfApp.Init(globalType, metaLogicFactory); EwfPage.Init( ModalBox.CreateBrowsingModalBox, () => { var cssInfos = new List <ResourceInfo>(); cssInfos.AddRange(EwfApp.MetaLogicFactory.CreateBasicCssInfos()); if (EwfUiStatics.AppMasterPage != null) { cssInfos.AddRange(EwfApp.MetaLogicFactory.CreateEwfUiCssInfos()); } cssInfos.AddRange(EwfApp.Instance.GetStyleSheets()); if (EwfUiStatics.AppMasterPage != null) { cssInfos.AddRange(EwfUiStatics.AppProvider.GetStyleSheets()); } return(cssInfos); }); CssPreprocessingStatics.Init(globalInitializer.GetType().Assembly, globalType.Assembly); HyperlinkBehaviorExtensionCreators.Init(ModalBox.GetBrowsingModalBoxOpenStatements); EwfUiStatics.Init(globalType); EwfInitializationOps.appInitializer = appInitializer; appInitializer?.InitStatics(); initTimeDataAccessState = null; EwfApp.FrameworkInitialized = true; }, false, false); } // If initialization failed, unload and restart the application after a reasonable delay. if (!EwfApp.FrameworkInitialized) { const int unloadDelay = 60000; // milliseconds initFailureUnloadTimer = new Timer( state => EwfApp.ExecuteWithBasicExceptionHandling( () => { if (ConfigurationStatics.IsDevelopmentInstallation) { return; } HttpRuntime.UnloadAppDomain(); // Restart the application by making a request. Idea from Rick Strahl: // http://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive. // // Disable server certificate validation so that this request gets through even for web sites that don't use a certificate that is trusted by // default. There is no security risk since we're not sending any sensitive information and we're not using the response. Tewl.Tools.NetTools.ExecuteWithResponse( IisConfigurationStatics.GetFirstBaseUrlForCurrentSite(false), response => {}, disableCertificateValidation: true); }, false, false), null, unloadDelay, Timeout.Infinite); } }
/// <summary> /// Call this from Application_Start in your Global.asax.cs file. Besides this call, there should be no other code in the method. /// </summary> // We could save people the effort of calling this by using trick #1 in // http://www.paraesthesia.com/archive/2011/02/08/dynamic-httpmodule-registration-in-asp-net-4-0.aspx, but that would probably require making this a static // method and would probably also cause this method to run at start up time in *all* web applications that reference the Standard Library, even the ones // that don't want to use EWF. protected void ewfApplicationStart(SystemLogic systemLogic) { // This is a hack to support data-access state in WCF services. var wcfDataAccessState = new ThreadLocal <DataAccessState>(() => new DataAccessState()); // Initialize system. var initTimeDataAccessState = new ThreadLocal <DataAccessState>(() => new DataAccessState()); try { AppTools.Init( Path.GetFileName(Path.GetDirectoryName(HttpRuntime.AppDomainAppPath)), false, systemLogic, mainDataAccessStateGetter: () => { // We must use the Instance property here to prevent this logic from always returning the request state of the *first* EwfApp instance. return(Instance != null ? Instance.RequestState != null ? Instance.RequestState.DataAccessState : initTimeDataAccessState.Value : System.ServiceModel.OperationContext.Current != null ? wcfDataAccessState.Value : null); }); } catch { // Suppress all exceptions since there is no way to report them. return; } ewlInitialized = true; // Initialize web application. if (!AppTools.SecondaryInitFailed) { executeWithBasicExceptionHandling( () => { EwfConfigurationStatics.Init(); // Prevent MiniProfiler JSON exceptions caused by pages with hundreds of database queries. MiniProfiler.Settings.MaxJsonResponseSize = int.MaxValue; GlobalType = GetType().BaseType; MetaLogicFactory = GlobalType.Assembly.CreateInstance("RedStapler.StandardLibrary.EnterpriseWebFramework." + GlobalType.Namespace + ".MetaLogicFactory") as AppMetaLogicFactory; if (MetaLogicFactory == null) { throw new ApplicationException("Meta logic factory not found."); } // This initialization could be performed using reflection. There is no need for EwfApp to have a dependency on these classes. if (systemLogic != null) { CssPreprocessingStatics.Init(systemLogic.GetType().Assembly, GlobalType.Assembly); } else { CssPreprocessingStatics.Init(GlobalType.Assembly); } EwfUiStatics.Init(GlobalType); initializeWebApp(); initTimeDataAccessState = null; initialized = true; }, false, false); } // If initialization failed, unload and restart the application after a reasonable delay. if (!initialized) { const int unloadDelay = 60000; // milliseconds initFailureUnloadTimer = new Timer( state => executeWithBasicExceptionHandling( () => { if (AppTools.IsDevelopmentInstallation) { return; } HttpRuntime.UnloadAppDomain(); // Restart the application by making a request. Idea from Rick Strahl: // http://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive. // // Disable server certificate validation so that this request gets through even for web sites that don't use a certificate that is trusted by // default. There is no security risk since we're not sending any sensitive information and we're not using the response. NetTools.ExecuteWithResponse(IisConfigurationStatics.GetFirstBaseUrlForCurrentSite(false), response => { }, disableCertificateValidation: true); }, false, false), null, unloadDelay, Timeout.Infinite); } }