From 0221e022f5bf1a564df833e7bb8dcf1bc5d23c63 Mon Sep 17 00:00:00 2001 From: Schwirg László Date: Thu, 8 Jun 2023 19:04:42 +0200 Subject: [PATCH] Vrh.Web.Reporting v1.1.0.0 Vrh.iScheduler v3.3.0.0 --- Vrh.Web.Reporting/Global.asax.cs | 9 ++++++--- Vrh.Web.Reporting/HangfireBootstrapper.cs | 410 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Vrh.Web.Reporting/Properties/AssemblyInfo.cs | 6 +++--- Vrh.Web.Reporting/Vrh.Web.Reporting.csproj | 2 +- Vrh.Web.Reporting/WebServerHostedServiceStarter.cs | 483 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Vrh.iScheduler/Monitor .cs | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------ Vrh.iScheduler/Properties/AssemblyInfo.cs | 6 +++--- 7 files changed, 718 insertions(+), 510 deletions(-) delete mode 100644 Vrh.Web.Reporting/HangfireBootstrapper.cs create mode 100644 Vrh.Web.Reporting/WebServerHostedServiceStarter.cs diff --git a/Vrh.Web.Reporting/Global.asax.cs b/Vrh.Web.Reporting/Global.asax.cs index b8d64b2..65ddcaa 100644 --- a/Vrh.Web.Reporting/Global.asax.cs +++ b/Vrh.Web.Reporting/Global.asax.cs @@ -16,20 +16,23 @@ using Hangfire; using Microsoft.Web.Administration; using Vrh.iScheduler; using Vrh.Logger; -using Vrh.Web.HangfireBootstrapperNS; +using Vrh.Web.WebServerHostedServiceStarterNS; namespace Vrh.Web.Reporting { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { + Thread.Sleep(20000); (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); - HangfireBootstrapper.Init(Vrh.iScheduler.Monitor.InitHangfire); + WebServerHostedServiceStarter.Init(typeof(Vrh.iScheduler.WAHostedMonitorHangfire)); + //IISHostedServiceStarter.Init(Vrh.iScheduler.WAHostedMonitorHangfire.Start, Vrh.iScheduler.WAHostedMonitorHangfire.Stop); + //IISHostedServiceStarter.Init(Vrh.iScheduler.WAHostedMonitor.Start, Vrh.iScheduler.WAHostedMonitor.Stop); //Vrh.Web.Menu inicializáló beállításai Vrh.Web.Menu.Global.CustomerLogo = "~/Content/Images/Menu_LearLogo.jpg"; @@ -39,7 +42,7 @@ namespace Vrh.Web.Reporting protected void Application_End(object sender, EventArgs e) { (new DCLogEntry(LogLevel.Information, $"{typeof(MvcApplication).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}")).Write(); - HangfireBootstrapper.Stop(); + WebServerHostedServiceStarter.Stop(); } /// /// Ha "Internal Server Error 500" üzenetet kapsz, akkor ide érdemes a hívás előtt betenni egy break point-ot. diff --git a/Vrh.Web.Reporting/HangfireBootstrapper.cs b/Vrh.Web.Reporting/HangfireBootstrapper.cs deleted file mode 100644 index dc68a72..0000000 --- a/Vrh.Web.Reporting/HangfireBootstrapper.cs +++ /dev/null @@ -1,410 +0,0 @@ -using System.Text; -using System.Threading.Tasks; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading; -using System.Web; -using System.Web.Hosting; -using System.Web.Mvc; -using System.Web.Optimization; -using System.Web.Routing; -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 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(); } - } - - /// - /// 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) - { - 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 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 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"; - - 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("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); - - string filecontent; - bool configchanged; - lock (lockerFile) - { - bool usefilestream = false; - if (usefilestream) - { - FileStream file=null; StreamReader reader = null; StreamWriter writer = null; - try - { - int opentriescounter = 0; - while (true) - { - try { file = new FileStream(configfilepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); break; } - catch - { - if (opentriescounter++ > 5) throw new Exception("ERROR! in accessing config file. Maybe it is open in other application!"); - Thread.Sleep(20); - } - } - - reader = new StreamReader(file, Encoding.ASCII); - filecontent = ProcessFileContent(le, reader.ReadToEnd(), applicationpoolname, websitename, webapplicationname, autostartprovidername, serviceAutoStartProviderAssassemblyName, serviceAutoStartProviderTypeFullName, disablemode); - configchanged = filecontent != null; - if (configchanged) - { - writer = new StreamWriter(file, Encoding.ASCII); - writer.Write(filecontent); - } - } - finally { try { writer?.Dispose(); } catch { } try { reader?.Dispose();} catch { } try { file?.Dispose(); } catch { } } - } - else - { - filecontent = ProcessFileContent(le, System.IO.File.ReadAllText(configfilepath), applicationpoolname, websitename, webapplicationname, autostartprovidername, serviceAutoStartProviderAssassemblyName, serviceAutoStartProviderTypeFullName, disablemode); - configchanged = filecontent != null; - if (configchanged) System.IO.File.WriteAllText(configfilepath, filecontent); - } - } - string modetxt = disablemode ? "DISABLED" : "ENABLED"; - le.AddDataField("SetupAutoStart SUCCESS RESULT",configchanged ? modetxt : $"NO CHANGE, ALREADY {modetxt}"); - } - catch (Exception ex) { le.AddDataField("SetupAutoStart EXCEPTION",ex.Message); le.SetLogLevel(LogLevel.Error); return; } - finally { if (writele) le.Write(); } - } - private static string ProcessFileContent(DCLogEntry le, string filecontent,string applicationpoolname,string websitename,string webapplicationname,string autostartprovidername,string serviceAutoStartProviderAssassemblyName, string serviceAutoStartProviderTypeFullName,bool disablemode) - { - const string SYSTEMAPPLICATIONHOST_ELEMENT = "system.applicationHost"; - const string APPLICATIONPOOLS_ELEMENT = "applicationPools"; - const string SITES_ELEMENT = "sites"; - const string SERVICEAUTOSTARTPROVIDERS_ELEMENT = "serviceAutoStartProviders"; - const string SITE_ELEMENT = "site"; - const string APPLICATION_ELEMENT = "application"; - const string ADD_ELEMENT = "add"; - const string NAME_ATTRIBUTE = "name"; - const string TYPE_ATTRIBUTE = "type"; - const string SERVICEAUTOSTARTENABLED_ATTRIBUTE = "serviceAutoStartEnabled"; - const string SERVICEAUTOSTARTPROVIDER_ATTRIBUTE = "serviceAutoStartProvider"; - const string APPLICATIONPOOL_ATTRIBUTE = "applicationPool"; - const string PATH_ATTRIBUTE = "path"; - const string AUTOSTART_ATTRIBUTE = "autoStart"; - const string STARTMODE_ATTRIBUTE = "startMode"; - const string PRELOADENABLED_ATTRIBUTE = "preloadEnabled"; - - XElement configxml = XElement.Parse(filecontent, LoadOptions.PreserveWhitespace); - XElement myconfigrootxml = configxml.Element(XName.Get(SYSTEMAPPLICATIONHOST_ELEMENT)); - - 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 || mysiteapplicationelement == null) return null; - - 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; - - 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; - } - return configxml.ToString(); - } - private static object lockerFile = new Object(); - 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 RemoveElement(string elementtoremovename, XElement elementcontainer,bool removecontainerifnochild=false) - { - bool configchanged = false; - 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 elementtosetname, XElement elementcontainer, string selectorattributename, string selectorattributevalue, string elementvalue, out XElement myelement) - { - bool configchanged = false; - myelement = elementcontainer?.Elements(XName.Get(elementtosetname))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); - if (myelement == null) - { - myelement = new XElement(XName.Get(elementtosetname), ""); - elementcontainer.Add(myelement); - SetOrAddAttribute(selectorattributename, myelement, selectorattributevalue); - configchanged = true; - } - if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } - return configchanged; - } - private static bool SetOrAddAttribute(string attributetosetname, XElement attrcontainer, string attrvalue) - { - bool configchanged = false; - 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 { return System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), Environment.Is64BitOperatingSystem?"Sysnative":""); } - } - private static string GetCurrentApplicationPoolName(string websitename=null) - { - return (new ServerManager()).Sites[websitename ?? System.Web.Hosting.HostingEnvironment.SiteName].Applications? - .FirstOrDefault(app => app.Path == HttpRuntime.AppDomainAppVirtualPath)? - .ApplicationPoolName; - } - #endregion private method - SetupAutoStart - } -} diff --git a/Vrh.Web.Reporting/Properties/AssemblyInfo.cs b/Vrh.Web.Reporting/Properties/AssemblyInfo.cs index 682b3d0..2defc83 100644 --- a/Vrh.Web.Reporting/Properties/AssemblyInfo.cs +++ b/Vrh.Web.Reporting/Properties/AssemblyInfo.cs @@ -36,6 +36,6 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: AssemblyInformationalVersion("1.0.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] +[assembly: AssemblyInformationalVersion("1.1.0")] diff --git a/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj b/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj index 0765643..19533d5 100644 --- a/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj +++ b/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj @@ -344,7 +344,7 @@ Global.asax - + diff --git a/Vrh.Web.Reporting/WebServerHostedServiceStarter.cs b/Vrh.Web.Reporting/WebServerHostedServiceStarter.cs new file mode 100644 index 0000000..556e8d3 --- /dev/null +++ b/Vrh.Web.Reporting/WebServerHostedServiceStarter.cs @@ -0,0 +1,483 @@ +using System.Text; +using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Web; +using System.Web.Hosting; +using System.Web.Mvc; +using System.Web.Optimization; +using System.Web.Routing; +using System.Xml.Linq; +using Hangfire; +using Microsoft.Web.Administration; +using Vrh.Logger; +using System.Configuration; +using System.Reflection; + +namespace Vrh.Web.WebServerHostedServiceStarterNS +{ + /// + /// TODO: ezt egy olyan helyre kellene rakni, ahol mindenhova referálható (az Vrh.Interfaces.dll egyre jobb ötletnek tűnik! Kár hogy nem hallgattam Antira!) + /// + public interface IWebServerHostedServiceStarter + { + void Start(); + void Stop(); + } + public class WebServerHostedServiceStarter : IRegisteredObject, IProcessHostPreloadClient + { + /// + /// Egy hosted service elindítását, paraméterezését, konfigurálását és a külső iniciátor meghívást végzi. + /// + /// + /// az indító és leállító metódusokat tartalmazó osztály; + /// IWebServerHostedServiceStarter interfészt meg kell valósítsa, bár ezt nem ellenőrzi, csak azt, + /// hogy az ezt jelentő 'public static void Start();' és 'public static void Stop();' metódusok megvannak-e. + /// + public static void Init(Type tt) + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{nameof(Init)}"); + try + { + //if (!tt.GetInterfaces().Contains(typeof(IWebServerHostedServiceStarter))) throw new InterfaceErrorApplicationException(tt.FullName); + + _SetupAutoStart(le: le); + + var startmethod = tt.GetMethod(nameof(IWebServerHostedServiceStarter .Start), BindingFlags.Public | BindingFlags.Static); + var stopmethod = tt.GetMethod(nameof(IWebServerHostedServiceStarter .Stop), BindingFlags.Public | BindingFlags.Static); + if (startmethod == null || startmethod.ReturnType != typeof(void) || startmethod.GetParameters().Count() > 0) throw new InterfaceErrorApplicationException(tt.FullName,nameof(IWebServerHostedServiceStarter .Start)); + if (stopmethod == null || stopmethod.ReturnType != typeof(void) || stopmethod.GetParameters().Count() > 0) throw new InterfaceErrorApplicationException(tt.FullName, nameof(IWebServerHostedServiceStarter .Stop)); + IISHostedServiceStarterInstance._RegisterExternalInitializer((Action)Delegate.CreateDelegate(typeof(Action), startmethod), (Action)Delegate.CreateDelegate(typeof(Action), stopmethod), le); + + IISHostedServiceStarterInstance._StartExternalInitializers(le); + } + catch (InterfaceErrorApplicationException ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// Egy hosted service elindítását, paraméterezését, konfigurálását és külső iniciátorok meghívást végzi. + /// + /// az indító metódus + /// a leállító metódus + public static void Init(List ttList) + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{nameof(Init)}"); + try + { + //if (!tt.GetInterfaces().Contains(typeof(IInterface))) throw new Exception ($"{tt.FullName} does not implement {nameof(IInterface)}!"); + + _SetupAutoStart(le: le); + foreach (var tt in ttList) + { + try + { + var startmethod = tt.GetMethod(nameof(IWebServerHostedServiceStarter .Start), BindingFlags.Public | BindingFlags.Static); + var stopmethod = tt.GetMethod(nameof(IWebServerHostedServiceStarter .Stop), BindingFlags.Public | BindingFlags.Static); + if (startmethod == null || startmethod.ReturnType != typeof(void) || startmethod.GetParameters().Count() > 0) throw new InterfaceErrorApplicationException(tt.FullName, nameof(IWebServerHostedServiceStarter .Start)); + if (stopmethod == null || stopmethod.ReturnType != typeof(void) || stopmethod.GetParameters().Count() > 0) throw new InterfaceErrorApplicationException(tt.FullName, nameof(IWebServerHostedServiceStarter .Stop)); + IISHostedServiceStarterInstance._RegisterExternalInitializer((Action)Delegate.CreateDelegate(typeof(Action), startmethod), (Action)Delegate.CreateDelegate(typeof(Action), stopmethod), le); + } + catch (InterfaceErrorApplicationException ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + } + IISHostedServiceStarterInstance._StartExternalInitializers(le); + } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + private class InterfaceErrorApplicationException : ApplicationException + { + public InterfaceErrorApplicationException(string typename, string methodname) : base($"Class '{typename}' does not implement 'public static void {methodname}()' action!") { } + public InterfaceErrorApplicationException(string typename) : base($"Class '{typename}' does not implement '{nameof(IWebServerHostedServiceStarter)}' interface!") { } + } + /// + /// Egy hosted service elindítását, paraméterezését, konfigurálását és a külső iniciátor meghívást végzi. + /// + /// az indító metódus + /// a leállító metódus + public static void Init(Action externalinitializerstartmethod, Action externalinitializerstopmethod) + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{nameof(Init)}"); + try + { + _SetupAutoStart(le: le); + IISHostedServiceStarterInstance._RegisterExternalInitializer(externalinitializerstartmethod, externalinitializerstopmethod, le); + IISHostedServiceStarterInstance._StartExternalInitializers(le); + } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// Több hosted service elindítását, paraméterezését, konfigurálását és a külső iniciátorok meghívást végzi. + /// + public static void Init(List> externalinitializerList) + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{nameof(Init)}"); + try + { + _SetupAutoStart(le: le); + foreach (var ei in externalinitializerList) IISHostedServiceStarterInstance._RegisterExternalInitializer(ei.Item1, ei.Item2, le); + IISHostedServiceStarterInstance._StartExternalInitializers(le); + } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// A hosted serviceek 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() + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try { IISHostedServiceStarterInstance._StopExternalInitializers(le); } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// 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 le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try + { + _SetupAutoStart(disablemode: false, le: le); + _StartExternalInitializers(le); + le.AddSuccessResult("SUCCESS"); + } + catch (Exception ex) { le.AddExceptionResult(ex);le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } + + /// + /// Kell legyen egy publikus paraméter nélküli konstruktor a webapp preload funkcióhoz!!! + /// + public WebServerHostedServiceStarter() { } + + + #region private members + void IRegisteredObject.Stop(bool immediate) { Stop(); } + private void _RegisterExternalInitializer(Action externalinitializerstartmethod, Action externalinitializerstopmethod, DCLogEntry le) + { + if (externalinitializerstartmethod != null) + { + externalinitializerList.Add(Tuple.Create(externalinitializerstartmethod, externalinitializerstopmethod)); + le?.AddDataField("ADD external initializer START", $"{externalinitializerstartmethod.Method.DeclaringType.FullName}.{externalinitializerstartmethod.Method.Name}()"); + le?.AddDataField("ADD external initializer STOP", $"{externalinitializerstopmethod.Method.DeclaringType.FullName}.{externalinitializerstopmethod.Method.Name}()"); + } + } + private void _StartExternalInitializers(DCLogEntry le) + { + lock (ExternalInitializerStarStopLocker) + { + int numofall = externalinitializerList.Count(); + int counter = externalinitializerList.Count(); + if (numofall == 0) { le.AddDebugField(nameof(_StartExternalInitializers), NOEXTERNALINITIALIZERSAREREGISTERED); return; } + + HostingEnvironment.RegisterObject(IISHostedServiceStarterInstance); + foreach (var ei in externalinitializerList) + { + var externalinitializername = $"External initializer: {ei.Item1.Method.DeclaringType.FullName}.{ei.Item1.Method.Name}()"; + try { ei.Item1.Invoke(); le.AddDataField($"{externalinitializername} START SUCCESS", $"{counter}of{numofall}"); } + catch (Exception ex) { le.AddDataField($"{externalinitializername} START EXCEPTION", ex.Message); } + counter++; + } + } + } + private void _StopExternalInitializers(DCLogEntry le) + { + lock (ExternalInitializerStarStopLocker) + { + int numofall = externalinitializerList.Count(); + int counter = externalinitializerList.Count(); + if (numofall == 0) { le.AddDebugField(nameof(_StopExternalInitializers), NOEXTERNALINITIALIZERSAREREGISTERED); return; } + + foreach (var ei in externalinitializerList) + { + var externalinitializername = $"External initializer: {ei.Item2.Method.DeclaringType.FullName}.{ei.Item2.Method.Name}()"; + try { ei.Item2.Invoke(); le.AddDataField($"{externalinitializername} STOP SUCCESS", $"{counter}of{numofall}"); } + catch (Exception ex) { le.AddDataField($"{externalinitializername} STOP EXCEPTION", ex.Message); } + counter++; + } + HostingEnvironment.UnregisterObject(IISHostedServiceStarterInstance); + } + } + + private object ExternalInitializerStarStopLocker = new object(); + private static readonly WebServerHostedServiceStarter IISHostedServiceStarterInstance = new WebServerHostedServiceStarter(); + private static List> externalinitializerList = new List>(); + private static bool Config_DisablAutoStart + { + get + { + if (!config_disablautostart.HasValue) + { + string disableautostartstring = ConfigurationManager.AppSettings[DISABLEAUTOSTART]; + if (string.IsNullOrWhiteSpace(disableautostartstring)) config_disablautostart = DISABLEAUTOSTARTDEFAULT; + else if (disableautostartstring.ToLower() == bool.TrueString.ToLower()) config_disablautostart = true; + else if (disableautostartstring.ToLower() != bool.FalseString.ToLower()) config_disablautostart = false; + else config_disablautostart = DISABLEAUTOSTARTDEFAULT; + } + return config_disablautostart.Value; + } + } + private static bool? config_disablautostart = null; + private const string IISHOSTEDSERVICESTARTER = "IISHostedServiceStarter:"; + private const string DISABLEAUTOSTART = IISHOSTEDSERVICESTARTER + "disableautostart"; + private const bool DISABLEAUTOSTARTDEFAULT = false; + private const string NOEXTERNALINITIALIZERSAREREGISTERED = "No external initializers are registered!"; + #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(string websitename = null, string webapplicationname = null, string applicationpoolname = null, bool? disablemode = null, DCLogEntry le = null) + where T: IProcessHostPreloadClient + { + Type serviceAutoStartProviderType = typeof(T); + const string CONFIGFILEDIRECTORY = @"inetsrv\config"; + const string CONFIGFILENAME = @"applicationHost.config"; + //const string FILEPATH = @"C:\temp\applicationHost.config"; + Thread.Sleep(20000); + bool writele = le == null; + if (le == null) { le = new DCLogEntry(LogLevel.Information, $"{typeof(WebServerHostedServiceStarter).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("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); + + if (!disablemode.HasValue) disablemode = Config_DisablAutoStart; + le.AddDataField("DisablAautoStart", disablemode.Value); + + string filecontent; + bool configchanged; + lock (lockerFile) + { + bool usefilestream = false; + if (usefilestream) + { + FileStream file=null; StreamReader reader = null; StreamWriter writer = null; + try + { + int opentriescounter = 0; + while (true) + { + try { file = new FileStream(configfilepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); break; } + catch + { + if (opentriescounter++ > 5) throw new Exception("ERROR! in accessing config file. Maybe it is open in other application!"); + Thread.Sleep(20); + } + } + + reader = new StreamReader(file, Encoding.ASCII); + filecontent = ProcessFileContent(le, reader.ReadToEnd(), applicationpoolname, websitename, webapplicationname, autostartprovidername, serviceAutoStartProviderAssassemblyName, serviceAutoStartProviderTypeFullName, disablemode.Value); + configchanged = filecontent != null; + if (configchanged) + { + writer = new StreamWriter(file, Encoding.ASCII); + writer.Write(filecontent); + } + } + finally { try { writer?.Dispose(); } catch { } try { reader?.Dispose();} catch { } try { file?.Dispose(); } catch { } } + } + else + { + filecontent = ProcessFileContent(le, System.IO.File.ReadAllText(configfilepath), applicationpoolname, websitename, webapplicationname, autostartprovidername, serviceAutoStartProviderAssassemblyName, serviceAutoStartProviderTypeFullName, disablemode.Value); + configchanged = filecontent != null; + if (configchanged) System.IO.File.WriteAllText(configfilepath, filecontent); + } + } + string modetxt = disablemode.Value ? "DISABLED" : "ENABLED"; + le.AddDataField("SetupAutoStart SUCCESS RESULT",configchanged ? modetxt : $"NO CHANGE, ALREADY {modetxt}"); + } + catch (Exception ex) { le.AddDataField("SetupAutoStart EXCEPTION",ex.Message); le.SetLogLevel(LogLevel.Error); return; } + finally { if (writele) le.Write(); } + } + private static string ProcessFileContent(DCLogEntry le, string filecontent,string applicationpoolname,string websitename,string webapplicationname,string autostartprovidername,string serviceAutoStartProviderAssassemblyName, string serviceAutoStartProviderTypeFullName,bool disablemode) + { + const string SYSTEMAPPLICATIONHOST_ELEMENT = "system.applicationHost"; + const string APPLICATIONPOOLS_ELEMENT = "applicationPools"; + const string SITES_ELEMENT = "sites"; + const string SERVICEAUTOSTARTPROVIDERS_ELEMENT = "serviceAutoStartProviders"; + const string SITE_ELEMENT = "site"; + const string APPLICATION_ELEMENT = "application"; + const string ADD_ELEMENT = "add"; + const string NAME_ATTRIBUTE = "name"; + const string TYPE_ATTRIBUTE = "type"; + const string SERVICEAUTOSTARTENABLED_ATTRIBUTE = "serviceAutoStartEnabled"; + const string SERVICEAUTOSTARTPROVIDER_ATTRIBUTE = "serviceAutoStartProvider"; + const string APPLICATIONPOOL_ATTRIBUTE = "applicationPool"; + const string PATH_ATTRIBUTE = "path"; + const string AUTOSTART_ATTRIBUTE = "autoStart"; + const string STARTMODE_ATTRIBUTE = "startMode"; + const string PRELOADENABLED_ATTRIBUTE = "preloadEnabled"; + + XElement configxml = XElement.Parse(filecontent, LoadOptions.PreserveWhitespace); + XElement myconfigrootxml = configxml.Element(XName.Get(SYSTEMAPPLICATIONHOST_ELEMENT)); + + 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 || mysiteapplicationelement == null) return null; + + 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; + + 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; + } + return configxml.ToString(); + } + private static object lockerFile = new Object(); + 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 RemoveElement(string elementtoremovename, XElement elementcontainer,bool removecontainerifnochild=false) + { + bool configchanged = false; + 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 elementtosetname, XElement elementcontainer, string selectorattributename, string selectorattributevalue, string elementvalue, out XElement myelement) + { + bool configchanged = false; + myelement = elementcontainer?.Elements(XName.Get(elementtosetname))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); + if (myelement == null) + { + myelement = new XElement(XName.Get(elementtosetname), ""); + elementcontainer.Add(myelement); + SetOrAddAttribute(selectorattributename, myelement, selectorattributevalue); + configchanged = true; + } + if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } + return configchanged; + } + private static bool SetOrAddAttribute(string attributetosetname, XElement attrcontainer, string attrvalue) + { + bool configchanged = false; + 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 { return System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), Environment.Is64BitOperatingSystem?"Sysnative":""); } + } + private static string GetCurrentApplicationPoolName(string websitename=null) + { + return (new ServerManager()).Sites[websitename ?? System.Web.Hosting.HostingEnvironment.SiteName].Applications? + .FirstOrDefault(app => app.Path == HttpRuntime.AppDomainAppVirtualPath)? + .ApplicationPoolName; + } + #endregion private method - _SetupAutoStart + } +} diff --git a/Vrh.iScheduler/Monitor .cs b/Vrh.iScheduler/Monitor .cs index 50f9dc6..063ffbb 100644 --- a/Vrh.iScheduler/Monitor .cs +++ b/Vrh.iScheduler/Monitor .cs @@ -16,107 +16,237 @@ using System.Data.SqlClient; using System.Xml.Linq; using Hangfire; using Hangfire.Storage; +using System.Web.Hosting; +using System.Configuration; + namespace Vrh.iScheduler { - - public class Monitor : IDisposable + public class WAHostedMonitorHangfire { - public static void InitHangfire(object parameters) + /// + /// A Hangfire alrendszer inicializálását+indítását, vagy a leállítását végzi + /// + /// true:inicalizálás/indítás; false:leállítás + public static void Start() { - string ischedulerMonitorXml = "config=ALMiSchedulerMonitor";//TODO:hogy lehet ezt paraméterben átadni?????? - string ischedulerXml = ""; // vagy "config=ALMiScheduler;"; - var m_xmlp = new iSchedulerXMLProcessor(ischedulerMonitorXml, ischedulerXml); - Monitor.SetiSchedulerCommonXMLProcessor(m_xmlp); - if (m_xmlp.EnableWebAppExecution && m_xmlp.CheckInterval > 0) + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WAHostedMonitorHangfire).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try { + _MonitorHangfireInstance._StartHangfire(le); + string ischedulerMonitorXml = "config=ALMiSchedulerMonitor";//TODO:hogy lehet ezt paraméterben átadni?????? + string ischedulerXml = ""; // vagy "config=ALMiScheduler;"; + var m_xmlp = new iSchedulerXMLProcessor(ischedulerMonitorXml, ischedulerXml); + Monitor.SetiSchedulerCommonXMLProcessor(m_xmlp); + if (m_xmlp.EnableWebAppExecution && m_xmlp.CheckInterval > 0) + { + IntervalCronExpression = Cron.MinuteInterval((int)(m_xmlp.CheckInterval / 60));//"*/1 * * * *" + //RecurringJob.RemoveIfExists("ischedulermonitorcycle"); + RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor().Examination(null), IntervalCronExpression); + //var HanfireJobId = BackgroundJob.Enqueue(() => new Monitor().Examination(null)); + //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), intervalcron); //minutes interval + //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), $"{(int)(m_xmlp.CheckInterval / 60)} * * * *"); // cron expression + } + } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } - //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 * * * *") + public static void Stop() + { + var le = new DCLogEntry(LogLevel.Information, $"{typeof(WAHostedMonitorHangfire).FullName}.{System.Reflection.MethodBase.GetCurrentMethod().Name}"); + try { _MonitorHangfireInstance._StopHangfire(le); } + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); } + finally { le.Write(); } + } - //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" + /// + /// 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 * * * *") + /// + /// Cron samples + /// 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 *" + /// + private static string IntervalCronExpression = null; + private static WAHostedMonitorHangfire _MonitorHangfireInstance = new WAHostedMonitorHangfire(); - //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 *" + private BackgroundJobServer _HangfireBackgroundJobServer { get; set; } + private static readonly object _HangfireStarterLocker = new object(); + private static bool _HangFireRunning = false; + const string HANGFIRE = "HangfireBootstrapper:"; + const string HANGFIREDBCONNECTIONSTRING = HANGFIRE + "dbconnectionstring"; + const string HANGFIRESQLDBCONNECTIONSTRINGNAMEDEFAULT = "HANGFIRESQLDB"; + private void _StartHangfire(DCLogEntry le) + { + lock (_HangfireStarterLocker) + { + le?.AddDataField("HangfireSqlDBConnectionString", Config_HangFireConnectionString); + GlobalConfiguration.Configuration + .UseSqlServerStorage(Config_HangFireConnectionString) + // Specify other options here + ; + _HangfireBackgroundJobServer = new BackgroundJobServer(); + _HangFireRunning = true; + } + } + private void _StopHangfire(DCLogEntry le) + { + lock (_HangfireStarterLocker) + { + if (!_HangFireRunning) return; + le?.AddDataField("Function", nameof(_StopHangfire)); + if (_HangfireBackgroundJobServer != null) { _HangfireBackgroundJobServer.Dispose(); } + _HangFireRunning = false; + } + } + private string Config_HangFireConnectionString + { + get + { + if (config_hangfireconnectionstring == null) + { + string HangfireSqlDBConnectionString = ConfigurationManager.AppSettings[HANGFIREDBCONNECTIONSTRING]; + if (string.IsNullOrWhiteSpace(HangfireSqlDBConnectionString)) HangfireSqlDBConnectionString = HANGFIRESQLDBCONNECTIONSTRINGNAMEDEFAULT; + config_hangfireconnectionstring = ConnectionStringStore.GetSQL(HangfireSqlDBConnectionString); + } + return config_hangfireconnectionstring; + } + } + private string config_hangfireconnectionstring = null; + } +} +namespace Vrh.iScheduler +{ + public class WAHostedMonitor : Monitor + { + public static void Start() + { + MonitorInstance = new Monitor(Config_scheduleMonitorXmlPath, Config_scheduleXmlPath); + MonitorInstance.Start(); + new DCLogEntry(LogLevel.Information, "iSchedulerMonitor started.").Write(); + } + public static void Stop() + { + MonitorInstance.Stop(); + MonitorInstance.Dispose(); + new DCLogEntry(LogLevel.Information, "iSchedulerMonitor stopped.").Write(); + } - string intervalcron = Cron.MinuteInterval((int)(m_xmlp.CheckInterval / 60));//"*/1 * * * *" - //RecurringJob.RemoveIfExists("ischedulermonitorcycle"); - RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor().Examination(null), intervalcron); - //var HanfireJobId = BackgroundJob.Enqueue(() => new Monitor().Examination(null)); - //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), intervalcron); //minutes interval - //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), $"{(int)(m_xmlp.CheckInterval / 60)} * * * *"); // cron expression + #region private members + private static string Config_scheduleMonitorXmlPath + { + get + { + if (config_schedulemonitorxmlpath == null) + { + string schedulemonitorxmlpath = ConfigurationManager.AppSettings[ISCHEDULERMONITORXMLPATH]; + config_schedulemonitorxmlpath = ConnectionStringStore.GetSQL(schedulemonitorxmlpath); + } + return config_schedulemonitorxmlpath; + } + } + private static string config_schedulemonitorxmlpath = null; + private static string Config_scheduleXmlPath + { + get + { + if (config_schedulexmlpath == null) + { + string schedulexmlpath = ConfigurationManager.AppSettings[ISCHEDULERXMLPATH]; + config_schedulexmlpath = ConnectionStringStore.GetSQL(schedulexmlpath); + } + return config_schedulexmlpath; } } + private static string config_schedulexmlpath = null; + const string ISCHEDULER = "iScheduler:"; + const string ISCHEDULERMONITORXMLPATH = ISCHEDULER + "monitorxmlpath"; + const string ISCHEDULERXMLPATH = ISCHEDULER + "xmlpath"; + private static Monitor MonitorInstance; + #endregion private members + } +} + +namespace Vrh.iScheduler +{ + public class Monitor : IDisposable + { #region Enums /// /// Ütemezések lehetséges állapotai. @@ -140,7 +270,7 @@ namespace Vrh.iScheduler } #endregion Enums - #region Privates + #region Private members private Timer m_timer; private iSchedulerXMLProcessor m_xmlp; @@ -149,7 +279,7 @@ namespace Vrh.iScheduler { CommonM_xmlp = m_xmlp; } - #endregion Privates + #endregion Private members #region Constructor @@ -198,6 +328,7 @@ namespace Vrh.iScheduler } #endregion Constructor + #region public methods - Start,Stop public void Start() { new DCLogEntry(LogLevel.Information, "iSchedulerMonitor started.").Write(); @@ -208,6 +339,7 @@ namespace Vrh.iScheduler m_timer.Stop(); new DCLogEntry(LogLevel.Information, "iSchedulerMonitor stopped.").Write(); } + #endregion public methods - Start,Stop #region Private methods diff --git a/Vrh.iScheduler/Properties/AssemblyInfo.cs b/Vrh.iScheduler/Properties/AssemblyInfo.cs index 1819271..6f161dd 100644 --- a/Vrh.iScheduler/Properties/AssemblyInfo.cs +++ b/Vrh.iScheduler/Properties/AssemblyInfo.cs @@ -32,7 +32,7 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.2.1.0")] -[assembly: AssemblyFileVersion("3.2.1.0")] -[assembly: AssemblyInformationalVersion("3.2.1")] +[assembly: AssemblyVersion("3.3.0.0")] +[assembly: AssemblyFileVersion("3.3.0.0")] +[assembly: AssemblyInformationalVersion("3.3.0")] -- libgit2 0.21.2