From 8f0de60592d1528482b6b338acb039ba418b82d5 Mon Sep 17 00:00:00 2001 From: Schwirg László Date: Fri, 28 Apr 2023 18:00:58 +0200 Subject: [PATCH] - Hangfire illesztés javítva --- Vrh.Web.Reporting/Global.asax.cs | 53 ++++++++++------------------------------------------- Vrh.Web.Reporting/HangfireBootstrapper.cs | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------- Vrh.iScheduler/Monitor .cs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 369 insertions(+), 166 deletions(-) diff --git a/Vrh.Web.Reporting/Global.asax.cs b/Vrh.Web.Reporting/Global.asax.cs index 9ee6e16..b8d64b2 100644 --- a/Vrh.Web.Reporting/Global.asax.cs +++ b/Vrh.Web.Reporting/Global.asax.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; @@ -22,62 +23,28 @@ namespace Vrh.Web.Reporting { protected void Application_Start() { - var methodfullname = $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"; - - (new DCLogEntry(LogLevel.Information, methodfullname)).Write(); + (new DCLogEntry(LogLevel.Information, $"{typeof(MvcApplication).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}")).Write(); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); - ////////////////////////////////////////////////////////////////////////////////////// - ///Enable webApp pool autostart, preload and alwaysrun - ////////////////////////////////////////////////////////////////////////////////////// - /// For web applications running on servers under your control, either physical or virtual, you can use the auto-start feature of IIS ≥ 7.5 shipped with - /// Windows Server ≥ 2008 R2. Full setup requires the following steps to be done. Enable automatic start and AlwaysRunning mode for Application pool - /// and configure Auto - start feature as written below. - /// Edit the following file: C:\Windows\System32\inetsrv\config\applicationHost.config. - /// All edits should be made below the section. - /// In the section find the tag of the application pool to be autostarted. - /// Add autoStart="true" and startMode="AlwaysRunning" attributes to this tag. - /// In the section find the tag of the web application - /// running on the application pool with name "YourApplicationPoolName". - /// Add serviceAutoStartEnabled="true" and serviceAutoStartProvider="AnyNameForYourAutoStartProvider" attributes to this tag. - /// Here YourWebsiteName is the name of the website where the web application, using the application pool belongs to. - /// In the section create the following element: - /// - /// Here AnyNameForYourAutoStartProvider can be any name, that is suitable for the xml standard. - /// Here FullTypeNameOfTheAutostartProviderClass is the full type name (with namespace and class name) of the class that matches the IProcessHostPreloadClient interface; - /// this class should not be within the root class of the mvc application, but for example another class on the same level! For what is in this code the tag is the following: - /// - /// Here NameOfTheAssemblyContainingTheAutostartProviderClass is the name of (for example the dll), but without the extension. - ////////////////////////////////////////////////////////////////////////////////////// + HangfireBootstrapper.Init(Vrh.iScheduler.Monitor.InitHangfire); - (new HangfireBootstrapper()).Initialize(); - //Vrh.Web.Menu inicializáló beállításai - Vrh.Web.Menu.Global.CustomerLogo = "~/Content/Images/Menu_LearLogo.jpg"; - // ! ha azt szeretnénk, hogy a menükezelő kezelje a hitelesítést is, - // ! akkor ezt itt igaz értékre kell állítani - Vrh.Web.Menu.Global.IsUseAuthentication = true; + Vrh.Web.Menu.Global.CustomerLogo = "~/Content/Images/Menu_LearLogo.jpg"; + Vrh.Web.Menu.Global.IsUseAuthentication = true;// ! ha azt szeretnénk, hogy a menükezelő kezelje a hitelesítést is, akkor ezt itt igaz értékre kell állítani } - protected void Application_End(object sender, EventArgs e) { - var methodfullname = $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"; - (new DCLogEntry(LogLevel.Information, methodfullname)).Write(); - HangfireBootstrapper.Instance.Stop(); + (new DCLogEntry(LogLevel.Information, $"{typeof(MvcApplication).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}")).Write(); + HangfireBootstrapper.Stop(); } /// - /// Ha "Internal Server Error 500" üzenetet kapsz, akkor - /// ide érdemes a hívás előtt betenni egy break point-ot. - /// Majd vizsgálni a this.Context.AllErrors tulajdonságot. - /// Egyből kiderül, miért van az 500-as hiba :) + /// Ha "Internal Server Error 500" üzenetet kapsz, akkor ide érdemes a hívás előtt betenni egy break point-ot. + /// Majd vizsgálni a this.Context.AllErrors tulajdonságot. Egyből kiderül, miért van az 500-as hiba :) /// - protected void Application_EndRequest() - { - //int i = 1; - } + protected void Application_EndRequest() { var thisContextAllErrors = this.Context.AllErrors; } } } diff --git a/Vrh.Web.Reporting/HangfireBootstrapper.cs b/Vrh.Web.Reporting/HangfireBootstrapper.cs index e0585cd..bbbd6a1 100644 --- a/Vrh.Web.Reporting/HangfireBootstrapper.cs +++ b/Vrh.Web.Reporting/HangfireBootstrapper.cs @@ -16,38 +16,200 @@ using System.Xml.Linq; using Hangfire; using Microsoft.Web.Administration; using Vrh.Logger; +using System.Configuration; namespace Vrh.Web.HangfireBootstrapperNS { public class HangfireBootstrapper : IRegisteredObject, IProcessHostPreloadClient { + /// + /// Egy külső iniciátort hregisztrálására szolgál, amelyben lehetőség van a + /// paraméterként megkapott BackgroundJobServer-re ütemezett feladatokat definiálni. + /// + public static void InitConfig(Action externalinitializer=null) + { + if (externalinitializer == null) return; + var le = new DCLogEntry(LogLevel.Information, $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try { _InitConfig(externalinitializer, le); } + catch (Exception ex) { le.AddExceptionResult(ex);le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + private static void _InitConfig(Action externalinitializer, DCLogEntry le) + { + if (externalinitializer != null) + { + externalinitializerList.Add(externalinitializer); + le.AddDataField("ADD external initializer", $"{externalinitializer.Method.DeclaringType.FullName}.{externalinitializer.Method.Name}()"); + } + } + /// + /// A Hangfire rendszer elindítását, paraméterezését, konfigurálását és a külső iniciátorok meghívást végzi. + /// + const string HANGFIRE = "HangfireBootstrapper:"; + const string HANGFIREDISABLEAUTOSTART = HANGFIRE + "disableautostart"; + const bool DISABLEAUTOSTARTDEFAULT = false; + const string HANGFIREDBCONNECTIONSTRING = HANGFIRE + "dbconnectionstring"; + const string HANGFIRESQLDBCONNECTIONSTRINGNAMEDEFAULT = "HANGFIRESQLDB"; + public static void Init(Action externalinitializer=null) + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try + { + bool DisablAautoStart; + string disableautostartstring = ConfigurationManager.AppSettings[HANGFIREDISABLEAUTOSTART]; + if (string.IsNullOrWhiteSpace(disableautostartstring)) DisablAautoStart = DISABLEAUTOSTARTDEFAULT; + else if (disableautostartstring.ToLower() == bool.TrueString.ToLower()) DisablAautoStart = true; + else if (disableautostartstring.ToLower() != bool.FalseString.ToLower()) DisablAautoStart = false; + else DisablAautoStart = DISABLEAUTOSTARTDEFAULT; + + le.AddDataField("DisablAautoStart", DisablAautoStart); + _InitConfig(externalinitializer, le); + HangfireBootstrapper.Instance._InstanceInitialize(DisablAautoStart,le); + ExecuteExternalInitializers(le); + } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// A Hangfire rendszeer leállítását végzi; + /// Ezt a metódust meg kell hívni a IProcessHostPreloadClient működéséhez! + /// + public static void Stop() + { + (new DCLogEntry(LogLevel.Information, $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}")).Write(); + HangfireBootstrapper.Instance._Stop(); + } + + /// + /// IProcessHostPreloadClient-et megvalósító metódus, amelyet a w3w worker process újratöltésekor hív meg az IIS + /// + /// public void Preload(string[] parameters) { - var methodfullname = $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"; - (new DCLogEntry(LogLevel.Information, methodfullname)).Write(); - Initialize(); + var le = new DCLogEntry(LogLevel.Information, $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try + { + _InstanceInitialize(le:le); + ExecuteExternalInitializers(le); + le.AddSuccessResult("SUCCESS"); + } + catch (Exception ex) { le.AddExceptionResult(ex);le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } } - public void Initialize() + + /// + /// Kell legyen egy publikus paraméter nélküli konstruktor a webapp preload funkcióhoz!!! + /// + public HangfireBootstrapper() { } + + #region private members + private static void ExecuteExternalInitializers(DCLogEntry le) { - SetupAutoStart(typeof(HangfireBootstrapper)); - HangfireBootstrapper.Instance.SqlDBconnectionstring = Vrh.XmlProcessing.ConnectionStringStore.GetSQL(HANGFIRESQLDBCONNECTIONSTRINGNAME); - HangfireBootstrapper.Instance.Start(); - Vrh.iScheduler.Monitor.InitHangfire(HangfireBootstrapper.Instance._backgroundJobServer); + int numofall = externalinitializerList.Count(); + int counter = externalinitializerList.Count(); + if (numofall==0) + { + le.AddDebugField("External initializer","Nothing to initialize!"); + } + else + { + foreach (var ei in externalinitializerList) + { + var externalinitializername = $"External initializer: {ei.Method.DeclaringType.FullName}.{ei.Method.Name}()"; + try { ei.Invoke(HangfireBootstrapper.Instance._backgroundJobServer); le.AddDataField($"{externalinitializername} SUCCESS",$"{counter}of{numofall})"); } + catch (Exception ex) { le.AddDataField($"{externalinitializername} EXCEPTION", ex.Message); } + counter++; + } + } } - private const string HANGFIRESQLDBCONNECTIONSTRINGNAME = "MAINDBLOG4PRO"; - private const string CONFIGFILEDIRECTORY = @"inetsrv\config"; - private const string CONFIGFILENAME = @"applicationHost.config"; - //public const string FILEPATH = @"C:\temp\applicationHost.config"; - private const string POOLNAME = "Log4ProIS_REPORTING"; - private const string WEBAPPNAME = "/Log4ProIS-REPORTING"; - private const string WEBSITENAME = "Default Web Site"; - private const string AUTOSTARTPROVIDERNAME = "ApplicationPreload"; - private const string AUTOSTARTPROVIDERTYPENAME = "Vrh.Web.Reporting.ApplicationPreload"; - private const string AUTOSTARTPROVIDERASSEMBLYNAME = "Vrh.Web.Reporting"; + private void _InstanceInitialize(bool autostartsetupdisable =false,DCLogEntry le=null) + { + string HangfireSqlDBConnectionString = ConfigurationManager.AppSettings[HANGFIREDBCONNECTIONSTRING]; + if (string.IsNullOrWhiteSpace(HangfireSqlDBConnectionString)) HangfireSqlDBConnectionString = HANGFIRESQLDBCONNECTIONSTRINGNAMEDEFAULT; + le?.AddDataField("HangfireSqlDBConnectionString", HangfireSqlDBConnectionString); + SetupAutoStart(typeof(HangfireBootstrapper),disablemode:autostartsetupdisable,le:le); + HangfireBootstrapper.Instance.SqlDBconnectionstring = Vrh.XmlProcessing.ConnectionStringStore.GetSQL(HangfireSqlDBConnectionString); + HangfireBootstrapper.Instance._Start(); + } - private static bool SetupAutoStart(Type serviceAutoStartProviderType) + private static List> externalinitializerList = new List>(); + private static readonly HangfireBootstrapper Instance = new HangfireBootstrapper(); + private BackgroundJobServer _backgroundJobServer { get; set; } + private string SqlDBconnectionstring { get; set; } = null; + private readonly object _lockObject = new object(); + private bool _started; + + + private void _Start() + { + lock (_lockObject) + { + if (_started) return; + _started = true; + + HostingEnvironment.RegisterObject(this); + GlobalConfiguration.Configuration + .UseSqlServerStorage(SqlDBconnectionstring) + // Specify other options here + ; + + _backgroundJobServer = new BackgroundJobServer(); + } + } + + private void _Stop() + { + lock (_lockObject) + { + if (_backgroundJobServer != null) { _backgroundJobServer.Dispose(); } + HostingEnvironment.UnregisterObject(this); + } + } + + void IRegisteredObject.Stop(bool immediate) { _Stop(); } + #endregion private members + + #region private method - SetupAutoStart + /// + /// Beállítja az autostart és alwaysrunning és a preload paramétereket a megadott websitra, + /// web alkalmazásra és application pool-ra vonatkozóan. + /// Enable webApp pool autostart, preload and alwaysrun + /// For web applications running on servers under your control, either physical or virtual, you can use the auto-start feature of IIS ≥ 7.5 shipped with + /// Windows Server ≥ 2008 R2. Full setup requires the following steps to be done. Enable automatic start and AlwaysRunning mode for Application pool + /// and configure Auto - start feature as written below. + /// Edit the following file: C:\Windows\System32\inetsrv\config\applicationHost.config. + /// All edits should be made below the section. + /// In the section find the tag of the application pool to be autostarted. + /// Add autoStart="true" and startMode="AlwaysRunning" attributes to this tag. + /// In the section find the tag of the web application + /// running on the application pool with name "YourApplicationPoolName". + /// Add preloadEnabled="true", serviceAutoStartEnabled="true" and serviceAutoStartProvider="AnyNameForYourAutoStartProvider" attributes to this tag. + /// Here YourWebsiteName is the name of the website where the web application, using the application pool belongs to. + /// In the section create the following element: + /// + /// Here AnyNameForYourAutoStartProvider can be any name, that is suitable for the xml standard. + /// Here FullTypeNameOfTheAutostartProviderClass is the full type name (with namespace and class name) of the class that matches the IProcessHostPreloadClient interface; + /// this class should not be within the root class of the mvc application, but for example another class on the same level! For what is in this code the tag is the following: + /// + /// Here NameOfTheAssemblyContainingTheAutostartProviderClass is the name of (for example the dll), but without the extension. + ////////////////////////////////////////////////////////////////////////////////////// + /// + /// + /// annak a class-nak a típusa, amely megvalósítja a IProcessHostPreloadClient interfészt a Preload metódus-sal, + /// amely metódus meghívásra kerül mindenkor, amikor a hozzájuk tartozó w3w worker processz ujraindításra kerül. + /// + /// a website neve; alapértelmezés:a tartalmazó website + /// a web app neve; alapértelmezés:a tartalmazó web app + /// az app pool neve; alapértelmezés:a tartalmazó pool + /// + private static void SetupAutoStart(Type serviceAutoStartProviderType, string websitename = null, string webapplicationname = null, string applicationpoolname = null, bool disablemode = false, DCLogEntry le = null) { + const string CONFIGFILEDIRECTORY = @"inetsrv\config"; + const string CONFIGFILENAME = @"applicationHost.config"; + //const string FILEPATH = @"C:\temp\applicationHost.config"; + const string SYSTEMAPPLICATIONHOST_ELEMENT = "system.applicationHost"; const string APPLICATIONPOOLS_ELEMENT = "applicationPools"; const string SITES_ELEMENT = "sites"; @@ -63,78 +225,124 @@ namespace Vrh.Web.HangfireBootstrapperNS const string PATH_ATTRIBUTE = "path"; const string AUTOSTART_ATTRIBUTE = "autoStart"; const string STARTMODE_ATTRIBUTE = "startMode"; + const string PRELOADENABLED_ATTRIBUTE = "preloadEnabled"; - string applicationpoolname = GetCurrentApplicationPoolName(); - string websitename = System.Web.Hosting.HostingEnvironment.SiteName; - string webapplicationname = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath; - string autostartprovidername = (websitename + "____" + applicationpoolname + "____" + webapplicationname).Replace(" ", "_").Replace("-", "_").Replace("/", "_"); - string serviceAutoStartProviderTypeFullName = serviceAutoStartProviderType.FullName; - string serviceAutoStartProviderAssassemblyName = serviceAutoStartProviderType.Assembly.GetName().Name; - var methodfullname = $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"; - var le = new DCLogEntry(LogLevel.Information, methodfullname); + bool writele = le == null; + if (le == null) { le = new DCLogEntry(LogLevel.Information, $"{typeof(HangfireBootstrapper).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); }; try { + websitename = websitename ?? HostingEnvironment.SiteName; //websitename = System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName(); + webapplicationname = webapplicationname ?? HostingEnvironment.ApplicationVirtualPath; //webapplicationname = System.Web.HttpRuntime.AppDomainAppVirtualPath; + applicationpoolname = applicationpoolname ?? GetCurrentApplicationPoolName(websitename); + string autostartprovidername = (websitename + "____" + applicationpoolname + "____" + webapplicationname).Replace(" ", "_").Replace("-", "_").Replace("/", "_"); + string serviceAutoStartProviderTypeFullName = serviceAutoStartProviderType.FullName; + string serviceAutoStartProviderAssassemblyName = serviceAutoStartProviderType.Assembly.GetName().Name; string configfilepath = Path.Combine(NativeSystemPath, CONFIGFILEDIRECTORY, CONFIGFILENAME); - le.AddDataField("configfilepath", configfilepath); - le.AddDataField("applicationpoolname", applicationpoolname); - le.AddDataField("websitename", websitename); - le.AddDataField("webapplicationname", webapplicationname); - le.AddDataField("serviceAutoStartProviderTypeFullName", serviceAutoStartProviderTypeFullName); - le.AddDataField("serviceAutoStartProviderAssassemblyName", serviceAutoStartProviderAssassemblyName); - - var filecontent = System.IO.File.ReadAllText(configfilepath); XElement configxml = XElement.Parse(filecontent, LoadOptions.PreserveWhitespace); //XElement.Load(configfilepath); - XElement myconfigrootxml = configxml.Element(XName.Get(SYSTEMAPPLICATIONHOST_ELEMENT)); + + le.AddDataField("SetupAutoStart configfilepath", configfilepath); + le.AddDataField("SetupAutoStart applicationpoolname", applicationpoolname); + le.AddDataField("SetupAutoStart websitename (System.Web.Hosting.HostingEnvironment.SiteName)", websitename); + le.AddDataField("SetupAutoStart webapplicationname (System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath)", webapplicationname); + //le.AddDataField("System.Web.HttpRuntime.AppDomainAppVirtualPath", HttpRuntime.AppDomainAppVirtualPath); + //le.AddDataField("System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName()", System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName()); + le.AddDataField("SetupAutoStart serviceAutoStartProviderTypeFullName", serviceAutoStartProviderTypeFullName); + le.AddDataField("SetupAutoStart serviceAutoStartProviderAssassemblyName", serviceAutoStartProviderAssassemblyName); + XElement myapplicationpooladdelement = myconfigrootxml?.Element(XName.Get(APPLICATIONPOOLS_ELEMENT))? .Elements(XName.Get(ADD_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(NAME_ATTRIBUTE)).Value == applicationpoolname); XElement mysiteapplicationelement = myconfigrootxml?.Element(XName.Get(SITES_ELEMENT))? .Elements(XName.Get(SITE_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(NAME_ATTRIBUTE)).Value == websitename) .Elements(XName.Get(APPLICATION_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(PATH_ATTRIBUTE)).Value == webapplicationname && e.Attribute(XName.Get(APPLICATIONPOOL_ATTRIBUTE)).Value == applicationpoolname); - if (myapplicationpooladdelement == null) return false; - if (mysiteapplicationelement == null) return false; + if (myapplicationpooladdelement == null) return; + if (mysiteapplicationelement == null) return; - bool configchanged = false; - configchanged = SetOrAddAttribute(AUTOSTART_ATTRIBUTE, myapplicationpooladdelement, "true") || configchanged; - configchanged = SetOrAddAttribute(STARTMODE_ATTRIBUTE, myapplicationpooladdelement, "AlwaysRunning") || configchanged; - configchanged = SetOrAddAttribute(SERVICEAUTOSTARTENABLED_ATTRIBUTE, mysiteapplicationelement, "true") || configchanged; - configchanged = SetOrAddAttribute(SERVICEAUTOSTARTPROVIDER_ATTRIBUTE, mysiteapplicationelement, autostartprovidername) || configchanged; + bool configchanged=false; + if (disablemode) + { + configchanged = SetOrAddAttribute(AUTOSTART_ATTRIBUTE, myapplicationpooladdelement, bool.FalseString.ToLower()) || configchanged; + configchanged = SetOrAddAttribute(STARTMODE_ATTRIBUTE, myapplicationpooladdelement, StartMode.OnDemand.ToString()) || configchanged; + configchanged = SetOrAddAttribute(SERVICEAUTOSTARTENABLED_ATTRIBUTE, mysiteapplicationelement, bool.FalseString.ToLower()) || configchanged; + configchanged = SetOrAddAttribute(PRELOADENABLED_ATTRIBUTE, mysiteapplicationelement, bool.FalseString.ToLower()) || configchanged; + configchanged = RemoveAttribute(SERVICEAUTOSTARTPROVIDER_ATTRIBUTE, mysiteapplicationelement) || configchanged; + + XElement myautostartproviderselement = myconfigrootxml.Element(XName.Get(SERVICEAUTOSTARTPROVIDERS_ELEMENT)); + configchanged = RemoveElementWithSelectorAttribute(ADD_ELEMENT, myautostartproviderselement, NAME_ATTRIBUTE, autostartprovidername,removecontainerifnochild:true) || configchanged; + } + else + { + configchanged = SetOrAddAttribute(AUTOSTART_ATTRIBUTE, myapplicationpooladdelement, bool.TrueString.ToLower()) || configchanged; + configchanged = SetOrAddAttribute(STARTMODE_ATTRIBUTE, myapplicationpooladdelement, StartMode.AlwaysRunning.ToString()) || configchanged; + configchanged = SetOrAddAttribute(SERVICEAUTOSTARTENABLED_ATTRIBUTE, mysiteapplicationelement, bool.TrueString.ToLower()) || configchanged; + configchanged = SetOrAddAttribute(PRELOADENABLED_ATTRIBUTE, mysiteapplicationelement, bool.TrueString.ToLower()) || configchanged; + configchanged = SetOrAddAttribute(SERVICEAUTOSTARTPROVIDER_ATTRIBUTE, mysiteapplicationelement, autostartprovidername) || configchanged; - XElement myautostartproviderselement = null; - XElement myautostartprovideraddelement = null; - configchanged = SetOrAddElement(SERVICEAUTOSTARTPROVIDERS_ELEMENT, myconfigrootxml, "", out myautostartproviderselement) || configchanged; - configchanged = SetOrAddElementWithSelectorAttribute(ADD_ELEMENT, myautostartproviderselement, NAME_ATTRIBUTE, autostartprovidername, "", out myautostartprovideraddelement) || configchanged; - configchanged = SetOrAddAttribute(TYPE_ATTRIBUTE, myautostartprovideraddelement, $"{serviceAutoStartProviderTypeFullName},{serviceAutoStartProviderAssassemblyName }") || configchanged; + configchanged = SetOrAddElement(SERVICEAUTOSTARTPROVIDERS_ELEMENT, myconfigrootxml, "", out XElement myautostartproviderselement) || configchanged; + configchanged = SetOrAddElementWithSelectorAttribute(ADD_ELEMENT, myautostartproviderselement, NAME_ATTRIBUTE, autostartprovidername, "", out XElement myautostartprovideraddelement) || configchanged; + configchanged = SetOrAddAttribute(TYPE_ATTRIBUTE, myautostartprovideraddelement, $"{serviceAutoStartProviderTypeFullName},{serviceAutoStartProviderAssassemblyName }") || configchanged; + } if (configchanged) { //configxml.Save(configfilepath); System.IO.File.WriteAllText(configfilepath, configxml.ToString()); } - le.AddDataField("configchanged", configchanged); - //le.AddDataField("myconfigrootxml", myconfigrootxml); - le.AddSuccessResult("SUCCESS"); - return true; + string modetxt = disablemode ? "DISABLED" : "ENABLED"; + le.AddSuccessResult("SetupAutoStart " + (configchanged ? $"SUCCESSFULLY {modetxt}" : $"NO CHANGE, ALREADY {modetxt}")); } - catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); return false; } - finally { le.Write(); } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); return; } + finally { if (writele) le.Write(); } + } + private static bool RemoveAttribute(string attributetoremovename, XElement attrcontainer) + { + XAttribute attr = attrcontainer.Attribute(XName.Get(attributetoremovename)); + if (attr == null) return false; + attr.Remove(); + return true; } - private static bool SetOrAddElement(string elementname, XElement elementcontainer, string elementvalue, out XElement myelement) + private static bool RemoveElement(string elementtoremovename, XElement elementcontainer,bool removecontainerifnochild=false) { bool configchanged = false; - myelement = elementcontainer?.Element(XName.Get(elementname)); - if (myelement == null) { myelement = new XElement(XName.Get(elementname), ""); elementcontainer.Add(myelement); configchanged = true; } + XElement elementtoremove = elementcontainer?.Element(XName.Get(elementtoremovename)); + if (elementtoremove == null) return configchanged; + elementtoremove.Remove(); + if (removecontainerifnochild) + { + var childelements = elementcontainer.Elements(); + if (childelements == null || !childelements.Any()) elementcontainer.Remove(); + } + return (configchanged=true); + } + private static bool RemoveElementWithSelectorAttribute(string elementtoremovename, XElement elementcontainer,string selectorattributename, string selectorattributevalue,bool removecontainerifnochild=false) + { + bool configchanged = false; + XElement elementtoremove = elementcontainer?.Elements(XName.Get(elementtoremovename))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); + if (elementtoremove == null) return configchanged; + elementtoremove.Remove(); + if (removecontainerifnochild) + { + var childelements = elementcontainer.Elements(); + if (childelements == null || !childelements.Any()) elementcontainer.Remove(); + } + return (configchanged = true); + } + private static bool SetOrAddElement(string elementtosetname, XElement elementcontainer, string elementvalue, out XElement myelement) + { + bool configchanged = false; + myelement = elementcontainer?.Element(XName.Get(elementtosetname)); + if (myelement == null) { myelement = new XElement(XName.Get(elementtosetname), ""); elementcontainer.Add(myelement); configchanged = true; } if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } return configchanged; } - private static bool SetOrAddElementWithSelectorAttribute(string elementname, XElement elementcontainer, string selectorattributename, string selectorattributevalue, string elementvalue, out XElement myelement) + private static bool SetOrAddElementWithSelectorAttribute(string elementtosetname, XElement elementcontainer, string selectorattributename, string selectorattributevalue, string elementvalue, out XElement myelement) { bool configchanged = false; - myelement = elementcontainer?.Elements(XName.Get(elementname))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); + myelement = elementcontainer?.Elements(XName.Get(elementtosetname))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); if (myelement == null) { - myelement = new XElement(XName.Get(elementname), ""); + myelement = new XElement(XName.Get(elementtosetname), ""); elementcontainer.Add(myelement); SetOrAddAttribute(selectorattributename, myelement, selectorattributevalue); configchanged = true; @@ -142,76 +350,24 @@ namespace Vrh.Web.HangfireBootstrapperNS if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } return configchanged; } - private static bool SetOrAddAttribute(string attrname, XElement attrcontainer, string attrvalue) + private static bool SetOrAddAttribute(string attributetosetname, XElement attrcontainer, string attrvalue) { bool configchanged = false; - XAttribute attr = attrcontainer.Attribute(XName.Get(attrname)); - if (attr == null) { attr = new XAttribute(XName.Get(attrname), ""); attrcontainer.Add(attr); configchanged = true; } + XAttribute attr = attrcontainer.Attribute(XName.Get(attributetosetname)); + if (attr == null) { attr = new XAttribute(XName.Get(attributetosetname), ""); attrcontainer.Add(attr); configchanged = true; } if (attr.Value != attrvalue) { attr.Value = attrvalue; configchanged = true; } return configchanged; } private static string NativeSystemPath { - get - { - if (Environment.Is64BitOperatingSystem) - { - return System.IO.Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.Windows), - "Sysnative"); - } - return Environment.GetFolderPath(Environment.SpecialFolder.System); - } + get { return System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), Environment.Is64BitOperatingSystem?"Sysnative":""); } } - - private static string GetCurrentApplicationPoolName() + private static string GetCurrentApplicationPoolName(string websitename=null) { - string appPoolName = string.Empty; - foreach (Application app in (new ServerManager()).Sites[System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName()].Applications) - { - if (app.Path == HttpRuntime.AppDomainAppVirtualPath) { appPoolName = app.ApplicationPoolName; } - } - return appPoolName; + return (new ServerManager()).Sites[websitename ?? System.Web.Hosting.HostingEnvironment.SiteName].Applications? + .FirstOrDefault(app => app.Path == HttpRuntime.AppDomainAppVirtualPath)? + .ApplicationPoolName; } - - public static readonly HangfireBootstrapper Instance = new HangfireBootstrapper(); - private BackgroundJobServer _backgroundJobServer { get; set; } - private string SqlDBconnectionstring { get; set; } = null; - private readonly object _lockObject = new object(); - private bool _started; - - - public HangfireBootstrapper() - { - } - - public void Start() - { - lock (_lockObject) - { - if (_started) return; - _started = true; - - HostingEnvironment.RegisterObject(this); - - GlobalConfiguration.Configuration - .UseSqlServerStorage(SqlDBconnectionstring) - // Specify other options here - ; - - _backgroundJobServer = new BackgroundJobServer(); - } - } - - public void Stop() - { - lock (_lockObject) - { - if (_backgroundJobServer != null) { _backgroundJobServer.Dispose(); } - HostingEnvironment.UnregisterObject(this); - } - } - - void IRegisteredObject.Stop(bool immediate) { Stop(); } + #endregion private method - SetupAutoStart } } diff --git a/Vrh.iScheduler/Monitor .cs b/Vrh.iScheduler/Monitor .cs index 8875527..50f9dc6 100644 --- a/Vrh.iScheduler/Monitor .cs +++ b/Vrh.iScheduler/Monitor .cs @@ -21,7 +21,7 @@ namespace Vrh.iScheduler public class Monitor : IDisposable { - public static void InitHangfire(BackgroundJobServer backgroundserver) + public static void InitHangfire(object parameters) { string ischedulerMonitorXml = "config=ALMiSchedulerMonitor";//TODO:hogy lehet ezt paraméterben átadni?????? string ischedulerXml = ""; // vagy "config=ALMiScheduler;"; @@ -29,6 +29,86 @@ namespace Vrh.iScheduler Monitor.SetiSchedulerCommonXMLProcessor(m_xmlp); if (m_xmlp.EnableWebAppExecution && m_xmlp.CheckInterval > 0) { + + //Cron Expression + // + // :0-59 + // :0-23 + // :1-31 + // :1-12 + // :0-6 (Sunday to Saturday; 7 is Sunday on some systems) + //Special Characters in Cron Expression + // * (all) all values. event should happen for every time unit. For example, “*” in the field means “for every minute.” + // ? (any) any value. used for the and fields. For example “?” in the field and 5 in the + // field means “5th of every month” irrespective of what day is this of the week. + // – (range) value range. For example, “10-11” in the field means “10th and 11th hours.” + // , (values) multiple values. For example, “MON, WED, FRI“ in field means on the days “Monday, Wednesday and Friday.” + // / (increments) specifies the incremental values.For example, a “5/15” in the field means at “5, 20, 35 and 50 minutes of an hour.” + // L (last) has different meanings when used in various fields. For example, if it's applied in the field, it means last day of the month, + // i.e. “31st of January” and so on as per the calendar month. It can be used with an offset value, like “L-3”, + // which denotes the “third to last day of the calendar month.” In , it specifies the “last day of a week.” It can also be used with + // another value in , like “6L”, which denotes the “last Friday.” + // W (weekday) determines the weekday (Monday to Friday) nearest to a given day of the month.For example, if we specify “10W” in the field, + // it means the “weekday near to 10th of that month.” So if “10th” is a Saturday, the job will be triggered on “9th,” and if “10th” is a Sunday, + // it will trigger on “11th.” If we specify “1W” in and if “1st” is Saturday, the job will be triggered on “3rd,” which is Monday, + // and it will not jump back to the previous month. + // # specifies the “N-th” occurrence of a weekday of the month, for example, “third Friday of the month” can be indicated as “6#3”. + //Cron Special Strings + // run once at the startup: "@reboot" + // run once a year: "@yearly" or "@annualy" (="0 0 1 1 *") + // run once a month: "@monthly" (="0 0 1 * *") + // run once a week: "@weekly" (="0 0 * * 0") + // run once a day: "@daily" or "@midnight" (="0 0 * * *") + // run hourly: "@hourly" (="0 * * * *") + + //At 12:00pm (noon) every day: "0 12 * * ?" + //At Every five minutes starting at 1pm and ending at 1:55pm and then starting at 6pm and ending at 6:55pm, every day: "0/5 13,18 * * ?" + //At Every minute starting at 1pm and ending at 1:05pm, every day: "0-5 13 * * ?" + //At 1:15pm and 1:45pm every Tuesday in the month of June: "15,45 13 ? 6 Tue" + //At 9:30am every Monday, Tuesday, Wednesday, Thursday and Friday: "30 9 ? *MON - FRI" + //At 9:30am on the 15th day of every month: "30 9 15 * ?" + //At 6pm on the last day of every month: "0 18 L * ?" + //At 6pm on the third to last day of every month: "0 18 L - 3 * ?" + //At 10:30am on the last Thursday of every month: "30 10 ? *5L" + //At 10am on the third Monday of every month: "0 10 ? *2#3" + //At 12 midnight on every 5th day, starting from the 10th until the end of the month: "0 0 10 / 5 * ?" + + //At every hour: "0 * * * *" + //At every hour: "@hourly" + //At once a day at midnight: "0 0 * * *" + //At every Sunday at midnight: "0 0 * * 0" + //At every hour on Mondays: "0 * * *1" + //At twice a day at 6am and 6pm: "0 6,18 * * *" + //At every 10 minutes: "*/10 * * * *" + //At every minute on July 20: "* * 20 7 *" + //At every weekday(Monday to Friday) at 10pm: "0 22 * * 1-5" + //At at midnight every Tuesday: "0 0 * * 2 *" + //At every minute during January, February, and May "* * * 1,2,5 *" + //At every 10 minutes at 5am, starting from 5:10am: "10-59/10 5 * * *" + //At quarterly on the first day of the month at 8am "0 8 1 */3 *" + //At every time you turn on the system: "@reboot" + //At the first Monday of each month, at 8am: "0 8 1-7 * 1" + //At every Sunday at 4:05 am: "5 4 * * 0" + //At at 9:15 pm on the 1st and 20th of every month: "15 9 1,20 * *" + //At at midnight every Wednesday between the 1st and 15th of every month: "0 0 1,15 * 3" + //At the first day of every month at 2:15pm: "15 14 1 * *" + //At every day from Monday to Friday every hour from 8 to 5pm: "00 08-17 * * 1-5" + //At every January 1st at 6:15am: "15 6 1 1 *" + //At at midnight on the 15th of every month: "0 0 15 * *" + //At every Monday and Friday: "* * * * 1,5" + + //At Every Minute of Every Day: "* * * * *" or "0-59 0-23 0-31 0-12 0-7" + //At Every 10 Minutes of Every Day: "*/10 * * * *" or "0-59/10 * * * *" or "0,10,20,30,40,50 * * * *" + //At Every 5 Minutes of the 6am hour starting at 6:07 (tu run at 6:07, 6:012, 6:17, 6:22, 6:27, and so on until 6:57):"07-59/5 06 * * *" + //At Every day at midnight: "0 0 * * *" or "0 0 * * 0-7" + //At Thrice Daily: "0 */8 * * *" or "0 0-23/8 * * *" or "0 0,8,16 * * *" + //At Every weekday at 6am: "0 06 * * 1-5" + //At Weekends at 6am: "0 06 * * 6,7" or "0 06 * * 6-7" + //At Once a month on the 20th at 6am: "0 06 20 * *" + //At Every 4 days at 6am: "0 06 */4 * *" + //At Every 4 Months at 6am on the 10th: "0 06 10 */4 *" + + string intervalcron = Cron.MinuteInterval((int)(m_xmlp.CheckInterval / 60));//"*/1 * * * *" //RecurringJob.RemoveIfExists("ischedulermonitorcycle"); RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor().Examination(null), intervalcron); @@ -100,7 +180,7 @@ namespace Vrh.iScheduler m_timer = new Timer(m_xmlp.CheckInterval * 1000); // !!! Ez itt a jó sor !!! m_timer = new Timer(20000); meg a debug !!! m_timer.Elapsed += OnExamination; - var le = new DCLogEntry(LogLevel.Debug, nameof(Monitor) + " constructor. Preparation ready."); + var le = new DCLogEntry(LogLevel.Information, nameof(Monitor) + " constructor. Preparation ready."); le.AddDataField("iSchedulerMonitor xml path", m_xmlp.ScheduleMonitorXmlPath); le.AddDataField("iScheduler xml path", m_xmlp.ScheduleXmlPath); le.AddDataField("Scheduled object type", m_xmlp.ObjectType); -- libgit2 0.21.2