Laden...

[Review] Programm zum sicheren Starten und Loggen des Startvorgangs von Programmen

Erstellt von R3turnz vor 8 Jahren Letzter Beitrag vor 8 Jahren 4.667 Views
R
R3turnz Themenstarter:in
125 Beiträge seit 2016
vor 8 Jahren
[Review] Programm zum sicheren Starten und Loggen des Startvorgangs von Programmen

Hallo,
erstmal möchte ich den Sinn meines Programmes erläutern:
Einfach gesagt: Es startet ein Program.
Jedoch werden Fehlermeldungen in eine log-Datei geschrieben und Einstellungen werden aus einer ini-Datei geladen. Außerdem bietet es eine Unterstüzung zum verbinden von Netzlaufwerken und ermöglicht so das zentralen Speichern der log-Datein.
Zugegeben, das Einsazgebiet ist sehr klein, und aktuell ist es sehr viel Code um nichts, wenn man aber z.B. das Starten eines Programmes zur bestimmten Uhrzeit per Gui geplant werden könnte etc. wäre es effektiver, ich werde es deswegen später auch wahrscheinlich weiter entwickeln. (Gerade fehlt mir vorallem das Wissen in WPF).
An einigen Stellen bin ich mir mit den Variablen-Namen nicht schlüssig geworden, habe aber versucht es so gut wie möglich hinzubekommen.

Program.cs:


using System;
namespace Starter
{

    class Program
    {

        public static void Main()
        {
            Console.Title = "Starte...";
            string[] log = new string[2];
            ConfigLoader config = new ConfigLoader("config.ini");
            
                log[0] = config.Load() + "\n";
            if (config.LoadedStarter != null) log[1] = config.LoadedStarter.Start() + "\n";
                config.LoadedLogWriter.Write(log);
        }
    }
}

Config-Loader.cs:


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;
namespace Starter
{
    class ConfigLoader
    {
        public string ConfigPath { get; private set; }
        public ConfigLoader(string configpath)
        {
            ConfigPath = configpath;
            LoadedStarter = null;
            LoadedLogWriter = null;
        }
        public Starter LoadedStarter { get; private set; }
        public LogWriter LoadedLogWriter { get; private set; }
        private string programpath = null;
        string args = null;
        string[] splittedArgs = null;
        string logpath = null;
        string nas = null;
        string nasuser = null;
        string naspasswd = null;
        string naspath = null;
        public string Load()
        {

            if (File.Exists(ConfigPath))
            {
                IniFile config = new IniFile("config.ini");
                if (config.KeyExists("Programpfad", "Starter")) programpath = config.Read("Programpfad", "Starter").Trim();
                if (config.KeyExists("Aufzeichnungspfad", "Starter")) logpath = config.Read("Aufzeichnungspfad", "Starter").Trim();
                if (config.KeyExists("Argumente", "Starter")) args = config.Read("Argumente","Starter");
                if (config.KeyExists("Netzwerkpfad", "NAS") && config.KeyExists("Aufzeichnungspfad","NAS"))
                {
                    nas = config.Read("Netzwerkpfad", "NAS").Trim();
                    naspath = config.Read("Aufzeichnungspfad","NAS").Trim();
                    if (config.KeyExists("Benutzer") && config.KeyExists("Nas-Passwort") && logpath == null)
                    {
                        nasuser = config.Read("Benutzer", "NAS").Trim();
                        naspasswd = config.Read("Passwort", "NAS").Trim();
                    }
                }
            }
            return Create();
        }
        private string Create()
        {
            StringBuilder parambuilder = new StringBuilder("Folgende Paramter wurden geladen:\n");
            if (!string.IsNullOrEmpty(logpath))
            {
                LoadedLogWriter = new LogWriter(logpath);
                parambuilder.AppendFormat("Der Pfad für die Aufzeichnung wurde auf:{0} gesetzt.",logpath);
            }
             else
            {
                LoadedLogWriter = new LogWriter();
                parambuilder.AppendFormat("Es konnte kein Pfad für die Aufzeichnung gefunden werden! Standartwert:{0}.",LoadedLogWriter.DefaultDestination);
            }
            parambuilder.AppendLine();
            if(!string.IsNullOrEmpty(programpath) && splittedArgs != null && splittedArgs.Length > 0)
            {
                SplitArgs(args,new char[] { ',' });
                parambuilder.AppendFormat("Der Programpfad wurde auf:{0} gesetzt. Außerdem wurden folgender Argumente erkannt:{1}.",LoadedStarter.ExecutionPath,args);
            }
            else if(!string.IsNullOrEmpty(programpath))
            {
                LoadedStarter = new Starter(programpath);
                parambuilder.AppendFormat("Der Programpfad wurde auf:{0} gesetzt.",LoadedStarter.ExecutionPath);
            }
            else
            {
                parambuilder.AppendFormat("Es konnte kein Pfad zum Ausführen gefunden werden!");
            }
            if(!string.IsNullOrEmpty(nas) && !string.IsNullOrEmpty(naspath))
            {
                parambuilder.AppendLine();     
                parambuilder.Append("NAS-Konfiguration:");
                if (!string.IsNullOrEmpty(nasuser) && !string.IsNullOrEmpty(naspasswd))
                {
                   parambuilder.Append(LoadedLogWriter.Connect(nas,naspath,nasuser,naspasswd));
                }
                else
                {
                    parambuilder.Append(LoadedLogWriter.Connect(nas,naspath));
                }
            }
           
            return parambuilder.ToString();
        }
      
        private void SplitArgs(string args,char[] pattern)
        {
            splittedArgs = args.Trim().Split(pattern);
        }
    }

}


LogWriter.cs:



using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Management.Automation;
using System.Collections.ObjectModel;
using System.Windows;
using System.Security;
using System.Text;

namespace Starter
{
    class LogWriter
    {
        public string Destination { get; set; }
        public string DefaultDestination
        {
            get
            {
                string appDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Starter");
                return Path.Combine(appDir, "log.txt");
            }
        }
        public LogWriter(string destination = null)
        {
            Destination = destination ?? DefaultDestination;
        }
        
        public void Write(string[] value)
        {
            string appDir = Path.GetDirectoryName(Destination);
            if (!Directory.Exists(appDir)) Directory.CreateDirectory(appDir);
            try
            {
                using (var fs = new FileStream(Destination, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    fs.Seek(0,SeekOrigin.End);
                    using (var sw = new StreamWriter(fs,Encoding.UTF8))
                    {
                        sw.WriteLine("Starter v0.1 "+Environment.MachineName + " (" + DateTime.Now.ToString() + ")");
                        foreach(var towrite in value)
                        {
                            if(towrite != null)
                            sw.WriteLine(towrite);
                        }
          
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(string.Format("Es ist ein Fehler wärend des Log-Schreibens nach:{0} aufgetreten:{1}",Destination,ex.Message),"CCleaner-Starter-Fehler",MessageBoxButton.OK,MessageBoxImage.Error);
            }
            
        }
        public string Connect(string root,string path, string user = null, string password = null)
        {
            var name = getNextDriveName();
            if (name == ' ') return "Kein weiteren Laufwerk-Bezeichner gefunden!";
            try
            { 
                using (var powershell = PowerShell.Create())
                {
                    powershell.AddCommand("New-PSDrive");
                    powershell.AddParameter("Name", name);
                    powershell.AddParameter("PSProvider", "FileSystem");
                    powershell.AddParameter("Root", root);
                    if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password))
                    {
                        var secure = new SecureString();
                        foreach (char c in password)
                        {
                            secure.AppendChar(c);

                        }
                        PSCredential credential = new PSCredential(user, secure);
                        powershell.AddParameter("Credential",credential);
                    }
                    Collection<PSObject> powershellobjects =  powershell.Invoke();
                    if(powershell.HadErrors)
                    {
                        StringBuilder errorbuilder = new StringBuilder("Während des Verbindens mit dem Netzlaufwerk ist ein/mehrere Fehler aufgetreten:");
                        for(int i = 0; i < powershell.Streams.Error.Count; i++)
                        {
                            if (i < powershell.Streams.Error.Count - 1)
                            {
                                errorbuilder.Append(powershell.Streams.Error[i].ToString() + ",");
                            }
                         else
                            {
                                errorbuilder.Append(powershell.Streams.Error[i].ToString());
                            }
                        }
                        return errorbuilder.ToString();
                    }
                    else if(powershellobjects.Any())
                    {
                        PSDriveInfo psinfo = (PSDriveInfo)powershellobjects[0].BaseObject;
                        Destination = Path.Combine(psinfo.Root,path);
                       return string.Format("Netzlaufwerk erfolgreich geladen, log wird nun nach: {0} geschrieben!", Destination);
                    }
                    else
                    {
                      return "Ein unbekannter Fehler ist aufgetreten!";
                    }
                   
                }
            }
            catch(Exception ex)
            {
                return "Während des Verbindens mit dem Netzlaufwerk ist ein Fehler aufgetreten:"+ex.Message;
            }

            
        }
           
            
            
        private char getNextDriveName()
        {
            List<char> alphabet = new List<char>(26);
            for (char c = 'A'; c < 'Z'; c++)
            {
                alphabet.Add(c);
            }
            DriveInfo[] drives = DriveInfo.GetDrives();
            foreach(var drive in drives)
            {
                alphabet.Remove(char.Parse(drive.Name.Substring(0,1)) );
            }

            return alphabet.Any() ? alphabet[0] : ' ';
                
        }
    }
}


Starter.cs:


using System.IO;
using System.Diagnostics;
using System;
using System.Text;

namespace Starter
{
    class Starter
    {
        public string ExecutionPath { get; private set; }
        public string Arguments { get; set; }
        public string Start()
        {
            Process ccleaner = new Process();
            ccleaner.StartInfo.FileName = ExecutionPath;

            if(!string.IsNullOrEmpty(Arguments))  ccleaner.StartInfo.Arguments = Arguments;
                ccleaner.StartInfo.CreateNoWindow = true;
            
            try
            {
                ccleaner.Start();
            }
            catch (Exception ex)
            {
                return string.Format("Es ist ein Fehler während des Startens von: {0} aufgetreten:{1}.", ExecutionPath, ex.Message);
            }
            return string.Format("Erfolgreich:{0} gestartet!",ExecutionPath);
        }
        public Starter(string executionpath,string args = null)
        {
            ExecutionPath = executionpath;
            Arguments = args;
        }
    }

}


Die InI-File Klasse kommt von: http://stackoverflow.com/questions/217902/reading-writing-an-ini-file

LG

16.806 Beiträge seit 2008
vor 8 Jahren

Von Ini Dateien solltest - wenn irgendwie möglich - Du allgemein die Finger weglassen, denn das ist wirklich aus der Mottenkiste.
Verwende XML oder Json. Lassen sich viel einfacher und sicherer lesen.

Ansonsten bin ich ein Freund von Code Dokumentation.
Muss nicht wirklich jede Zeile sein, aber der Leser sollte wissen, was an der Stelle passiert (und manchmal auch wieso).

P
441 Beiträge seit 2014
vor 8 Jahren

Ich habe jetzt nicht alles durchgelesen, aber du übergibst der Klase _ConfigLoader _im Konstruktor die zu ladende Datei, lädst dann aber in ConfigLoader.Load() die "config.ini" egal, was vorher übergeben wurde.

3.170 Beiträge seit 2006
vor 8 Jahren

Hallo,

was mir daran gar nicht gefällt, ist, dass überall in den Methoden die Status/Logmedungen als Strings zurückgegeben werden.

Das mag in diesem speziellen Fall ja OK sein und das tun was Du willst.
Als Konzept finde ich es aber grauselig, und sollte man sich nicht angewöhnen/abschauen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

R
R3turnz Themenstarter:in
125 Beiträge seit 2016
vor 8 Jahren

Hallo,
@Abt InI-Datein haben für mich den Vorteil, jeder könnte sie selber editieren (Brauche nicht wie z.B. bei XML ein Tool dafür zu entwerfen), und sie haben mir nihctmal 10 Minuten Einarbeitung gekostet 🙂 .
Aber keine Angst, mein aktueller "Schlachtplan" sieht so aus: LinQ, XML, WPF 8o . Bis ich da durchbin wird es zwar noch dauern, aber werde es schon packen.
@Papst Danke, ist behoben 😉
@MarsStein Okay, nur bringt es mir leider wenig ohne Verbesserungsvorschlag. 🤔

Nochmal danke an alle, fürs durchsehen.

LG

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo R3turnz,

@Abt InI-Datein haben für mich den Vorteil, jeder könnte sie selber editieren (Brauche nicht wie z.B. bei XML ein Tool dafür zu entwerfen), und sie haben mir nihctmal 10 Minuten Einarbeitung gekostet 😃

XML und JSON lassen sich ebenfalls in jedem Texteditor editieren.

Gruss

Coffeebean

16.806 Beiträge seit 2008
vor 8 Jahren

Ini-Dateien haben über XML eigentlich genau: keinen Vorteil.
Auch XML Dateien basieren auf einfachem Text - da braucht man kein Tool dazu.

XML und Json unterstützen im Gegensatz zu Ini aber weit mehr als nur Key-Value.
Und sind dabei auch noch viel sicherer und einfacher zu lesen.

R
R3turnz Themenstarter:in
125 Beiträge seit 2016
vor 8 Jahren

Hallo,
ich wollte ini-File's nicht gut reden. Mir sind die stärken von XMl/Json durchaus bewusst 😉
Ich weiß auch das man sie normal in einem Editor öffnen kann, ein XML File, ist jedoch meiner Meinung nach ein wenig komplexer als ein ini-File.
Wenn ich jedoch darüber nachdenke wäre es aber auch gar nicht so schlimm.
Ich muss mier jedoch XML jedoch nochmal anschauen, blicke vorallem in XSD noch gar nicht durch.

LG

C
1.214 Beiträge seit 2006
vor 8 Jahren

Ich will diese Diskussion eigentlich nicht vertiefen. Ich bevorzuge auch XML oder Json, wo das möglich ist. Aber ich auch erwähnen, dass die meisten unserer Kunden und Consultants im Maschinenbaubereich ini Dateien absolut den Vorrang geben. Kaum führen wir mal irgendwo eine Config im XML Format ein, mit der auch "Benutzer" direkt in Berührung kommen, dann kommen garantiert zig Anfragen rein, bitte auf ini umstellen.

16.806 Beiträge seit 2008
vor 8 Jahren

Ich komm ursprüngliche aus der Maschinenbaubranche und neue Systeme verwenden durchaus XML - selbst als Market Leader.
Bei Legacy-Systemen ist das durchaus so, was historisch aufgrund der Abwärtskompatibilität bedingt ist. Nicht unüblich bei einem Fertigungslaser, der 20 Jahre Laufzeit hat.
Nur pauschal zu sagen die Maschinenbauer verwenden ini ist inkorrekt.

C
1.214 Beiträge seit 2006
vor 8 Jahren

Nein, ich wollte das natürlich nicht pauschalisieren. Ich habe auch nicht Maschinenbauer allgemein gemeint, und auch nicht die Software, die sie möglicherweise benutzen, sondern ganz konkret auf unsere Software bezogen. Aber da das eine Branchenlösung für Maschinenbauer ist, wollte ich das eben eingrenzen. Unsere Software ist auch schon seit über 20 Jahren auf dem Markt und natürlich dementsprechend sehr stark historisch gewachsen. Die Konfiguration ist auch teilweise sehr umfangreich und komplex, und wenn sich Kunden und Consultants da schon auskennen, wollen sie weder neue noch gemischte Konfigurationsformate.