Commit e76b511841ab3d83d20a74db6ffb58cbb75bce30

Authored by Schwirg László
1 parent 0b366b5a

FileCleanerManager és MaintenanceToolManager/RegexTester elkészítése

Vrh.Log4Pro.MaintenanceConsole/App.config
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 <configuration> 2 <configuration>
  3 + <configSections>
  4 + <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  5 + <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  6 + </configSections>
3 <startup> 7 <startup>
4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" /> 8 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
5 </startup> 9 </startup>
6 <appSettings> 10 <appSettings>
7 - <add key="VRH.XmlParser:root" value="XmlParser.xml"/> 11 + <add key="VRH.XmlParser:root" value="XmlParser.xml" />
8 </appSettings> 12 </appSettings>
9 <runtime> 13 <runtime>
10 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 14 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
@@ -14,4 +18,9 @@ @@ -14,4 +18,9 @@
14 </dependentAssembly> 18 </dependentAssembly>
15 </assemblyBinding> 19 </assemblyBinding>
16 </runtime> 20 </runtime>
  21 + <entityFramework>
  22 + <providers>
  23 + <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  24 + </providers>
  25 + </entityFramework>
17 </configuration> 26 </configuration>
18 \ No newline at end of file 27 \ No newline at end of file
Vrh.Log4Pro.MaintenanceConsole/Config.xml
@@ -70,11 +70,11 @@ @@ -70,11 +70,11 @@
70 70
71 <XmlVar Name="DIR_ROOTBAK">C:\Log4ProISBackups</XmlVar> 71 <XmlVar Name="DIR_ROOTBAK">C:\Log4ProISBackups</XmlVar>
72 <XmlVar Name="MSMQTEST">@DIR_ROOTBAK@\MSMQtests</XmlVar> 72 <XmlVar Name="MSMQTEST">@DIR_ROOTBAK@\MSMQtests</XmlVar>
73 - <XmlVar Name="ILOG">@DIR_ROOTBAK@\VRH.Logfiles</XmlVar>  
74 - <XmlVar Name="REDISLOG">@ILOG@\RedisLog</XmlVar>  
75 - <XmlVar Name="WINEVENTLOGS">@ILOG@\WindowsEventLogs</XmlVar>  
76 - <XmlVar Name="DUMPFOLDER">@ILOG@\WindowsEventLogs</XmlVar>  
77 - <XmlVar Name="SRVLOG">@ILOG@\ServiceScriptLogs</XmlVar> 73 + <XmlVar Name="DIR_ILOG">@DIR_ROOTBAK@\VRH.Logfiles</XmlVar>
  74 + <XmlVar Name="REDISLOG">@DIR_ILOG@\RedisLog</XmlVar>
  75 + <XmlVar Name="DIR_WINEVENTLOGS">@DIR_ILOG@\WindowsEventLogs</XmlVar>
  76 + <XmlVar Name="DUMPFOLDER">@DIR_ILOG@\WindowsEventLogs</XmlVar>
  77 + <XmlVar Name="SRVLOG">@DIR_ILOG@\ServiceScriptLogs</XmlVar>
78 <XmlVar Name="DIR_SYSBAK">@DIR_ROOTBAK@\SystemBackups</XmlVar> 78 <XmlVar Name="DIR_SYSBAK">@DIR_ROOTBAK@\SystemBackups</XmlVar>
79 <XmlVar Name="DIR_DBBAK">@DIR_ROOTBAK@\BackupDBOnly</XmlVar> 79 <XmlVar Name="DIR_DBBAK">@DIR_ROOTBAK@\BackupDBOnly</XmlVar>
80 <XmlVar Name="DIR_BAKTMP">@DIR_ROOTBAK@\TEMP</XmlVar> 80 <XmlVar Name="DIR_BAKTMP">@DIR_ROOTBAK@\TEMP</XmlVar>
@@ -157,4 +157,34 @@ @@ -157,4 +157,34 @@
157 <WebApplication Id="WEBAPP_CP" Name="WebPack" Description="@WEBPACKDESC@" AppPool="WebPack" Website="Default Web Site" InstallDir="@DIR_WEBAPPWEBPACK@" SiteRootDir="@DIR_WEBAPPWEBPACK@" IdentityConfigFile="@WEBPACKIDENTITYCONFIG@" AppPoolUsername="" AppPoolPassword="" AppPoolPipeLineMode="" RecreateSite="false" RecreatePool="true" RecreateApp="true"/> 157 <WebApplication Id="WEBAPP_CP" Name="WebPack" Description="@WEBPACKDESC@" AppPool="WebPack" Website="Default Web Site" InstallDir="@DIR_WEBAPPWEBPACK@" SiteRootDir="@DIR_WEBAPPWEBPACK@" IdentityConfigFile="@WEBPACKIDENTITYCONFIG@" AppPoolUsername="" AppPoolPassword="" AppPoolPipeLineMode="" RecreateSite="false" RecreatePool="true" RecreateApp="true"/>
158 <WebApplication Id="WEBAPP_LOG4PROIS" Name="Log4ProIS" Description="@WEBLOG4PROISDESC@" AppPool="Log4ProIS" Website="Default Web Site" InstallDir="@DIR_WEBAPPLOG4PROIS@" SiteRootDir="@DIR_WEBAPPLOG4PROIS@" IdentityConfigFile="@LOG4PROISIDENTITYCONFIG@" AppPoolUsername="" AppPoolPassword="" AppPoolPipeLineMode="" RecreateSite="false" RecreatePool="true" RecreateApp="true"/> 158 <WebApplication Id="WEBAPP_LOG4PROIS" Name="Log4ProIS" Description="@WEBLOG4PROISDESC@" AppPool="Log4ProIS" Website="Default Web Site" InstallDir="@DIR_WEBAPPLOG4PROIS@" SiteRootDir="@DIR_WEBAPPLOG4PROIS@" IdentityConfigFile="@LOG4PROISIDENTITYCONFIG@" AppPoolUsername="" AppPoolPassword="" AppPoolPipeLineMode="" RecreateSite="false" RecreatePool="true" RecreateApp="true"/>
159 </WebApplications> 159 </WebApplications>
  160 +
  161 + <FileCleaner CleanupDays="7">
  162 + <FolderToClean Directory="@DIR_ILOG@" Recurse="True" RemoveEmptyFolder="False" IncludeMask="L_*">
  163 + <IncludeFullpathRegexp>^.*\\L_.*_(?'YEAR'\d\d\d\d)(?'MONTH'\d\d)(?'DAY'\d\d)_(?'HOUR'\d\d)(?'MINUTE'\d\d)(?'SECOND'\d\d)$</IncludeFullpathRegexp>
  164 + <Conditions OrConditionList="True">
  165 + <Condition Type="TimeStampInName" TimestampConstructor="{YEAR}.{MONTH}.{DAY} {HOUR}:{MINUTE}:{SECOND}" Limit="3" />
  166 + <Condition Type="Length" Limit="80000000" />
  167 + </Conditions>
  168 + </FolderToClean>
  169 + <FolderToClean Directory="@DIR_WINEVENTLOGS@" Recurse="True" RemoveEmptyFolder="False" IncludeMask="*.dmp">
  170 + <IncludeFullpathRegexp>^.*\\VRH.Log4Pro.DataController.WindowsService.exe.*\.dmp$</IncludeFullpathRegexp>
  171 + <Conditions OrConditionList="False">
  172 + <Condition Type="LastWriteTime" Limit="2" />
  173 + </Conditions>
  174 + </FolderToClean>
  175 + <FolderToClean Directory="@DIR_DBBAK@" Recurse="False" RemoveEmptyFolder="False" IncludeMask="SQLDBBackup_Lear*.*">
  176 + <IncludeFullpathRegexp>^.*\\SQLDBBackup_Lear.*_.*_(?'YEAR'\d\d\d\d)(?'MONTH'\d\d)(?'DAY'\d\d)(?'HOUR'\d\d)(?'MINUTE'\d\d)(?'SECOND'\d\d)\.(bak|zip)$</IncludeFullpathRegexp>
  177 + <Conditions>
  178 + <Condition Type="TimeStampInName" TimestampConstructor="{YEAR}.{MONTH}.{DAY} {HOUR}:{MINUTE}:{SECOND}" Limit="7" />
  179 + </Conditions>
  180 + </FolderToClean>
  181 + <FolderToClean Directory="@DIR_SYSBAK@" Recurse="True" RemoveEmptyFolder="True" IncludeMask="Lear*.exe">
  182 + <IncludeFullpathRegexp>^.*\\\d\d\d\d\d\d\d\d\\LearALM_.*_BackupPackage.*(?'YEAR'\d\d\d\d)(?'MONTH'\d\d)(?'DAY'\d\d)(?'HOUR'\d\d)(?'MINUTE'\d\d)(?'SECOND'\d\d).*\.exe$</IncludeFullpathRegexp>
  183 + <Conditions>
  184 + <Condition Type="TimeStampInName" TimestampConstructor="{YEAR}.{MONTH}.{DAY} {HOUR}:{MINUTE}:{SECOND}" Limit="7" />
  185 + </Conditions>
  186 + </FolderToClean>
  187 + <FolderToClean Directory="@DIR_BAKTMP@" Recurse="True" RemoveEmptyFolder="False" IncludeMask="*.*" />
  188 + </FileCleaner>
  189 +
160 </Configuration> 190 </Configuration>
161 \ No newline at end of file 191 \ No newline at end of file
Vrh.Log4Pro.MaintenanceConsole/ConsoleFunction - ColorConsole.cs
@@ -48,7 +48,7 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -48,7 +48,7 @@ namespace Vrh.Log4Pro.MaintenanceConsole
48 Console.ForegroundColor = savecolorF; 48 Console.ForegroundColor = savecolorF;
49 Console.BackgroundColor = savecolorB; 49 Console.BackgroundColor = savecolorB;
50 if (!string.IsNullOrEmpty(bracket)) { Console.Write($"{bracket[1]}"); } 50 if (!string.IsNullOrEmpty(bracket)) { Console.Write($"{bracket[1]}"); }
51 - if (!string.IsNullOrEmpty(prefix)) { Write(suffix); } 51 + if (!string.IsNullOrEmpty(suffix)) { Write(suffix); }
52 } 52 }
53 } 53 }
54 #endregion ColorConsole 54 #endregion ColorConsole
Vrh.Log4Pro.MaintenanceConsole/ConsoleFunction - Menu.cs
@@ -31,7 +31,7 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -31,7 +31,7 @@ namespace Vrh.Log4Pro.MaintenanceConsole
31 31
32 #region public properties 32 #region public properties
33 public List<Item> MenuItemList { get; private set; } = new List<Item>(); 33 public List<Item> MenuItemList { get; private set; } = new List<Item>();
34 - List<string> MenuKeyList { get { return MenuItemList.Select(x => x.Key).ToList(); } } 34 + List<string> MenuKeyList { get { return MenuItemList.Where(x=> !x.Separator).Select(x => x.Key).ToList(); } }
35 #endregion public properties 35 #endregion public properties
36 36
37 #region public tools 37 #region public tools
@@ -85,6 +85,17 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -85,6 +85,17 @@ namespace Vrh.Log4Pro.MaintenanceConsole
85 Console.SetCursorPosition(0, Console.CursorTop); 85 Console.SetCursorPosition(0, Console.CursorTop);
86 foreach (var menuitem in MenuItemList) 86 foreach (var menuitem in MenuItemList)
87 { 87 {
  88 + if (menuitem.Separator && columns == 1)
  89 + {
  90 + Console.SetCursorPosition(columnlength * columncounter + HeaderWidth, Console.CursorTop);
  91 + var seplen = menuitem.SeparatorLength;
  92 + if (menuitem.SeparatorLength==0)
  93 + {
  94 + foreach (var mi in MenuItemList.Where(x=>!x.Separator)) { if (mi.Text.Length > seplen) { seplen = mi.Text.Length; } }
  95 + }
  96 + ColorConsole.WriteLine(new string(menuitem.SeparatorChar, seplen));
  97 + continue;
  98 + }
88 ColorConsole.Write($"["); 99 ColorConsole.Write($"[");
89 ColorConsole.Write($"{i}"); 100 ColorConsole.Write($"{i}");
90 if (!string.IsNullOrEmpty(menuitem.Key) && !menuitem.Key.StartsWith("#$KEY")) 101 if (!string.IsNullOrEmpty(menuitem.Key) && !menuitem.Key.StartsWith("#$KEY"))
@@ -249,7 +260,15 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -249,7 +260,15 @@ namespace Vrh.Log4Pro.MaintenanceConsole
249 } 260 }
250 private Menu.Item GetItem(int ix) 261 private Menu.Item GetItem(int ix)
251 { 262 {
252 - return MenuItemList.ElementAt(ix); 263 + var i = 0;
  264 + foreach (var mi in MenuItemList)
  265 + {
  266 + if (mi.Separator) { continue; }
  267 + if (i == ix) return mi;
  268 + i++;
  269 + }
  270 + return null;
  271 + //return MenuItemList.ElementAt(ix);
253 } 272 }
254 private int GetItemIx(string itemkey) 273 private int GetItemIx(string itemkey)
255 { 274 {
@@ -271,8 +290,18 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -271,8 +290,18 @@ namespace Vrh.Log4Pro.MaintenanceConsole
271 } 290 }
272 } 291 }
273 #endregion private tools 292 #endregion private tools
  293 + public class ItemSeparator : Item
  294 + {
  295 + public ItemSeparator(char c = '-', int length = 0) : base()
  296 + {
  297 + Separator = true;
  298 + SeparatorChar = c;
  299 + SeparatorLength = length;
  300 + }
  301 + }
274 public class Item 302 public class Item
275 { 303 {
  304 + public Item() { }
276 public Item(string key, string text, MenuItemExecutorFunc executor = null, object parameters = null) 305 public Item(string key, string text, MenuItemExecutorFunc executor = null, object parameters = null)
277 { 306 {
278 Key = key; 307 Key = key;
@@ -284,6 +313,10 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -284,6 +313,10 @@ namespace Vrh.Log4Pro.MaintenanceConsole
284 public string Text; 313 public string Text;
285 public MenuItemExecutorFunc Executor; 314 public MenuItemExecutorFunc Executor;
286 public object Parameters; 315 public object Parameters;
  316 +
  317 + public bool Separator = false;
  318 + public char SeparatorChar = '-';
  319 + public int SeparatorLength = 0;
287 } 320 }
288 } 321 }
289 } 322 }
Vrh.Log4Pro.MaintenanceConsole/Manager - FileCleanerManager.cs 0 → 100644
@@ -0,0 +1,504 @@ @@ -0,0 +1,504 @@
  1 +using System;
  2 +using System.IO;
  3 +using System.Configuration.Install;
  4 +using System.Collections.Generic;
  5 +using System.Linq;
  6 +using System.ServiceProcess;
  7 +using System.Text;
  8 +using System.Threading;
  9 +using System.Threading.Tasks;
  10 +
  11 +using Microsoft.Web.Administration;
  12 +using System.Management;
  13 +using System.Diagnostics;
  14 +
  15 +using Vrh.XmlProcessing;
  16 +using System.Xml.Linq;
  17 +using System.Text.RegularExpressions;
  18 +
  19 +namespace Vrh.Log4Pro.MaintenanceConsole
  20 +{
  21 + #region FileCleanerManager class
  22 + public static class FileCleanerManager
  23 + {
  24 + #region Execute
  25 + public static object Execute(object o1 = null, object o2 = null)
  26 + {
  27 + string xmlcs = "file=Config.Xml;element=FileCleaner;";
  28 + var config = new FileCleanerManagerCoreXmlProcessor(xmlcs, "", "hu-HU");
  29 +
  30 + var menufunctions = new Menu("Manage Folders To Clean", "Select the management function!")
  31 + .AddMenuItem(new Menu.Item("CLN", "Clean folder", CleanFolder))
  32 + .SetSelectionMode(Menu.SelectionMode.Single);
  33 +
  34 + while (true)
  35 + {
  36 + Menu.Selection sr;
  37 +
  38 + menufunctions.DisplayTitle();
  39 + var menuservices = DisplayFolders(config);
  40 + menufunctions.DisplayItems();
  41 + sr = menufunctions.Select();
  42 + if (sr.Result == Menu.SelectionResult.Exit) { break; }
  43 + else if (sr.Result == Menu.SelectionResult.None) { continue; }
  44 + else if (sr.Result == Menu.SelectionResult.Error) { continue; }
  45 + menufunctions.SetParameters(sr,config);
  46 + menufunctions.Execute(sr.SelectedKeyList);
  47 + }
  48 + return null;
  49 + }
  50 + #endregion Execute
  51 +
  52 + #region First level Executors with UI
  53 + private static object CleanFolder(object parameter, object o)
  54 + {
  55 + var config = parameter as FileCleanerManagerCoreXmlProcessor;
  56 +
  57 + var menufolders = DisplayFolders(config, $"Select the folder(s) to manage with function '{nameof(CleanFolder)}'!", silent: true);
  58 +
  59 + Menu.Selection sr = menufolders.Select();
  60 + if (sr.Result == Menu.SelectionResult.Exit) { return o; }
  61 + else if (sr.Result == Menu.SelectionResult.None) { return o; }
  62 + else if (sr.Result == Menu.SelectionResult.Error) { return o; }
  63 + else if (sr.Result == Menu.SelectionResult.Ok) { }
  64 + else { }
  65 + foreach (var p in sr.SelectedParameterList)
  66 + {
  67 + FolderToClean ftc = p as FolderToClean;
  68 + try
  69 + {
  70 + var di = new DirectoryInfo(ftc.Xml_DirectoryPath);
  71 + var success = FileCleanerManagerCore.CleanFolderFiles(di,ftc, delete: true);
  72 + ColorConsole.WriteLine($"Folder cleaned. Name:{ftc.Xml_DirectoryPath}", ConsoleColor.Green);
  73 + }
  74 + catch (Exception ex)
  75 + {
  76 + ColorConsole.WriteLine(ex.Message, ConsoleColor.Red);
  77 + }
  78 + }
  79 + return o;
  80 + }
  81 + #endregion First level Executors with UI
  82 +
  83 + #region private methods
  84 + #region private DisplayFolders
  85 + private static Menu DisplayFolders(FileCleanerManagerCoreXmlProcessor config,string prompt = null,bool silent=false)
  86 + {
  87 + List<FolderToClean> fctdefList = config.GetDefinitionList();
  88 + var menufct = new Menu("Folder to clean",prompt)
  89 + .SetMenuItemDisplayer(DisplayFolderInfo)
  90 + .SetSelectionMode(Menu.SelectionMode.Multi)
  91 + .SetHeaderWidth(4);
  92 + menufct.ClearMenuItemList();
  93 + foreach (var fctdef in fctdefList)
  94 + {
  95 + var fi = CollectFolderInfo(fctdef);
  96 + menufct.AddMenuItem(new Menu.Item(null, null, null, fi));
  97 + }
  98 + if (!silent) { menufct.DisplayItems(1); }
  99 + return menufct;
  100 + }
  101 + #endregion private DisplayFolders
  102 + #region private method: DisplayFolderInfo
  103 + private static object DisplayFolderInfo(object obj, int lineix)
  104 + {
  105 + FolderToClean ws = obj as FolderToClean;
  106 + if (lineix == 0)
  107 + {
  108 + ColorConsole.Write($"{ws.Xml_DirectoryPath}", ConsoleColor.Black, ConsoleColor.White);
  109 + var existscolor = ws.FolderExists ? ConsoleColor.Green : ConsoleColor.Red;
  110 + var existstext = ws.FolderExists ? "Exists" : "Missing";
  111 + ColorConsole.WriteLine(existstext, existscolor, bracket: "[]", prefix: " ", suffix: ". ");
  112 + return " ";
  113 + }
  114 + else if (lineix == 1)
  115 + {
  116 + if (ws.FolderExists)
  117 + {
  118 + ColorConsole.Write(ws.SizeSelectedBeforeClean.ToString(), ConsoleColor.Yellow, prefix: "Size of filtered files now:");
  119 + ColorConsole.Write(ws.SizeSelectedAfterClean.ToString(), ConsoleColor.Yellow, prefix: ", after cleaning:", suffix: ". ");
  120 + ColorConsole.Write(ws.SizeSelectedCleaned.ToString(), ConsoleColor.Red, prefix: "To clean:", suffix: ".");
  121 + ColorConsole.WriteLine(" ");
  122 + return " ";
  123 + }
  124 + return "";
  125 + }
  126 + else if (lineix == 2)
  127 + {
  128 + ColorConsole.Write($"{ws.Xml_CleanupDays}", ConsoleColor.Yellow, prefix: "Cleanup days:", bracket: "[]");
  129 + var fc2 = ws.Xml_Recurse ? ConsoleColor.Green : ConsoleColor.Yellow;
  130 + ColorConsole.Write($"{ws.Xml_Recurse}", fc2, prefix: ", Recurse:", bracket: "[]");
  131 + var fc0 = ws.Xml_RemoveEmptyFolder ? ConsoleColor.Green : ConsoleColor.Yellow;
  132 + ColorConsole.Write($"{ws.Xml_RemoveEmptyFolder}", fc0, prefix: ", Remove empty folder:", bracket: "[]");
  133 + ColorConsole.WriteLine(ws.Xml_IncludeMask, ConsoleColor.Yellow, prefix: ", Include mask:");
  134 + return " ";
  135 + }
  136 + else // if (lineix == INDEXBASE)
  137 + {
  138 + const int INDEXBASE = 3; // a linex következő indexe kerüljön ide !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  139 + if (ws.Xml_ConditionList.Count <= lineix - INDEXBASE) { return null; }
  140 + var c = ws.Xml_ConditionList.ElementAt(lineix- INDEXBASE);
  141 + if (c != null)
  142 + {
  143 + if (lineix != INDEXBASE) { ColorConsole.Write(ws.Xml_OrConditionList ? "OR" : "AND", ConsoleColor.Yellow,suffix:" "); }
  144 + ColorConsole.Write("Condition:");
  145 + ColorConsole.Write(c.Type.ToString(),ConsoleColor.Yellow, prefix: " Type:");
  146 + if (c.Type==FolderToClean.ConditionType.TimeStampInName) { ColorConsole.Write(c.TimestampConstructor, ConsoleColor.Yellow, prefix: ", TS constructor:"); }
  147 + ColorConsole.Write(c.Limit.ToString(), ConsoleColor.Yellow, prefix: ", Limit:",suffix: c.Type == FolderToClean.ConditionType.Length ? "bytes" : "days");
  148 + ColorConsole.WriteLine();
  149 + return " ";
  150 + }
  151 + }
  152 + return null;
  153 + }
  154 + #endregion private method: DisplayFolderInfo
  155 + #region private CollectFolderInfo
  156 + private static FolderToClean CollectFolderInfo(FolderToClean ftc)
  157 + {
  158 + ftc.SizeFolderTotal= 0;
  159 + ftc.SizeSelectedBeforeClean = 0;
  160 + ftc.SizeSelectedCleaned = 0;
  161 + ftc.FolderExists = Directory.Exists(ftc.Xml_DirectoryPath);
  162 + if (ftc.FolderExists)
  163 + {
  164 + var di = new DirectoryInfo(ftc.Xml_DirectoryPath);
  165 + ftc.SizeFolderTotal = FileCleanerManagerCore.DirSize(di,"*","",ftc.Xml_Recurse);
  166 + ftc.SizeSelectedBeforeClean = FileCleanerManagerCore.DirSize(di, ftc.Xml_IncludeMask, ftc.Xml_IncludeFullpathRegexp, ftc.Xml_Recurse);
  167 + ftc.SizeSelectedCleaned = FileCleanerManagerCore.CleanFolderFiles(di,ftc,delete:false);
  168 + }
  169 + return ftc;
  170 + }
  171 + #endregion private CollectFolderInfo
  172 + #endregion private methods
  173 + }
  174 + #endregion FileCleanerManager class
  175 +
  176 + #region class FileCleanerManagerCore
  177 + public static class FileCleanerManagerCore
  178 + {
  179 + #region public GetDirSize
  180 + public static long DirSize(DirectoryInfo d, string filenamemask, string filefullpathregex, bool recurse)
  181 + {
  182 + long size = 0;
  183 + // Add file sizes.
  184 + FileInfo[] fis = d.GetFiles(filenamemask, SearchOption.TopDirectoryOnly);
  185 + foreach (FileInfo fi in fis) { if (Regex.Match(fi.FullName, filefullpathregex).Success) { size += fi.Length; } }
  186 + // Add subdirectory sizes.
  187 + if (recurse)
  188 + {
  189 + DirectoryInfo[] dis = d.GetDirectories();
  190 + foreach (DirectoryInfo di in dis) { size += DirSize(di, filenamemask, filefullpathregex, recurse); }
  191 + }
  192 + return size;
  193 + }
  194 + #endregion public GetDirSize
  195 + #region public FileIsToDelete
  196 + public static bool FileIsToDelete(FileInfo fi, FolderToClean ftc)
  197 + {
  198 + var rgx = new Regex(ftc.Xml_IncludeFullpathRegexp);
  199 + var rgxmatch = rgx.Match(fi.FullName);
  200 + if (rgxmatch.Success)
  201 + {
  202 + var daystodelete = ftc.Xml_CleanupDays;
  203 + var conditionlist = ftc.Xml_ConditionList;
  204 + if (conditionlist == null || !conditionlist.Any()) { return true; }
  205 +
  206 + bool fileistodeleteResult = !ftc.Xml_OrConditionList;
  207 +
  208 + var groupnames = rgx.GetGroupNames();
  209 + var groupnamevalues = new Dictionary<string, string>();
  210 + foreach (var rgxgn in groupnames) { groupnamevalues.Add(rgxgn, rgxmatch.Groups[rgxgn].Value); }
  211 +
  212 + foreach (var c in ftc.Xml_ConditionList)
  213 + {
  214 + bool conditionresult = false;
  215 + if (c.Type == FolderToClean.ConditionType.TimeStampInName)
  216 + {
  217 + var fileTSstr = VRH.Common.StringConstructor.ResolveConstructor<string>(groupnamevalues, c.TimestampConstructor, "{}");
  218 + try { var fileTS = DateTime.Parse(fileTSstr); conditionresult = DateTime.Now.Subtract(fileTS).TotalDays > c.Limit; }
  219 + catch
  220 + {
  221 + var tscn = nameof(FolderToClean.XmlStructure.FolderToClean.Conditions.Condition.Attributes.TimestampConstructor);
  222 + var fprn = nameof(FolderToClean.XmlStructure.FolderToClean.IncludeFullpathRegexp);
  223 + throw new Exception(
  224 + $"Error in condition, type {FolderToClean.ConditionType.TimeStampInName}. {tscn} or {fprn} value incorrect!"
  225 + + $"\n Folder: {ftc.Xml_DirectoryPath}"
  226 + + $"\n {tscn} : {c.TimestampConstructor}"
  227 + + $"\n {tscn} after substitution: {fileTSstr}");
  228 + }
  229 + }
  230 + else if (c.Type == FolderToClean.ConditionType.CreationTime)
  231 + {
  232 + conditionresult = DateTime.Now.Subtract(fi.CreationTime).TotalDays > c.Limit;
  233 + }
  234 + else if (c.Type == FolderToClean.ConditionType.LastAccessTime)
  235 + {
  236 + conditionresult = DateTime.Now.Subtract(fi.LastAccessTime).TotalDays > c.Limit;
  237 + }
  238 + else if (c.Type == FolderToClean.ConditionType.LastWriteTime)
  239 + {
  240 + conditionresult = DateTime.Now.Subtract(fi.LastWriteTime).TotalDays > c.Limit;
  241 + }
  242 + else if (c.Type == FolderToClean.ConditionType.Length)
  243 + {
  244 + conditionresult = fi.Length > c.Limit;
  245 + }
  246 +
  247 + fileistodeleteResult = ftc.Xml_OrConditionList ? fileistodeleteResult || conditionresult : fileistodeleteResult = fileistodeleteResult && conditionresult;
  248 + if ((ftc.Xml_OrConditionList && fileistodeleteResult) || (!ftc.Xml_OrConditionList && !fileistodeleteResult)) { break; }
  249 + }
  250 + return fileistodeleteResult;
  251 + }
  252 + return false;
  253 + }
  254 + #endregion public FileIsToDelete
  255 + #region public CleanFiles
  256 + public static long CleanFolderFiles(DirectoryInfo d,FolderToClean ftc, bool delete)
  257 + {
  258 + int daystodelete = ftc.Xml_CleanupDays;
  259 + long cleanedsize = 0;
  260 + // Add file sizes.
  261 + FileInfo[] fis = d.GetFiles(ftc.Xml_IncludeMask, SearchOption.TopDirectoryOnly);
  262 + foreach (FileInfo fi in fis)
  263 + {
  264 + if (FileIsToDelete(fi, ftc))
  265 + {
  266 + var fl = fi.Length;
  267 + try
  268 + {
  269 + if (delete) { File.Delete(fi.FullName); }
  270 + cleanedsize += fl;
  271 + }
  272 + catch { }
  273 + }
  274 + }
  275 + // Add subdirectory sizes.
  276 + if (ftc.Xml_Recurse)
  277 + {
  278 + foreach (DirectoryInfo di in d.GetDirectories()) { cleanedsize += CleanFolderFiles(di, ftc, delete); }
  279 + }
  280 + if (ftc.Xml_RemoveEmptyFolder && DirSize(d, ftc.Xml_IncludeMask, ftc.Xml_IncludeFullpathRegexp, ftc.Xml_Recurse) == 0)
  281 + {
  282 + try { Directory.Delete(d.FullName, ftc.Xml_Recurse); } catch { }
  283 + }
  284 + return cleanedsize;
  285 + }
  286 + #endregion public CleanFiles
  287 + }
  288 + #endregion class FileCleanerManagerCore
  289 +
  290 + #region FileCleanerManagerCoreXmlProcessor class
  291 + public class FileCleanerManagerCoreXmlProcessor : XmlParser
  292 + {
  293 + private List<FolderToClean> _foldertocleanlist;
  294 + private int commoncleanupdays;
  295 + #region constructor
  296 + public FileCleanerManagerCoreXmlProcessor(string xmlcs, string basefolder, string lcid) : base(xmlcs, basefolder, lcid, null)
  297 + {
  298 + _foldertocleanlist = new List<FolderToClean>();
  299 + commoncleanupdays = GetValue(nameof(FolderToClean.XmlStructure.Attributes.CleanupDays),this.RootElement, FolderToClean.XmlStructure.Attributes.CleanupDays.Values.DEFAULT);
  300 + var ftcxmllist = GetAllXElements(nameof(FolderToClean.XmlStructure.FolderToClean));
  301 + if (ftcxmllist != null && ftcxmllist.Any())
  302 + {
  303 + foreach (var ftcxml in ftcxmllist) { var ws = new FolderToClean(ftcxml, commoncleanupdays); if (ws.Valid) { _foldertocleanlist.Add(ws); } }
  304 + }
  305 + }
  306 + #endregion constructor
  307 + #region GetDefinitionList
  308 + public List<FolderToClean> GetDefinitionList() { return _foldertocleanlist; }
  309 + #endregion GetDefinitionList
  310 + }
  311 + #endregion FileCleanerManagerCoreXmlProcessor class
  312 + #region WindowsService class
  313 + public class FolderToClean : XmlLinqBase
  314 + {
  315 + #region fields
  316 + public bool Valid = true;
  317 + public string Xml_DirectoryPath;
  318 + public bool Xml_Recurse;
  319 + public bool Xml_RemoveEmptyFolder;
  320 + public string Xml_IncludeMask;
  321 + public string Xml_IncludeFullpathRegexp;
  322 + public bool Xml_OrConditionList = true;
  323 + public List<Condition> Xml_ConditionList;
  324 + public int Xml_CleanupDays;
  325 +
  326 + public bool FolderExists;
  327 + public long SizeFolderTotal;
  328 + public long SizeSelectedBeforeClean;
  329 + public long SizeSelectedAfterClean { get { return SizeSelectedBeforeClean - SizeSelectedCleaned; } }
  330 + public long SizeSelectedCleaned;
  331 + #endregion fields
  332 +
  333 + #region basic constructor
  334 + public FolderToClean() { }
  335 + #endregion basic constructor
  336 + #region xml constructor
  337 + public FolderToClean(XElement foldertocleanxml,int commoncleanupdays)
  338 + {
  339 + Valid = true;
  340 + string ATTRIBUTEMANDATORY = nameof(XmlStructure.FolderToClean) + " attribute is mandatory! Name: {0}";
  341 + Xml_DirectoryPath = foldertocleanxml.Attribute(XName.Get(nameof(XmlStructure.FolderToClean.Attributes.Directory)))?.Value;
  342 + if (string.IsNullOrWhiteSpace(Xml_DirectoryPath)) { throw new ApplicationException(string.Format(ATTRIBUTEMANDATORY, nameof(XmlStructure.FolderToClean.Attributes.Directory))); }
  343 + Xml_Recurse = GetValue(nameof(XmlStructure.FolderToClean.Attributes.Recurse), foldertocleanxml, XmlStructure.FolderToClean.Attributes.Recurse.Values.DEFAULT);
  344 + Xml_RemoveEmptyFolder = GetValue(nameof(XmlStructure.FolderToClean.Attributes.RemoveEmptyFolder), foldertocleanxml, XmlStructure.FolderToClean.Attributes.RemoveEmptyFolder.Values.DEFAULT);
  345 + Xml_IncludeMask = GetValue(nameof(XmlStructure.FolderToClean.Attributes.IncludeMask), foldertocleanxml, XmlStructure.FolderToClean.Attributes.IncludeMask.Values.DEFAULT);
  346 + Xml_IncludeFullpathRegexp = GetValue(GetXElement(foldertocleanxml,nameof(XmlStructure.FolderToClean.IncludeFullpathRegexp)), XmlStructure.FolderToClean.IncludeFullpathRegexp.Values.DEFAULT);
  347 + Xml_CleanupDays = GetValue(GetXElement(foldertocleanxml,nameof(XmlStructure.FolderToClean.Attributes.CleanupDays)), commoncleanupdays);
  348 + Xml_ConditionList = new List<Condition>();
  349 + //var conditionxmlList = GetAllXElements(foldertocleanxml, nameof(XmlStructure.FolderToClean.Conditions), nameof(XmlStructure.FolderToClean.Conditions.Condition));
  350 + var conditionsxml = foldertocleanxml.Element(XName.Get(nameof(XmlStructure.FolderToClean.Conditions)));
  351 + var conditionxmlList = conditionsxml?.Elements(XName.Get(nameof(XmlStructure.FolderToClean.Conditions.Condition)));
  352 + if (conditionxmlList!=null && conditionxmlList.Any())
  353 + {
  354 + Xml_OrConditionList = GetValue(nameof(XmlStructure.FolderToClean.Conditions.Attributes.OrConditionList), conditionsxml, XmlStructure.FolderToClean.Conditions.Attributes.OrConditionList.Values.DEFAULT);
  355 + foreach (var conditionxml in conditionxmlList) { Xml_ConditionList.Add(new Condition(conditionxml)); }
  356 + }
  357 + }
  358 + #endregion xml constructor
  359 + #region cloner constructor
  360 + public FolderToClean(FolderToClean ftc)
  361 + {
  362 + Valid = ftc.Valid;
  363 + Xml_DirectoryPath = ftc.Xml_DirectoryPath;
  364 + Xml_Recurse = ftc.Xml_Recurse;
  365 + Xml_RemoveEmptyFolder = ftc.Xml_RemoveEmptyFolder;
  366 + Xml_IncludeMask = ftc.Xml_IncludeMask;
  367 + Xml_IncludeFullpathRegexp = ftc.Xml_IncludeFullpathRegexp;
  368 + Xml_OrConditionList = ftc.Xml_OrConditionList;
  369 + Xml_CleanupDays = ftc.Xml_CleanupDays;
  370 + Xml_ConditionList = ftc.Xml_ConditionList.Select(c=>new Condition(c)).ToList(); ;
  371 + }
  372 + #endregion cloner constructor
  373 + #region Condition
  374 + public enum ConditionType { Length, TimeStampInName, LastWriteTime, LastAccessTime, CreationTime, }
  375 + public class Condition: XmlLinqBase
  376 + {
  377 + #region cloner constructor
  378 + public Condition(Condition c)
  379 + {
  380 + Type = c.Type;
  381 + TimestampConstructor = c.TimestampConstructor;
  382 + Limit = c.Limit;
  383 + }
  384 + #endregion cloner constructor
  385 + #region constructor
  386 + public Condition(XElement cxml)
  387 + {
  388 + var typestr = GetValue(nameof(XmlStructure.FolderToClean.Conditions.Condition.Attributes.Type), cxml, XmlStructure.FolderToClean.Conditions.Condition.Attributes.Type.Values.DEFAULT);
  389 + this.Type = (ConditionType)Enum.Parse(typeof(ConditionType),typestr);
  390 + TimestampConstructor = GetValue(nameof(XmlStructure.FolderToClean.Conditions.Condition.Attributes.TimestampConstructor), cxml, XmlStructure.FolderToClean.Conditions.Condition.Attributes.TimestampConstructor.Values.DEFAULT);
  391 + Limit = GetValue(nameof(XmlStructure.FolderToClean.Conditions.Condition.Attributes.Limit), cxml, XmlStructure.FolderToClean.Conditions.Condition.Attributes.Limit.Values.DEFAULT);
  392 + }
  393 + #endregion constructor
  394 + public ConditionType Type;
  395 + public string TimestampConstructor;
  396 + public int Limit;
  397 + }
  398 + #endregion Condition
  399 + #region XmlStructure
  400 + public static class XmlStructure
  401 + {
  402 + public static class Attributes
  403 + {
  404 + public static class CleanupDays
  405 + {
  406 + public static class Values
  407 + {
  408 + public const int DEFAULT = 7;
  409 + }
  410 + }
  411 + }
  412 + public static class FolderToClean
  413 + {
  414 + public static class Attributes
  415 + {
  416 + public static class Directory { }
  417 + public static class CleanupDays
  418 + {
  419 + public static class Values
  420 + {
  421 + public const int DEFAULT = XmlStructure.Attributes.CleanupDays.Values.DEFAULT;
  422 + }
  423 + }
  424 + public static class Recurse
  425 + {
  426 + public static class Values
  427 + {
  428 + public const bool DEFAULT = false;
  429 + }
  430 + }
  431 + public static class RemoveEmptyFolder
  432 + {
  433 + public static class Values
  434 + {
  435 + public const bool DEFAULT = false;
  436 + }
  437 + }
  438 + public static class IncludeMask
  439 + {
  440 + public static class Values
  441 + {
  442 + public const string DEFAULT = "*.*";
  443 + }
  444 + }
  445 + }
  446 + public static class IncludeFullpathRegexp
  447 + {
  448 + public static class Values
  449 + {
  450 + public const string DEFAULT = "";
  451 + }
  452 + }
  453 + public static class Conditions
  454 + {
  455 + public static class Attributes
  456 + {
  457 + public static class OrConditionList
  458 + {
  459 + public static class Values
  460 + {
  461 + public const bool DEFAULT = true;
  462 + }
  463 + }
  464 + }
  465 + public static class Condition
  466 + {
  467 + public static class Attributes
  468 + {
  469 + public static class Type
  470 + {
  471 + public static class Values
  472 + {
  473 + public const string DEFAULT = nameof(ConditionType.LastWriteTime);
  474 + public static class TimeStampInName { }
  475 + public static class Length { }
  476 + public static class LastWriteTime { }
  477 + public static class LastAccessTime { }
  478 + public static class CreationTime { }
  479 + }
  480 + }
  481 + public static class TimestampConstructor
  482 + {
  483 + public static class Values
  484 + {
  485 + public const string DEFAULT = "{YEAR}.{MONTH}.{DAY} {HOUR}:{MINUTE}:{SECOND}";
  486 + }
  487 + }
  488 + public static class Limit
  489 + {
  490 + public static class Values
  491 + {
  492 + public const int DEFAULT = XmlStructure.Attributes.CleanupDays.Values.DEFAULT;
  493 + }
  494 + }
  495 + }
  496 + }
  497 + }
  498 + }
  499 + }
  500 + #endregion XmlStructure
  501 + }
  502 + #endregion WindowsService class
  503 +
  504 +}
Vrh.Log4Pro.MaintenanceConsole/Manager - MaintenanceToolManager.cs 0 → 100644
@@ -0,0 +1,124 @@ @@ -0,0 +1,124 @@
  1 +using System;
  2 +using System.IO;
  3 +using System.Configuration.Install;
  4 +using System.Collections.Generic;
  5 +using System.Linq;
  6 +using System.ServiceProcess;
  7 +using System.Text;
  8 +using System.Threading;
  9 +using System.Threading.Tasks;
  10 +
  11 +using Microsoft.Web.Administration;
  12 +using System.Management;
  13 +using System.Diagnostics;
  14 +
  15 +using Vrh.XmlProcessing;
  16 +using System.Xml.Linq;
  17 +using System.Text.RegularExpressions;
  18 +
  19 +namespace Vrh.Log4Pro.MaintenanceConsole
  20 +{
  21 + #region MaintenanceTools class
  22 + public static class MaintenanceToolManager
  23 + {
  24 + #region Execute
  25 + public static object Execute(object o1 = null, object o2 = null)
  26 + {
  27 + string xmlcs = "file=Config.Xml;element=WindowsServices;";
  28 + var config = new MaintenanceToolsXmlProcessor(xmlcs, "", "hu-HU");
  29 +
  30 + var menufunctions = new Menu("Maintenance Tools", "Select function!")
  31 + .AddMenuItem(new Menu.Item("RGX", "Regex tester", RegexTester))
  32 + .AddMenuItem(new Menu.Item("TL1", "Tool #1", Tool1))
  33 + .AddMenuItem(new Menu.Item("TL2", "Tool #2", Tool2))
  34 + .SetSelectionMode(Menu.SelectionMode.Single);
  35 +
  36 + while (true)
  37 + {
  38 + Menu.Selection sr;
  39 +
  40 + menufunctions.DisplayTitle();
  41 + menufunctions.DisplayItems();
  42 + sr = menufunctions.Select();
  43 + if (sr.Result == Menu.SelectionResult.Exit) { break; }
  44 + else if (sr.Result == Menu.SelectionResult.None) { continue; }
  45 + else if (sr.Result == Menu.SelectionResult.Error) { continue; }
  46 + menufunctions.SetParameters(sr,config);
  47 + menufunctions.Execute(sr.SelectedKeyList);
  48 + }
  49 + return null;
  50 + }
  51 + #endregion Execute
  52 +
  53 + #region First level Executors with UI
  54 + #region RegexTester
  55 + private static object RegexTester(object parameter, object o)
  56 + {
  57 + var config = parameter as MaintenanceToolsXmlProcessor;
  58 + var regexptesterconfig = config.RegexpTesterConfig;
  59 + while(true)
  60 + {
  61 + var regexstr = ColorConsole.ReadLine($"Enter REGEX to test with:", ConsoleColor.Yellow);
  62 + if (regexstr == "EX") { break; }
  63 + var teststr = ColorConsole.ReadLine($"Enter STRING to test:", ConsoleColor.Yellow);
  64 + if (teststr == "EX") { break; }
  65 +
  66 + var rgx = new Regex(regexstr, RegexOptions.None);
  67 + var regexmatch = rgx.Match(teststr);
  68 + if (!regexmatch.Success)
  69 + {
  70 + ColorConsole.WriteLine($"No match.", ConsoleColor.Red);
  71 + }
  72 + else
  73 + {
  74 + ColorConsole.WriteLine($"Match.", ConsoleColor.Green);
  75 + ColorConsole.WriteLine($"Named groups:");
  76 + var groups = new Dictionary<string, string>();
  77 + foreach (var groupname in rgx.GetGroupNames())
  78 + {
  79 + ColorConsole.Write(groupname,bracket:"[]", suffix: " = ");
  80 + ColorConsole.WriteLine(regexmatch.Groups[groupname].Value, ConsoleColor.Yellow);
  81 + }
  82 + }
  83 + ColorConsole.ReadLine($"Press any key to continue...");
  84 + }
  85 + return o;
  86 + }
  87 + #endregion RegexTester
  88 + #region Tool templates
  89 + private static object Tool1(object parameter, object o)
  90 + {
  91 + var config = parameter as MaintenanceToolsXmlProcessor;
  92 + ColorConsole.ReadLine($"{nameof(Tool1)} is not ready yet...",ConsoleColor.Yellow);
  93 + return o;
  94 + }
  95 + private static object Tool2(object parameter, object o)
  96 + {
  97 + var config = parameter as MaintenanceToolsXmlProcessor;
  98 + ColorConsole.ReadLine($"{nameof(Tool2)} is not ready yet...", ConsoleColor.Yellow);
  99 + return o;
  100 + }
  101 + #endregion Tool templates
  102 + #endregion First level Executors with UI
  103 + }
  104 + #endregion MaintenanceTools class
  105 +
  106 + #region MaintenanceToolsXmlProcessor class
  107 + public class MaintenanceToolsXmlProcessor : XmlParser
  108 + {
  109 + public XElement RegexpTesterConfig;
  110 + #region constructor
  111 + public MaintenanceToolsXmlProcessor(string xmlcs, string basefolder, string lcid) : base(xmlcs, basefolder, lcid, null)
  112 + {
  113 + RegexpTesterConfig = GetXElement(nameof(XmlStructure.RegexpTester));
  114 + }
  115 + #endregion constructor
  116 + #region XmlStructure
  117 + public static class XmlStructure
  118 + {
  119 + public static class RegexpTester { }
  120 + }
  121 + #endregion XmlStructure
  122 + }
  123 + #endregion MaintenanceToolsXmlProcessor class
  124 +}
Vrh.Log4Pro.MaintenanceConsole/WebApplicationManager.cs renamed to Vrh.Log4Pro.MaintenanceConsole/Manager - WebApplicationManager.cs
Vrh.Log4Pro.MaintenanceConsole/WindowsServiceManager.cs renamed to Vrh.Log4Pro.MaintenanceConsole/Manager - WindowsServiceManager.cs
Vrh.Log4Pro.MaintenanceConsole/Program.cs
@@ -28,6 +28,9 @@ namespace Vrh.Log4Pro.MaintenanceConsole @@ -28,6 +28,9 @@ namespace Vrh.Log4Pro.MaintenanceConsole
28 var mm = new Menu("Log4ProIS Maintenance Console") 28 var mm = new Menu("Log4ProIS Maintenance Console")
29 .AddMenuItem(new Menu.Item("WAM", "Web Application Manager", WebApplicationManager.Execute)) 29 .AddMenuItem(new Menu.Item("WAM", "Web Application Manager", WebApplicationManager.Execute))
30 .AddMenuItem(new Menu.Item("WSM", "Windows Service Manager", WindowsServiceManager.Execute)) 30 .AddMenuItem(new Menu.Item("WSM", "Windows Service Manager", WindowsServiceManager.Execute))
  31 + .AddMenuItem(new Menu.Item("FCL", "File Cleaner Manager", FileCleanerManager.Execute))
  32 + .AddMenuItem(new Menu.ItemSeparator('-'))
  33 + .AddMenuItem(new Menu.Item("TOL", "Maintenance tools", MaintenanceToolManager.Execute))
31 .SetSelectionMode(Menu.SelectionMode.Single); 34 .SetSelectionMode(Menu.SelectionMode.Single);
32 35
33 mm.ExecuteMenu(); 36 mm.ExecuteMenu();
Vrh.Log4Pro.MaintenanceConsole/Vrh.Log4Pro.MaintenanceConsole.csproj
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3 + <Import Project="..\packages\EntityFramework.6.4.0\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.0\build\EntityFramework.props')" />
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> 4 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4 <PropertyGroup> 5 <PropertyGroup>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> 6 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +13,8 @@ @@ -12,6 +13,8 @@
12 <FileAlignment>512</FileAlignment> 13 <FileAlignment>512</FileAlignment>
13 <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> 14 <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
14 <Deterministic>true</Deterministic> 15 <Deterministic>true</Deterministic>
  16 + <NuGetPackageImportStamp>
  17 + </NuGetPackageImportStamp>
15 </PropertyGroup> 18 </PropertyGroup>
16 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> 19 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17 <PlatformTarget>AnyCPU</PlatformTarget> 20 <PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,6 +36,12 @@ @@ -33,6 +36,12 @@
33 <WarningLevel>4</WarningLevel> 36 <WarningLevel>4</WarningLevel>
34 </PropertyGroup> 37 </PropertyGroup>
35 <ItemGroup> 38 <ItemGroup>
  39 + <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
  40 + <HintPath>..\packages\EntityFramework.6.4.0\lib\net45\EntityFramework.dll</HintPath>
  41 + </Reference>
  42 + <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
  43 + <HintPath>..\packages\EntityFramework.6.4.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
  44 + </Reference>
36 <Reference Include="Microsoft.Web.Administration, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> 45 <Reference Include="Microsoft.Web.Administration, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
37 <HintPath>..\packages\Microsoft.Web.Administration.11.1.0\lib\netstandard1.5\Microsoft.Web.Administration.dll</HintPath> 46 <HintPath>..\packages\Microsoft.Web.Administration.11.1.0\lib\netstandard1.5\Microsoft.Web.Administration.dll</HintPath>
38 </Reference> 47 </Reference>
@@ -47,6 +56,7 @@ @@ -47,6 +56,7 @@
47 <HintPath>..\packages\System.AppContext.4.1.0\lib\net46\System.AppContext.dll</HintPath> 56 <HintPath>..\packages\System.AppContext.4.1.0\lib\net46\System.AppContext.dll</HintPath>
48 </Reference> 57 </Reference>
49 <Reference Include="System.ComponentModel.Composition" /> 58 <Reference Include="System.ComponentModel.Composition" />
  59 + <Reference Include="System.ComponentModel.DataAnnotations" />
50 <Reference Include="System.Configuration.Install" /> 60 <Reference Include="System.Configuration.Install" />
51 <Reference Include="System.Console, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> 61 <Reference Include="System.Console, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
52 <HintPath>..\packages\System.Console.4.0.0\lib\net46\System.Console.dll</HintPath> 62 <HintPath>..\packages\System.Console.4.0.0\lib\net46\System.Console.dll</HintPath>
@@ -135,6 +145,9 @@ @@ -135,6 +145,9 @@
135 <Reference Include="Microsoft.CSharp" /> 145 <Reference Include="Microsoft.CSharp" />
136 <Reference Include="System.Data" /> 146 <Reference Include="System.Data" />
137 <Reference Include="System.Xml" /> 147 <Reference Include="System.Xml" />
  148 + <Reference Include="VRH.Common, Version=2.19.0.0, Culture=neutral, processorArchitecture=MSIL">
  149 + <HintPath>..\packages\VRH.Common.2.19.0\lib\net45\VRH.Common.dll</HintPath>
  150 + </Reference>
138 <Reference Include="Vrh.XmlProcessing, Version=1.23.0.0, Culture=neutral, processorArchitecture=MSIL"> 151 <Reference Include="Vrh.XmlProcessing, Version=1.23.0.0, Culture=neutral, processorArchitecture=MSIL">
139 <HintPath>..\packages\Vrh.XmlProcessing.1.23.0\lib\net45\Vrh.XmlProcessing.dll</HintPath> 152 <HintPath>..\packages\Vrh.XmlProcessing.1.23.0\lib\net45\Vrh.XmlProcessing.dll</HintPath>
140 </Reference> 153 </Reference>
@@ -143,8 +156,10 @@ @@ -143,8 +156,10 @@
143 <Compile Include="ConsoleFunction - CommandLineParser.cs" /> 156 <Compile Include="ConsoleFunction - CommandLineParser.cs" />
144 <Compile Include="ConsoleFunction - ColorConsole.cs" /> 157 <Compile Include="ConsoleFunction - ColorConsole.cs" />
145 <Compile Include="ConsoleFunction - Menu.cs" /> 158 <Compile Include="ConsoleFunction - Menu.cs" />
146 - <Compile Include="WindowsServiceManager.cs" />  
147 - <Compile Include="WebApplicationManager.cs" /> 159 + <Compile Include="Manager - WindowsServiceManager.cs" />
  160 + <Compile Include="Manager - FileCleanerManager.cs" />
  161 + <Compile Include="Manager - MaintenanceToolManager.cs" />
  162 + <Compile Include="Manager - WebApplicationManager.cs" />
148 <Compile Include="Program.cs" /> 163 <Compile Include="Program.cs" />
149 <Compile Include="Properties\AssemblyInfo.cs" /> 164 <Compile Include="Properties\AssemblyInfo.cs" />
150 </ItemGroup> 165 </ItemGroup>
@@ -153,6 +168,7 @@ @@ -153,6 +168,7 @@
153 <CopyToOutputDirectory>Always</CopyToOutputDirectory> 168 <CopyToOutputDirectory>Always</CopyToOutputDirectory>
154 </None> 169 </None>
155 <None Include="packages.config" /> 170 <None Include="packages.config" />
  171 + <None Include="Vrh.NugetModuls.Documentations\VRH.Common\ReadMe.md" />
156 <None Include="Vrh.NugetModuls.Documentations\Vrh.XmlProcessing\ReadMe.md" /> 172 <None Include="Vrh.NugetModuls.Documentations\Vrh.XmlProcessing\ReadMe.md" />
157 </ItemGroup> 173 </ItemGroup>
158 <ItemGroup> 174 <ItemGroup>
@@ -164,4 +180,12 @@ @@ -164,4 +180,12 @@
164 </Content> 180 </Content>
165 </ItemGroup> 181 </ItemGroup>
166 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 182 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  183 + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
  184 + <PropertyGroup>
  185 + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
  186 + </PropertyGroup>
  187 + <Error Condition="!Exists('..\packages\EntityFramework.6.4.0\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.0\build\EntityFramework.props'))" />
  188 + <Error Condition="!Exists('..\packages\EntityFramework.6.4.0\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.0\build\EntityFramework.targets'))" />
  189 + </Target>
  190 + <Import Project="..\packages\EntityFramework.6.4.0\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.0\build\EntityFramework.targets')" />
167 </Project> 191 </Project>
168 \ No newline at end of file 192 \ No newline at end of file
Vrh.Log4Pro.MaintenanceConsole/Vrh.NugetModuls.Documentations/VRH.Common/ReadMe.md 0 → 100644
@@ -0,0 +1,297 @@ @@ -0,0 +1,297 @@
  1 +# Vrh.Common
  2 +A modul a Vonalkód Rendszerház fejlesztési környezetében szabványosított és
  3 +hasznosan alkalmazható eszközeinek gyűjtőhelye.
  4 +
  5 +> Igényelt minimális framework verzió: **4.5**
  6 +
  7 +> Teljes funkcionalitás és hatékonyság kihasználásához szükséges legalacsonyabb framework verzió: **4.5**
  8 +
  9 +# Főbb összetevők
  10 +### Interfészek
  11 +* **[IManage](##IManage)**
  12 +
  13 +### Standard osztályok
  14 +* **[CheckListJSON](##CheckListJSON)**
  15 +* **[ReturnInfoJSON](##ReturnInfoJSON)**
  16 +* **[SelectListJSON](##SelectListJSON)**
  17 +
  18 +## IManage
  19 +Generikus interfész, melyben azt a típust kell megadni, amely menedzselését végzi.
  20 +```javascript
  21 +/// <summary>
  22 +/// Meghatározza és előírja egy karbantartást és hozzáférést
  23 +/// biztosító osztály elvárt tulajdonságait és módszereit.
  24 +/// </summary>
  25 +public interface IManage<T>
  26 +{
  27 + /// <summary>
  28 + /// A kezelt típust össze egyedét szolgáltató tulajdonság.
  29 + /// </summary>
  30 + List<T> All { get; }
  31 +
  32 + /// <summary>
  33 + /// A kezelt típus egy elemét adja vissza az egyedi azonosító segítségével.
  34 + /// </summary>
  35 + /// <param name="id">Az elem egyedi azonosítója.</param>
  36 + /// <returns></returns>
  37 + T Get(int id);
  38 + /// <summary>
  39 + /// A kezelt típus egy elemét adja vissza a megadott név segítségével.
  40 + /// </summary>
  41 + /// <param name="name">Az elem egyedi neve.</param>
  42 + /// <returns></returns>
  43 + T Get(string name);
  44 +
  45 + /// <summary>
  46 + /// Létrehozza a kezelt típus egy elemét.
  47 + /// </summary>
  48 + /// <param name="item">A kezelt típus egy eleme, amit hozzá kell adni.</param>
  49 + void Create(T item);
  50 +
  51 + /// <summary>
  52 + /// A kezelt típus egy elemét törli az egyedi azonosító alapján.
  53 + /// </summary>
  54 + /// <param name="id">A törlendő elem egyedi azonosítója.</param>
  55 + void Delete(int id);
  56 + /// <summary>
  57 + /// A kezelt típus egy elemét törli az egyedi neve alapján.
  58 + /// </summary>
  59 + /// <param name="name">A törlendő elem egyedi neve.</param>
  60 + void Delete(string name);
  61 +
  62 + /// <summary>
  63 + /// A kezelt típus egy elemének módosítása.
  64 + /// Ha nem létezik az hiba.
  65 + /// </summary>
  66 + /// <param name="item">A kezelt típus egy eleme.</param>
  67 + void Update(T item);
  68 +}
  69 +```
  70 +
  71 +## CheckListJSON
  72 +```javascript
  73 +/// <summary>
  74 +/// Egy meghívott akció válaszüzenetének egy lehetséges meghatározott szerkezete.
  75 +/// Valamely lista ellenőrzéshez használható, amelyben a Checked oszlopban jelölhető az ellenőrzés eredménye.
  76 +/// </summary>
  77 +public class CheckListJSON
  78 +{
  79 + /// <summary>
  80 + /// Az ellenőrzendő illetve ellenőrzött azonosító.
  81 + /// </summary>
  82 + public string Value { get; set; }
  83 +
  84 + /// <summary>
  85 + /// Az ellenőrzéskor megtalált név vagy leíró.
  86 + /// </summary>
  87 + public string Text { get; set; }
  88 +
  89 + /// <summary>
  90 + /// Az ellenőrzés eredményét jelző logikai érték, mely a felhasználáskor
  91 + /// az üzleti logikától függ.
  92 + /// </summary>
  93 + public bool Checked { get; set; }
  94 +}
  95 +```
  96 +
  97 +## ReturnInfoJSON
  98 +```javascript
  99 +/// <summary>
  100 +/// Egy meghívott akció válaszüzenetének egy lehetséges meghatározott szerkezete.
  101 +/// A válasz érték (ReturnValue) és üzenet (ReturnMessage) formájú.
  102 +/// Sikeres végrehajtás esetén mindig 0 legyen a ReturnValue.
  103 +/// Sikertelen esetben ettől eltérő, de ha nincs egyéb ok, akkor hiba esetén legyen -1.
  104 +/// Alapértelmezett érték: 0, "Az indított akció sikeresen lezajlott!" }
  105 +/// </summary>
  106 +public class ReturnInfoJSON
  107 +{
  108 + /// <summary>
  109 + /// Egy reprezentatív értéke, mely a sikerességtől függ.
  110 + /// Ha nincs hiba az akció végrehajtásában, akkor 0 legyen az értéke.
  111 + /// Alapértelmezett értéke: 0
  112 + /// </summary>
  113 + public int ReturnValue { get; set; } = 0;
  114 +
  115 + /// <summary>
  116 + /// Az akció üzenete. Hiba esetén a hibaüzenet szövege.
  117 + /// Alapértelmezett értéke: "Az indított akció sikeresen lezajlott!"
  118 + /// </summary>
  119 + public string ReturnMessage { get; set; } = "Az indított akció sikeresen lezajlott!";
  120 +}
  121 +```
  122 +
  123 +## SelectListJSON
  124 +```javascript
  125 +/// <summary>
  126 +/// Egy meghívott akció válaszüzenetének egy lehetséges meghatározott szerkezete.
  127 +/// Egy listához használható, mely értékeit és azonosítóit fel lehet használni.
  128 +/// </summary>
  129 +/// <remarks>
  130 +/// Egyenértékű a System.Web.Mvc.SelectListItem osztállyal, de nem onnan származik.
  131 +/// Az ott szereplő leírás:
  132 +/// "Represents the selected item in an instance of the System.Web.Mvc.SelectList class."
  133 +/// </remarks>
  134 +public class SelectListJSON
  135 +{
  136 + /// <summary>
  137 + /// Jelzi, hogy ez az elem a listában letiltott.
  138 + /// </summary>
  139 + public bool Disabled { get; set; }
  140 +
  141 + /// <summary>
  142 + /// A csoport jelölése. Alapértelmezett értéke: null
  143 + /// </summary>
  144 + public SelectListGroup Group { get; set; }
  145 +
  146 + /// <summary>
  147 + /// Jelzi, hogy ez az elem a listában kiválasztott.
  148 + /// </summary>
  149 + public bool Selected { get; set; }
  150 +
  151 + /// <summary>
  152 + /// A listelem szövege, ami megjelenik.
  153 + /// </summary>
  154 + public string Text { get; set; }
  155 +
  156 + /// <summary>
  157 + /// A listelem értéke.
  158 + /// </summary>
  159 + public string Value { get; set; }
  160 +}
  161 +
  162 +#region SelectListGroup public class
  163 +/// <summary>
  164 +/// Represents the optgroup HTML element and its attributes. In a select list,
  165 +/// multiple groups with the same name are supported.
  166 +/// They are compared with reference equality.
  167 +/// </summary>
  168 +/// <remarks>
  169 +/// A System.Mvc.SelectListItem-mel való kompatibilitás miatt van itt.
  170 +/// A 'summary' szövege is onnan másolt.
  171 +/// </remarks>
  172 +public class SelectListGroup
  173 +{
  174 + /// <summary>
  175 + /// Beállítja, hogy az adott csoport engedélyezett-e.
  176 + /// </summary>
  177 + public bool Disabled { get; set; }
  178 +
  179 + /// <summary>
  180 + /// A csoport neve.
  181 + /// </summary>
  182 + public string Name { get; set; }
  183 +}
  184 +#endregion SelectListGroup public class
  185 +```
  186 +
  187 +
  188 +## Version History:
  189 +#### 2.13.2 (2020.03.27) Patches:
  190 +- NuGet csomag módosítása úgy, hogy a modul ReadMe.md "Build Action" tulajdonsága "None" legyen a telepítés után. Install.ps1 hozzáadása.
  191 +
  192 +#### 2.13.1 (2020.03.26) Patches:
  193 +- Felesleges függések törlése.
  194 +- XML comment dokumentáció pontosítása.
  195 +
  196 +#### 2.13.0 (2020.03.19) Compatible changes:
  197 +- Vrh.Web.Common.Lib egyes elemeinek átemelése ide
  198 +
  199 +#### 2.12.1 (2020.02.13) Patches:
  200 +- SelectListJSON egyenlőség vizsgálat javítása
  201 +
  202 +#### 2.12.0 (2020.02.13) Compatible changes:
  203 +- SelectListJSON struktúrába beépítésre került egy speciális egyenlőség vizsgálat, amely a Value, a Text és a Group mezők értékének egyenlősége
  204 +esetén ad igaz értéket; a Disabled és a Selected mezők értéke az egyenlőség vizsgálatban nem játszik szerepet
  205 +- CheckListJSON és ReturnInfoJSON strukturákhoz analóg módon, mely ugyanezekkel a feltételekkel dolgozik.
  206 +
  207 +#### 2.11.1-3 (2019.12.19) Compatible changes:
  208 +- CommandLine class hibák javítása.
  209 +
  210 +#### 2.11.0 (2019.12.17) Compatible changes:
  211 +- Topshelf formátumú parancssori paraméterek kezelése: -NAME:value
  212 +
  213 +#### 2.10.1 (2019.12.17) Patches:
  214 +- CommandLine osztályban egy javítás
  215 +
  216 +#### 2.10.1 (2019.12.05) Patches:
  217 +- SerializeObject metódusban a string-ek külön kezelése.
  218 +
  219 +#### 2.10.0 (2019.10.08) Compatible changes:
  220 +- ToEnum string extension hozzáadása, amelyik egy stringből megadott tipusú enumra konvertál, vagy a típus (Enum) defaultját adja
  221 +
  222 +#### 2.9.0 (2019.09.12) Compatible changes:
  223 +- EntryAsseblyFixer static class hozzáadása, ami beállítja amegfelelő EntryAssembly-t, ha az alakalmazás tér dinamikus hostolású, ahol null, vagy dynamic az EntryAssembly
  224 +- EntryAsseblyFixer egység tesztjei
  225 +
  226 +## 2.8.1 (2019.09.07):
  227 +### Patch:
  228 +- Name property típusa javítva.
  229 +
  230 +## v2.8.0 (2019.09.06):
  231 +### Compatibility API changes:
  232 +- ReturnDictJSON adatstruktúra hozzáadva.
  233 +
  234 +## 2.7.0 (2019.08.15) Compatible changes:
  235 +### Compatibility API changes:
  236 +- Az EntityFramework extension bővítése az AlreadyOrdered függvénynel, amely megmondja egy IQueryable-ről, hogy rendezett-e már (tehát a további rendezéséhez az OrderBy, vagy a ThenBy-t kell-e használni)
  237 +
  238 +## 2.6.0 (2019.08.01) Compatible changes:
  239 +### Compatibility API changes:
  240 +- Extensions bővítése az EntityFramework extension-nel, EntityFrameworkQueryHelper bővítő osztály, SmartOrder bővítő metódus (IQueryable típusra)
  241 +
  242 +## 2.5.0 (2019.07.10) Compatible changes:
  243 +### Compatibility API changes:
  244 +- ExtensionMethods bővítése az Enum extensionssel, Enumdata attribútum osztály
  245 +
  246 +## 2.3.0 (2019.05.14) Compatible changes:
  247 +- IManage interfész áthelyezése Vrh.Web.Common.Lib 1.18.1-es változatából.
  248 +- Standard osztályok (CheckListJSON, ReturnInfoJSON, SelectListJSON) áthelyezése Vrh.Web.Common.Lib 1.18.1-es változatából.
  249 +
  250 +## 2.2.0 (2018.12.17)
  251 +### Compatible changes:
  252 +- VrhConvert.SerializeObject Private metódus publikussá tétele.
  253 +
  254 +## 2.1.0 (2018.12.17)
  255 +### Compatible changes:
  256 +- Új függvények beillesztése a conversion részbe.
  257 +
  258 +## 2.0.1 (2018.12.12)
  259 +### Patches:
  260 +- ConnandLine osztály metóduasdinak kommentezése és egy apró javítás: a GetCommandLineArgument lekezeli, ha az argumentname paramétere üres string.
  261 +
  262 +## 2.0.0 (2018.11.28)
  263 +### Braking change:
  264 +- 3.5-ös .Net framwork verzi támogatásának megszüntetése új target verzió: 4.5
  265 +### Compatibility API changes:
  266 +- CommandLine static segéd osztály hozzáadása
  267 +
  268 +## 1.13.0 (2017.04.04)
  269 +### Compatibility API changes:
  270 +- String Extension method: FromHexOrThis
  271 +
  272 +## 1.12.0 (2017.03.29)
  273 +### Compatibility API changes:
  274 +- FixStack class hozzáadása
  275 +### Patches:
  276 +- UnitTest method elnevezések javítása (konvenció kidolgozása)
  277 +
  278 +## 1.11.0 (2017.03.28)
  279 +### Compatibility API changes:
  280 +- Assembly Extension methodok: Version, AssemblyAttribute
  281 +
  282 +## 1.10.0 (2017.03.16)
  283 +### Compatibility API changes:
  284 +- StringBuilder Extension methodok: AppendWithSeparator, Reverse
  285 +### Patches:
  286 +- Extension methodok helyének hozzáadása.
  287 +- Test projekt hozzáadása
  288 +
  289 +## V1.9.2 (2017.02.21)
  290 +### Patches:
  291 +- Projekt könyvrtárszerkezet rendbetétele.
  292 +- AutoBuild Vrh Nuget csomaggá alakítás (összes Nuget-tel kapcsolatos elvárás átvezetése)
  293 +- MinFramweork meghatározás
  294 +
  295 +
  296 +
  297 +
0 \ No newline at end of file 298 \ No newline at end of file
Vrh.Log4Pro.MaintenanceConsole/packages.config
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 <packages> 2 <packages>
  3 + <package id="EntityFramework" version="6.4.0" targetFramework="net462" />
3 <package id="Microsoft.NETCore.Platforms" version="1.0.1" targetFramework="net462" /> 4 <package id="Microsoft.NETCore.Platforms" version="1.0.1" targetFramework="net462" />
4 <package id="Microsoft.Web.Administration" version="11.1.0" targetFramework="net462" /> 5 <package id="Microsoft.Web.Administration" version="11.1.0" targetFramework="net462" />
5 <package id="Microsoft.Win32.Primitives" version="4.0.1" targetFramework="net462" /> 6 <package id="Microsoft.Win32.Primitives" version="4.0.1" targetFramework="net462" />
@@ -54,5 +55,6 @@ @@ -54,5 +55,6 @@
54 <package id="System.Threading.Timer" version="4.0.1" targetFramework="net462" /> 55 <package id="System.Threading.Timer" version="4.0.1" targetFramework="net462" />
55 <package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="net462" /> 56 <package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="net462" />
56 <package id="System.Xml.XDocument" version="4.0.11" targetFramework="net462" /> 57 <package id="System.Xml.XDocument" version="4.0.11" targetFramework="net462" />
  58 + <package id="VRH.Common" version="2.19.0" targetFramework="net462" />
57 <package id="Vrh.XmlProcessing" version="1.23.0" targetFramework="net462" /> 59 <package id="Vrh.XmlProcessing" version="1.23.0" targetFramework="net462" />
58 </packages> 60 </packages>
59 \ No newline at end of file 61 \ No newline at end of file