Laden...

Forenbeiträge von hinrich Ingesamt 116 Beiträge

17.05.2016 - 20:19 Uhr

Hi,

war auch länger nicht hier, so dass ich das Thema mal als Einstieg nutzen möchte.

Um nochmal auf den Kern der Eingangsfrage zu kommen: Exceptions sind recht "teuer" in der Laufzeit. Und sie sind, wie der Name schon vermuten lässt, Ausnahmen. Natürlich sollen und müssen die an geeigneter Stelle behandelt werden. Aber für mein Verständnis sollte der geregelte Programmfluss durch if-Anweisungen erfolgen und eine Exception nur für Notfälle herhalten.

Hinrich

21.02.2012 - 23:19 Uhr

Hach, danke.

Die Angaben der Entwickler selbst sind ungefähr so vertrauensselig wie die Angaben zum Kraftstoffverbrauch von VW. Und ob ein 486er mehr als 1GB adressieren kann, habe ich angesichts der technologischen Entwicklung der letzten 10 Jahre schlicht aus meinem Hirn verdrängt.

Aber irgendwie war Dein Post so gar nicht hilfreich. Schade, aber dennoch danke für Deinen Versuch.

Hinrich

21.02.2012 - 21:59 Uhr

verwendetes Datenbanksystem: SQLite

Moin Moin!

Hat jemand von Euch mal einen Stress-Test mit SQLite laufen lassen/entwickelt? Mich würde interessieren, ab welchen Grenzen SQLite anfängt, auf dem sprichwörtlichen letzten Loch zu pfeifen. 1.000.000 Datensätze, oder 2,5 GB große Datei oder 398 Tabellen etc.

Es geht mir um ein spürbares Einknicken der Performance.

Hinrich

02.02.2012 - 20:30 Uhr

für mich ist die Angabe einer Datei (...) eine Benutzereingabe, (...)

Das sehe ich ähnlich. Die Frage, ob die Datei auch tatsächlich existiert (also der gesamte Pfad), ist für mich aber Bestandteil der Validierung. Wenn mir dann aber beim Zugriff auf diese Datei das Betriebssystem ein access denied um die Ohren schmeißt, dann ist das ein Fehler (der auch den Einsatz von throw Exception rechtfertigt).

Hinrich

02.02.2012 - 15:53 Uhr

Vielleicht hat ja noch jemand eine bessere Idee?

Die beste Idee ist, RegEx zu verwenden. Es ist erprobt, weitgehend fehlerfrei und leistungsstark. Dem Kunden kann man auch nur eine Teilmenge der Befehle in die Hilfe schreiben und das Wort RegEx vermeiden. Andererseits solltest Du dem Anwender (sprich Kunden) auch eine (kostenpflichtige) Schulung verpassen können.

Ansonsten gibt es noch die MaskedTextBox aus dem IDE-Baukasten.

Hinrich

13.02.2011 - 12:29 Uhr

Moin!

Also wenn es nur um mögliche Vertragslaufzeiten geht, würde ich mich nicht mit einer mathematischen Lösung beschäftigen, sondern die ganze Problematik über mehr oder weniger simple Listen lösen.

Dann kann ich die verschiedenen Laufzeiten und deren Kombinationen auch später ändern und beispielsweise auch nachträglich 48 Monate ermöglichen, ohne im Source wühlen zu müssen.

Hinrich

27.01.2011 - 10:21 Uhr

(1) Wie erreiche ich es, dass mein Hauptfenster zunächst gezeichnet wird und im Anschluss daran eine 2. Form geöffnet wird? Wenn ich die 2. Form im Load-Event der 1. Form öffne, so wird zunächst nur die 2. Form angezeichnet und erst danach die 1. Form gezeichnet.

Was logisch ist, da zu dem Zeitpunkt, wenn Form_Loaded geworfen wird, noch nichts angezeigt wird. Das ist erst passiert, wenn Form_Shown geworfen wurde (mit Einschränkungen).

Für den kontrollierten Aufbau zweier oder mehrerer (gleichberechtigter) Fenster solltest Du Dir mal ApplicationContext ansehen.

Hinrich

26.01.2011 - 17:12 Uhr

Es geht um eine Personalstammerfassung...da kann man schlecht einfach Felder weg lassen! Es sind so ca. 300 Eingabefelder (also 300 Textboxen + 300 Labels) angeordnet in einem TabControl...

Da möchte ich nicht arbeiten...

Habe inzwischen auch festgestellt, dass der Methodenaufruf selbst sehr lange dauert...

Passiert da vielleicht noch was anderes, wie etwa Dateizugriffe oder Datenbankabfragen etc.? Ansonsten würde ich auch den Vorschlag versuchen, Controls in den TabPages erst aufzubauen, wenn diese aktiviert werden.

Hinrich

23.12.2010 - 01:00 Uhr

Moin Moin.

Soll heißen, ich weiß wie man die Dinge der OO verwendet(abstract, virtual, Vererbung, Properties,...), aber der richtige Sinn, der dahinter steckt, ist mir oftmals nicht wirklich geläufig.

Das sind letztlich nur technische Details.

Ein Beispiel aus meinem Projekt wäre, dass ich eine abstrakte Elternklasse mit einer Methode Start() habe und jedes Kind hat auch diese Startmethode, die aber bei jedem Kind anders ist. Also was macht es für einen Unterschied, ob ich nun in der Elternklasse eine abstracte Start() schreibe und dann bei jedem Kind überschreibe, oder ob ich einfach die Methode in der Elternklasse weglasse und jedes Kind seine eigene Start() hat, weil sie ja sowieso komplett anders ist.

Denke nicht im Source, denke im Objekt. Nimm zum Beispiel ein Auto: Das hat eine Farbe (Eigenschaft, üblicherweise enum), eine Anzahl von Türen (Eigenschaft, nur lesen [nachträglich kann man keine Türen einbauen... na ja, mit der Flex geht's]), einen Motor (Eigenschaft, wobei Motor wiederum ein Objekt ist [Diesel, Benziner]) usw. Und dann kann man mit dem Auto was machen (wobei die Einzelteile am Ende machen), z.B. Auto.Start() (was dann zu Auto.Motor.Start() führt).

Diese Abstraktion kann ich mit allem machen, was als Software umgesetzt werden soll: Ein Buch hat Seiten, eine Waschmaschine hat Waschgänge, ein Herd hat Kochplatten, ein Hund hat ein Fell usw.

Ein Objekt: Es hat etwas (Farbe -> Eigenschaft), es tut etwas (Methode) und ich merke es (Event) oder es geht kaputt (Exception).

Hinrich

22.12.2010 - 22:12 Uhr

Moin Moin!

In meinem Programm wirds wohl so aussehen, dass es sehr viele Stellen gibt, an denen abgefragt wird ob der Benutzer das darf oder nicht.

Zum Beispiel Darf der User nur auf 3 von 5 Buttons klicken. Da hatte ich bisher die vorstellung, dass für jeden Button eine 1 oder 0 in der entsrpechen Spalte in der Tabelle stehen soll.
Kreige ich das mit der Bit-KOdierung auch noch hin? vorallem wenns nicht 5 sonder 100 Button würden?

Ich denke da würde eine enum Classe einfacher zu handeln sein oder täusch ich mich da?

Das Bit-Feld würde ja lediglich die Rechte einer Gruppe festlegen, so dass in den meisten Fällen wohl selbst ein Byte ausreichen würde. Es reichen ja wenige Definitionen, wenn man abstrahiert.


/* Rechte für den Zugriff, erweiterbar */
[Flags]
enum Grants
{
    // Lesen
    Read = 1,
    // Ändern
    Write = 2,
    // Erzeugen (kann auch bei Grants.Write subsumiert werden)
    Create = 4,
    // Löschen (sollte immer gesondert behandelt werden)
    Delete = 8,
    // Lesen und Schreiben
    ReadWrite = 3,
    // Administrator
    Admin = 15
}

Das sind 4 Bits, passt also.

Darüber hinaus definiert man beliebig viele Gruppen, die dann spezifische Rechte haben. Die Gruppe kann auch als enum[/TT} (starr) oder string` definiert werden. Die Gruppe (am besten eine Klasse) erhält dann Standardrechte zugewiesen.


class Group 
{
    public string Title {get; set; }
    public Grants Grant {get; set; }
}
...
    SysOp = new Group("SysOp", Grants.Admin);
    Clerk = ne  Group("Clerk", Grants.ReadWrite | Grants.Create);

Nun ordne ich nur noch jedem Benutzer die gewünschten Gruppen zu. Dasselbe mache ich mit den Steuerelementen. Dann prüfe ich vor der Anzeige bzw. Aktivierung eines Steuerelements nur noch, ob der Nutzer einer Gruppe angehört, der das Steuerelement auch angehört, und ob damit die gewünschte Aktion vorgenommen werden darf.

Das Prinzip ist recht trivial, selbst bei komplexeren Strukturen Speicher schonend, durch die Bit-Operationen hinreichend schnell (zumal dann, wenn die Gruppen nur noch über Datenbank-Ids im Speicher angesprochen werden) und gut mit LINQ einsetzbar. Man könnte es durch Prioritäten (Rangfolge der Gruppen, first match) erweitern, was zwar bei der Zuweisung weniger Hirnschmalz verlangen, jedoch den administrativen Aufwand erhöhen würde.

Hinrich

22.12.2010 - 00:12 Uhr

Moin.

die bereits vorgeschlagene Lösung mit enum und dem Attribute Flags ist wahrscheinlich die beste Lösung, Deine von POSIX-Dateisystemen abgeleitete Rechtestruktur umzusetzen. Allerdings hat das Problem weniger etwas mit Datentechnologien zu tun, weshalb es vielleicht vom geneigten Moderator verschoben werden könnte.

Wenn Du enum mit Flags verwendest, muss Deine Methode nur noch ein int zurückgeben. Noch einfacher wäre es, wenn Deine Klassen des Business-Layers eine Schnittstelle bereitstellen würden, etwa wie folgt


[Flags]
public enum Grants
{
    // ...
}

interface IUserAccess 
{
    bool UserGranted(Grants userRights);
}

class FooBar : BaseClass, IUserAccess
{
    private const Grants RIGHTS = UserRW | GroupR | OtherR;

    // ...

    #region IUserAccess-Member

    public bool UserGranted(Grants userRights)
    {
        // Vergleiche die Bits 
        return (bool) (RIGHTS & userRights);
    }

    #endregion
}

So, oder so ähnlich könnte eine Abfrage geklärt werden.

enum gibt es zwar in PHP nicht, aber die Systematik ist ja dennoch bekannt:


define('UREAD', 0x01);
define('UWRITE', 0x02);
define('UEXECUTE', 0x04);
// ...
function canWrite(userRights) 
{
    return userRights & UWRITE;
}

Von PHP kommend solltest Du das Zusammensetzen der Queries überdenken. In C# ist es sinnvoller Deine Methode in etwa wie folgt zu kodieren:


public int[] getUserRights()
{
    int[] result = new int[10];
    // Instanzweite Verbindungen können problematisch sein!
    // C#-Connectoren können Pooling, so dass jeweils eine
    // Conection neu erstellt werden kann.
    if (conn.State == ConnectionState.Closed)
        DBConnection();

    cmdisPWkorrekt.CommandText 
        = "SELECT * FROM tbl_Rechte WHERE User_ID = @id LIMIT 1";
    cmdisPWkorrekt.Parameters.AddWithValue("id", UserId);
    cmdisPWkorrekt.Connection = conn;
    using(var Reader = cmdisPWkorrekt.ExecuteReader())
    {
        int i = 0;
        while (Reader.Read())
            for (int i = 1; i < Reader.FieldCount; i++)
                result[i-1] = Reader.GetInt16(i);
    }
    return result;
}

Die TableRow direkt zu benutzen, halte ich (andere mögen das anders sehen) für nicht sinnvoll. In diesem Fall würde ich diese durch eine relativ dumme Klasse kapseln.

Anyway, ich würde die Rechte als Bit-Kodierung aus der Datenbank lesen, so dass ich am Ende nur einen Int-Wert zurückbekäme, etwa so:


public Grants getUserRights()
{
    int rights = 0;
    using (MySqlConnection conn = new MySqlConnection(meinConnectionString))
    {
        MySqlCommand cmd 
            = new MySqlCommand(
                "SELECT `Right` FROM `tbl_Rechte` WHERE `User_Id`=@id",
                conn);
        cmd.Paramters.AddWithValue("id", UserId);
        conn.Open()
        try { rights = Convert.ToInt32(cmd.ExecuteScalar()); }
        catch { }
    }
    return (Grants) rights;
}

Hinrich

21.12.2010 - 09:56 Uhr

Moin!

Irgendwie stehe ich auf den Schlauch, oder sehe den Wald vor lauter Bäumen nicht.

Ich möchte gerne den Inhalt der Eigenschaft ToolTip eines Menüeintrags in der Statuszeile anzeigen lassen, wenn der Anwender sich im Menü befindet. Leider aber fehlen dem MenuStrip so sinnvolle Eigenschaften wie SelectedItem oder SelectedIndex.

Any hints?

Hinrich

21.12.2010 - 09:51 Uhr

Welche IPAdresse muss ich eintragen, die Zugriff haben. Meine "Public"-IPAdresse ist es schonmal nicht, da immer ein Fehler zurück kommt. "%" will ich nicht eintragen. % würde es jedem erlauben, sich zu verbinden, dass macht wenig Sinn. Normal gibst Du die konkrete IP oder Domainnamen an, z.B. localhost. Wenn Du über ein Dial-Up oder DSL-Anschluss mit dem Server verbunden bist, ändert sich Deine IP ständig. Dann würde sich nur noch DynDNS anbieten.

Neben der Freigabe für die IP (per default ist es eigentlich nur localhost bzw. 127.0.0.1 muss auch der Port (default: 3306) erreichbar sein. Viele Server im Netz weisen Zugriffe auf diesen Port bereits an der Firewall ab.

Hinrich

08.12.2010 - 15:36 Uhr

Moin Moin!

Ich setze die Bibliothek DockPanel Suite von WeifenLuo ein, um meine Arbeitsfläche zu verwalten. Dabei sind einige Fenster einmalig, andere hingegen können mehrfach (dann nütlich mit verschiedenen Daten) vorkommen.

Bei Programmende werden die Einstellungen mittels DockPanel.SaveAsXml() gespeichert. Entsprechend werden sie beim Start mit DockPanel.LoadFromXml() wieder geladen. Für die Deserialisierung der Fenster nutze ich die folgende Funktion:

        private IDockContent deserializePanels(string persistName)
        {
            IDockContent panel;
            Type type = Type.GetType(persistName);
            switch (type.Name)
            {
                case "CemeteryPanel":
                    panel = new CemeteryPanel();
                    break;
                /* ... */
                default:
                    panel = null;
                    break;
            }

            return panel;
        }

Einmalige Fenster, wie hier etwa CemeteryPanel stellen dabei nicht das Problem dar, sondern es sind diejenigen, die mehrfach vorkommen können. Denen muss auch noch mitgeteilt werden, welchen Inhalt sie anzeigen sollen, beispielsweise einen Dateinamen.

Meine Überlegung ist nun, den persistName, der ja von DockContent.GetPersistString() zur Verfügung gestellt wird, dahingehend zu erweitern, dass dieser einen Verweis auf die Daten enthält.

Hat einer von Euch diese Problematik bereits gelöst? Und wenn ja, wohlmöglich auf einen anderen Weg?

Hinrich

04.12.2010 - 20:47 Uhr

Kann mir einer diese Fehlermeldung erklären? Wie ich diese lösen kann? Es ist eine normale Datenbank Connection, die ich bei jeder Application nutze.

Die Fehlermeldung ist doch eigentlich klar und selbsterklärend. Am besten steuerst Du den Zeichensatz über CharacterSet im MySqlConnectionStringBuilder. Ich speichere beispielsweise alles in UTF-8 (utf8_general_ci in der Datenbank) und lege dies in der Verbindung fest.

Das komische ist, das der Server nichtmal windows-1251 als Kodierung nutzt.

Eben.

Hinrich

28.11.2010 - 21:39 Uhr

Die Methode Dateien() wird über einen Timer alle 5s aufgerufen

Vielleicht dauert das Einsammeln der Information länger als 5 Sekunden, so dass zu viel Speicher auf dem Stack verbraucht wird?

Hinrich

27.11.2010 - 16:54 Uhr

Moin herbivore & gfoidl!

Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird

(...) Wenn man für die eigenen Projekte eine Bibliothek einsetzt, also z.B. das .NET-Framework, dann kann man mit Fug und Recht erwarten, dass die eigenen Programm auch mit einer neuen Version des Frameworks laufen. (...)

Dann habe ich mich vielleicht etwas missverständlich ausgedrückt: Kompatibilität ist in Grenzen richtig und wichtig. Aber eben in Grenzen. Wenn ich ein Framework einsetze, ob nun .NET oder sonst was, so erwarte ich, dass das, was ich unter 3.0 in der API zur Verfügung hatte, auch in der 3.x da ist. Vielleicht könnte ich auch noch erwarten, dass es mit identischem Verhalten in einer Version 4.x vorhanden ist. Aber in einer 5.x würde ich es nicht mehr unbedingt erwarten.

Auch Microsoft geht so vor, denn ich glaube nicht (ohne es probiert zu haben), dass Word 6.0 unter Windows 7 laufen würde (macht auch nicht wirklich Sinn). Auch glaube ich nicht, dass in der API von Windows noch alle Funktionen aus Windows 1.0 oder 3.11 in unveränderter Form verfügbar sind.

Soweit ich das mal gelernt habe, implementieren Bibliotheken Schnittstellen in einer Version, meinetwegen 1.0, erweitern die Schnittstelle über 1.1 bis 1.8, stellen dieses oder jenes ab 1.9 als deprecated dar, halten diesen Status über den 2.xer-Zyklus und entfernen diese dann im 3.x-Zyklus. Solche Versionierung ist sinnvoll und die Entfernung von Schnittstellen stellt imho mitnichten einen Vertragsbruch dar.

Hinrich

26.11.2010 - 16:18 Uhr

Moin!

(...) Probleme entstehen erst da, wo Unter- und Oberklasse nicht in einer Hand liegen. Und da ist es dann doch wesentlich sicher und hält für den Entwickler der Bibliothek (also der Oberklassen) den Entwicklungspfad offen, wenn man die Methoden - ja, leider entgegen der reine Lehre der OO - standardmäßig non-virtual macht.

Imho gelangen wir da mehr in eine philosophische Debatte. Ich denke, wenn ich eine Unterklasse auf Basis einer Oberklasse entwickle, dann spielt die Version der Oberklasse eine entscheidende Rolle. Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird (wobei veraltete Funktionen ja niemals binär abgeschaltet werden).

Und dem Entwickler der Oberklasse kann und muss es eigentlich egal sein, was wer auch immer wo auch immer was für eine Unterklasse auch immer entwickelt.

Hinrich

26.11.2010 - 09:52 Uhr

Moin!

(...) Im .net Framework geschieht das auch so. Einige Methoden die bisher nicht virtual waren wurden in einer neuen .net-Version als virtual markiert (Bsp. hab ich jezt keins parat für eine solche Methode, aber das lässt sich ja herausfinden

Dann muss ich aber auch warten, bis das Framework geändert wurde, was aus verschiedenen Gründen (Lebenszyklen, Hersteller hat die Entwicklung eingestellt etc.) nicht unbedingt wünschenswert ist.

Ich bin auch der Meinung, alles virtual zu deklarieren. Wenn es dann wirklich mal nicht sein soll, kann ich die Klasse ja versiegeln.

Hinrich

26.11.2010 - 09:42 Uhr

Moin!

Bezieht sich zwar auf Fortran, könnte aber helfen (ich meine, in der Schule auch mal so etwas gehört zu haben):

Unterprogramme können in Fortran Funktionen oder Sub-routinen sein. Funktionen werden im aufrufenden Programm in Ausdrücken benutzt. Subroutinen werden mit call aufgerufen. Für beide Arten gab es im Rahmen dieses Kurses Beispiele (vordefinierte Funktionen und Subroutinen {mvbits}). Die vom aufrufenden Programm übergebenen Werte nennt man Aktualparameter. Aktualparameter, Funktionen und Subroutinen

Ansonsten: Frage einen Kollegen, der bei der Veranstaltung gewesen ist. 😃

Hinrich

12.11.2010 - 23:36 Uhr

Hi,

grundsätzlich würde ich im Regelfall Dateien immer in der Datenbank speichern, egal, welches DBMS zum Einsatz kommt. Vorausgesetzt natürlich, die Datei ist integraler Bestandteil des Datensatzes (also ein Foto zu einer Adresse oder ein Pdf zu einer Fakturierung). Letztlich ist es Aufgabe des DBMS die zu verwaltenden Daten effizient zu speichern. Ist das DBMS damit überfordert, sollte es ausgetauscht werden, denn Workarounds (und als solchen müsste man Verweise auf eine Datei im Verzeichnissystem verstehen) sind fehlerträchtig und schaffen Inkonsistenzen (Stichwort ACID).

Ist jedoch die Datei kein integraler Bestandteil eines Datensatzes, so kann man auch einen Verweis setzen. Mit URL's tun wir das schließlich auch, ohne zu wissen, ob die URL in Zukunft überhaupt noch erreichbar sein wird. Umgekehrt: Ist der Inhalt der URL von essentieller Bedeutung (etwa eine bestimmte Version eines Wikifehlia-Artikels als Quellenangabe), so würde man (zumindest ich) die entsprechende Version der URL komplett dem Datensatz hinzufügen, so dass dieser auch bei einer Nichterreichbarkeit des entsprechenden Servers verfügbar wäre.

Die Betrachtung ist jetzt zwar weniger technisch, aber ich habe es so gelernt: Schaffe ein Anforderungsprofil und wähle dann die passenden Werkzeuge.

Hinrich

12.11.2010 - 17:53 Uhr

Hi,

seit dem Windows XP-Patch vom letzten Dienstag (9.11.) stürzt die VS2008 regelmäßig ab, entweder beim Build-Vorgang, oder beim Settings-Designer.

Hat einer ähnliche Probleme oder any hints?

Hinrich

30.10.2010 - 23:28 Uhr

Hi,

was also könnte ich jetzt machen? Die Lizenzen von MS sind so was von undurchsichtig...

Ich nutze jetzt VS 2008 Prof und möchte gerne auf eine vergleichbare Version upgraden, wobei MSDN für mich eigentlich nicht so wichtig ist. Any hints?

Hinrich

10.10.2010 - 16:12 Uhr

Welchen Wrapper nimmt man für SQLLite?

Guckst Du hier: SQLite.NET

Hinrich

10.10.2010 - 11:35 Uhr

Hallo!

Ich benutze dafür SQLite.

Hinrich

05.07.2010 - 21:14 Uhr

Es fehlt auch noch ein reader.Read(), am besten mit einer if-Abfrage.

Hinrich

30.06.2010 - 09:16 Uhr

Hallo,

in den letzten Tagen häufen sich wieder diese Meldungen:


SQL-DATABASE ERROR

Database error in WoltLab Burning Board (): Link-ID == false, connect failed
mysql error: User v***** has already more than 'max_user_connections' active connections
mysql error number: 1203
mysql version: unknown
php version: 4.4.9
Date: 30.06.2010 @ 08:46
Script: /wbb2/
Referer:

Hinrich

29.06.2010 - 12:27 Uhr

Hallo,

Verwirrungsgebiet 1: Der Preis
...
Zuständiger Kollege ruft heute bei <großem Distributor> an: Die haben eine andere Sonderaktion, bei der man von VS2008Std auf VS2010Prof updaten kann für ca. 300. Das Update von VS2008Prof auf VS2010Prof kostet ca. 600€. Der kleine Sprung Prof>Prof ist also doppelt so teuer wie Std>Prof.

worüber ich mich denn ärgern könnte. Ich habe die 2008 Prof. und wollte irgendwie mal updaten. Die anderen Lizenzen sind nicht interessant, da es um eine reine innerbetriebliche Entwicklung geht.

Hinrich

27.02.2010 - 11:18 Uhr

In der iX beginnt mit der Ausgabe 3 ein Tutorial zu OOo.

Hinrich

26.02.2010 - 19:50 Uhr

es sollte schon auf Dateibasis bleiben um unabhängig der verschiedenen Server zu bleiben, das Tool arbeitet mit 6 verschiedenen Servern welche einander nicht kennen, und diese Produktiv Server sollten nichts von unseren internen Tool wissen.

Auch da könnte sich eine lokale Datenbank (und sei es SQLite) anbieten. Ich meine ja nur, da man bei der Fülle an Log-Einträgen später auch vernünftig auf diese zugreifen können sollte.

Du schlägst also LocalApplicationData vor, mal schaun.

Wenn es Logs sind, die sich auf den Client beziehen, ja. Wenn die eigentlich zu den Nutzdaten gehören, dann müsste der 7. Server her, damit alle Logs aller Clients in einem Log landen.

Wenn du täglich sagst, meinst du eine Überprüfung bei Applikations Start oder zur Laufzeit? Das Tool läuft hin und wieder auch über Nacht.

Wenn ich täglich sage, muss ich sowohl beim Start wie auch beim Datumswechsel die Datei prüfen und ggf. Wechseln. Vielleicht läuft der Client auch auf einem Laptop im Flugzeug, dann muss ich auch noch mögliche Wechsel der Zeitzonen beachten.

Die Archivierten Log Dateien sollten ja irgendwo hin, in den Windows System.

Wenn man sie braucht. Wenn es Textdateien sind, dann würde ich sie in jedem Fall mit Zip packen. Dann könnte man unter LocalApplicationData Unterverzeichnisse anlegen, z. B. Jahr-Kalenderwoche, um später zielgenauer eine passende Datei selektieren zu können.

Das ist ein internes Tool, unsere Endkunden bekommen das nicht, und die Log Einträge sind alle von Bedeutung und können nicht gekürzt werden.

Ich weiss aber nicht, ob die Endkunden das gut finden, wenn eine Anwendung tonnenweise Logs produziert. Und eigentlich sind automatische Logs, die nicht irgendeinen Workflow protokollieren, den man später für eine Beweissicherung benötigt, irgendwann obsolet. Und Workflow-Logs gehören zu den Nutzdaten, im Zweifel auf den 7. Server, der dann eigenen Backup-Richtlinien unterliegt.

Fertig bedeutet wenn die Applikation beendet wird, nur wenn die Applikation anderweitig beendet wird können Daten verloren gehen.

Ein Flush nach dem Schreiben sollte auch beim Absturz unproblematisch sein, da die Puffer geleert und auf die Platte geschrieben wurden.

Durch Entleeren des Streams wird der zugrunde liegende Encoder nicht entleert, wenn Sie nicht ausdrücklich Flush oder Close aufrufen. Wenn AutoFlush auf true festgelegt ist, werden Daten aus dem Puffer in den Stream weggeschrieben, aber der Encoderzustand wird nicht entleert. Dadurch kann der Encoder seinen Zustand beibehalten (Teilzeichen), um den nächsten Block von Zeichen richtig zu codieren. Dieses Szenario betrifft UTF8 und UTF7, bei denen bestimmte Zeichen nur verschlüsselt werden können, nachdem der Encoder das bzw. die angrenzenden Zeichen empfangen hat.

Hinrich

26.02.2010 - 18:14 Uhr
  1. Wohin die Log Dateien?

Datenbank?

  1. Wie benennen?

Wenn es eine Datei sein muss, würde sich anbieten:


string logfile 
    = Environment.GetFolderPath(SpecialFolder.LocalApplicationData)
        + DateTime.Now.ToString("s") + ".log";

  1. Wann neue Dateien anlegen?

Das dürfte wohl Geschmackssache sein. Entweder täglich, bei jedem Programmstart, beim Überschreiten einer gewissen Dateigröße oder nach gewissen Zeitabständen.

  1. Die Alten Dateien, wie weg sichern und wohin?

Da gibt es für Log-Dateien natürlich /dev/nul. Man kann sie natürlich auch archivieren. Nach dem Schließen einer laufenden Log-Datei könnte ein eigener Thread die Datei packen und sonstwohin kopieren (Streamer, anderes Laufwerk, Drucker, Fax...).

Es stellt sich natürlich die Frage nach der Relevanz der Protokollnachrichten. Im Hintergrund könnte auch eine Datei, die archiviert wird, zunächst um unwichtige Einträge bereinigt werden. Handelt es sich aber um Protokolldaten, die mit den Nutzdaten der anwendung in Zusammenhang stehen (z. B. An- und Abmelden von Sachbearbeitern sowie Aufzeichnen derer Tätigkeiten), so würde ich sie auch bei den Nutzdaten speichern. In einer "klassischen" Log-Datei sollten sich imho nur Daten finden, die dem Entwickler Aufschluss über das Programmverhalten geben. Entsprechend sollten in einer stabilen Release-Version eigentlich keine Logs mehr erstellt werden (außer bei Fehlern, die nicht vom Programm eigenständig behoben werden können).

  1. Wie Dateien korrekt schreiben lassen (schließen) auch wenn die Applikation von Windows beendet wird?

Also ich schließe eine Datei, wenn ich mit ihr fertig bin. Wenn ich zwischenzeitlich sicherstellen möchte, dass die Daten aus dem Buffer auf die Platte gelangen, dann ist Flush() eigentlich hilfreich. Für ACID müsste das ganze dann mit Transaktionen gesichert werden.

Die Punkte 4. und 5. bieten sich aber an, sie von einem externen Tool erledigen zu lassen. Ein solches Tool kann man ja entsprechend der eigenen Bedürfnisse implementieren.

Hinrich

20.02.2010 - 13:15 Uhr

Hallo m0rius,

das ist viel zu pauschal formuliert. Willst du Interfaces ihren Nutzen beim
>
absprechen?

nein, aber auch ein Test ist für mich ein Eingriff von Außen.

19.02.2010 - 21:40 Uhr

Hallo herbivore,

die Begriffe Instanz und Objekt sind Synonyme und können an (fast) allen Stellen im Text ausgetauscht werden, ohne dass dadurch die Bedeutung geändert wird.

wo eigentlich nicht?

Hinrich

19.02.2010 - 21:38 Uhr

ClassA Instanz = new ClassB();

Was erzeuge ich denn jetzt eigentlich, ein Objekt vom Typ A oder B? Ich habe jetzt natürlich schon den ein oder anderen Testlauf gestartet.

Du hast ein Objekt vom Typ ClassA, welches aber ohne das Werfen einer Exception auf ClassB gecastet werden kann. D. h. ohne Cast ist die Methode Y nicht verfügbar, sondern nur die Methode X.

Kann man sagen dass Instanz ein Objekt vom Typ B ist, dass nach außen aber "kastriert" wurde und eben nur die Methoden anbietet, die A ebenfalls besitzt?

Das kann man so wahrscheinlich nicht sagen (Informatiker der reinen Lehre, wo seid Ihr?), aber es läuft zumindest darauf hinaus.

Aber irgendwie doch eher B als A...

Bau Dir entsprechenden Interfaces. Dann kannst Du mit IWasIchBraucheVonB Instanz = new ClassB das erreichen, was Dir vorschweb.

Hinrich

19.02.2010 - 21:31 Uhr

In Deinem Fall würde ich folgendes machen:


public interface IFeldBus
{
   void Senden();
   void Empfangen();
}

public interface IFeldBusV2 : IFeldBus
{
   int BusLast { get; } // int ist hier besser, weil default type, 0 % ... 100 %
}

Ein Interface macht ja nur Sinn, wenn ich etwas so abstrahiere, dass die abstrahierten Eigenschaften und Methoden nicht durch die normale Klassenvererbung dargestellt werden können (Mehrfachvererbung gibt es ja leider nicht) wie z. B. ICompareable, oder ich nach außen etwas publizieren möchte, was quasi wie ein physischer Stecker normiert ist wie z. B. IDataAdapter.

Solange aber ich mich in der Entwicklung an einer Stelle befinde, die niemanden außer mir zu interessieren hat, also keine Zugriff von Plugins oder anderen Programmteilen, kann ich mir Interfaces getrost schenken.

Hinrich

19.02.2010 - 21:15 Uhr

wuerdet ihr das auch mittels einer ArrayList machen?

Ich würde ein Stack<T> nehmen, aber das ist mehr so ein Bauchgefühl.

Hinrich

14.02.2010 - 20:00 Uhr

(...) Ich kenne auch die GetDouble Methode des readers allerdings müsste ich dann immer die Feldposition wissen. (...)

public double getDouble(IDataRecord row, string fieldname)
{
    // TODO: NULL-Werte abfangen
    // TODO: row validieren
    // TODO: fieldname validieren
    double value = row.GetDouble(row.GetOrdinal(fieldname));
    return value;
}
12.02.2010 - 10:12 Uhr

... unzwar muss ich erst eine Verbindung öffnen bevor ich den EventHandler anhäng.

Hallo,

das kann ich so nicht nachvollziehen. Ich nutze eine abstrakte Basis innerhalb des Data Layer, die auszugsweise so aussieht:

        /// <summary>
        /// Eine Verbindung zurückgeben
        /// </summary>
        /// <returns>Geschlossene Verbindung</returns>
        virtual protected MySqlConnection GetConnection()
        {
            return this.GetConnection(false);
        }

        /// <summary>
        /// Eine Verbindung zurückgeben
        /// </summary>
        /// <param name="open">TRUE gibt eine geöffnete Verbindung zurück</param>
        /// <returns>Verbindung</returns>
        virtual protected MySqlConnection GetConnection(bool open)
        {
            MySqlConnection connection = new MySqlConnection(this.DSN);
            connection.StateChange
                += new System.Data.StateChangeEventHandler(connection_StateChange);
            connection.InfoMessage
                += new MySqlInfoMessageEventHandler(connection_InfoMessage);
            if (open)
                connection.Open();
            return connection;
        }

Zu einem Fehler ist es dabei noch nicht gekommen. Ich verwende den .NET-Connector Version 6.1.2.

Hinrich

07.02.2010 - 13:40 Uhr

[...] Da noch kein Preimage-Angriff bekannt ist, [...]

Du verkennst aber, dass es sich nicht um einen Preimage-Angriff handelt, da mit der Datei ja eben das Urbild bekannt ist.

Und um da Wiki nochmals zu bemühen:

... Vor diesem Hintergrund ist von einer Weiterverwendung von MD5 abzuraten.

07.02.2010 - 00:17 Uhr

Hallo herbivore!

Wobei es selbst da die Frage ist, wie wahrscheinlich so ein Angriff in der Praxis tatsächlich ist. Dass MD5 angreifbar ist, sagt ja nichts darüber aus, wie wahrscheinlich ein Angriff ist. Ich halte es z.B. für relativ unwahrscheinlich, dass mir jemand manipulierte Dateien unterschiebt, damit ich einige eigene Dateien fälschlich als Duplikate erkenne und lösche. 😃 Und um das Finden von Duplikaten ging es ja in diesem Thread hauptsächlich. Also selbst unter Sicherheitsaspekten würde ich MD5 zur Ermittlung von Duplikaten auf der heimischen Festplatte nicht ablehnen.

Die Wahrscheinlichkeit eines Angriffs hängt natürlich von der realen Umgebung ab. Aber bei einem Internet-Server oder einem Intranet (zum Beispiel im Sektor Biotech) kann die Wahrscheinlichkeit, dass aus welchem Grund auch immer eine Datei untergeschoben wird, nicht so trivial sein, dass man sie bei der Implementierung eines Dubletten-Löschers vernachlässigt.

Ausgehend von einem böswilligen Unterfangen (was man aus Sicherheitsgründen jedem immer unterstellen sollte) ist es heute leicht, eine Datei mit einer identischen MD5 zu erzeugen. Dass die Daten zur Erstellungs-, Änderungs- und anderen Zeiten gefälscht sein können, dürfte kaum bezweifelt werden.

Unabhängig von der Frage, welche Datei im Falle einer vermeindlichen Dublette denn gelöscht werden soll, würde ich mich ungerne auf eine reine MD5-Prüfung verlassen. Man könnte auf eine andere, möglichst zusätzliche Prüfsumme zurückgreifen. Eine simple CRC32, die die Performance bei der Erstellung der Prüfsummen kaum verschlechtert, dürfte zusammen mit der MD5 bereits einen befriedigenden Schutz gegen untergeschobene Dateien geben. Wem das nicht reicht, der mag MD5 mit SHA1 oder besser kombinieren.

Ich würde aber immer zwei Hashes auf eine Datei prüfen, um eine belastbare Aussage über deren Eindeutigkeit zu erhalten. Je nach Abwägung zwischen Sicherheit, Performance und Datenmengen kann ich natürlich auch die Prüfsummen auf nur beispielsweise 75% der Datei anwenden.

Hinrich

06.02.2010 - 23:46 Uhr

Das wird die einzige Möglichkeit sein, um da an DB Daten bei einem Massenhoster zu kommen.

Sicher und ohne Verlust am Kompfort geht es auch mit einem VPN-Tunnel zwischen meinem lokalen Rechner (typischerweise im lokalen Intranet) und dem Server beim Massenhoster.

BTW: Die aktuelle c't zeigt sogar eine Möglichkeit, wie zwei MySql-Server sich quasi im Hintergrund synchronisieren.

Hinrich

06.02.2010 - 17:20 Uhr

Um den Themenstarter vollends zu verwirren, möchte ich noch anführen, dass mit this auch Indexer deklariert werden, und auch Extension-Methods.

Vergiss bitte nicht die Verwendung bei Extensions. 😉

06.02.2010 - 11:07 Uhr

Moin!

Auch bei mehreren Konstruktoren kann this. benötigt werden.

class Foo : Bar
{
    private string aString;

    public Foo()
        : base()
    {
        aString = string.Empty;
    }

    public Foo(string myNewString)
        : this()
    {
        aString = myNewString;
    }
}

Hinrich

05.02.2010 - 23:46 Uhr

... Wobei die Wahrscheinlichkeit, dass dabei was schief geht, deutlich höher ist, als dass zwei MD5-Summen zufällig übereinstimmen. ...

Was natürlich voraussetzt, dass man nur den Zufall als Gegner hat. Unter Sicherheitsaspekten wäre MD5 abzulehnen.

Hinrich

02.02.2010 - 16:48 Uhr

Moin!

Der Streit ist Kult.

Aber vielleicht gibt es hier ein paar Ideen.

Persönlich wähle ich für Tabellen die englische Form im Singular, z. B.

Grave

statt

Graves

. Singular deshalb, weil es sich ja um eine Tabelle handelt. Eine Tabelle impliziert bereits, dass sie 0 oder mehrere gleichartige Daten beinhaltet.

Hinrich

02.02.2010 - 09:17 Uhr

Moin!

also ich fange Fehler grundsätzlich so weit oben wie möglich und so tief wie nötig, Meistens in der Logik-Schicht, eigentlich nie in der Daten-Schicht. Sollte die Daten-Schicht inkonsestente Daten (-strukturen) finden, so lasse ich dort eine Exception werfen, denn die Ursache kann nur ein Fehler in der Programmierung sein. Und da hilft ein bischen herumdoktorn an den Daten auch nichts, sondern führt auf lange Sicht nur zu noch mehr Problemen.

Hinrich

29.01.2010 - 21:37 Uhr

Bei Software die Industriell zum Einsatz kommt, ...

Ich weiß ja nicht, was Du unter industriellem Einsatz verstehst. Für mich heitsst das, ein Arbeiter schaut auf einen Display, der in schön übersichtlicher Form den Status darstellt, die Einstellungen vornehmen lässt und als Eingabe ein abgespecktes Keyboard hat.

Dann würde ich mit GroupBox die einzelnen Stati thematisch gruppieren und mit Farben (sofern möglich) und einfachen Icons arbeiten, um zu visualisieren. Z. B. ein Getreidetrockner besteht aus dem Trockner (Einlauf, Auslauf, jeweils mit Temperatur und Feuchtigkeitssensoren versehen), einem Wärmeerzeuger (Temperatursensor, vielleicht auch Energiereserve) und einem Rezept (Eingangsfeuchte-Getreideart-Ausgangsfeuchte). Die einzelen Teile kann man schön gruppieren und Soll-Ist-Werte schön farbig darstellen (Fehlerintensität, z. B. Feuchte beim Ausgang, Getreide Weizen: 14,5% grün, +/- 0,5% langsam rot werdend). Zusammenfassend könnte in einer GroupBox die Gesamtfehlerintensität skaliert dargestellt werden, so dass der Arbeiter auf einen Blick alle Prozessdaten unter Kontrolle hat.

26.01.2010 - 14:58 Uhr

Eine spontane Umfrage unter 5 (meist promovierten) Mathematikern mit unterschiedlichen Studienorten ergab, dass niemand das mathematische Runden als solches kannte 👶. Zumindest scheint diese Definition also nicht allgemein Verbreitet zu sein.

Wie schön, dass ich nicht alleine darstehe. Immerhin habe ich keine Mathematik studiert, sondern nur so'n langweiliges BWL. Aber an dem Begriff mathematisches Runden störe ich mich dennoch. Wikipedia (zumindest die deutsche Ausgabe, nicht aber die englische Fassung) spricht zwar vom mathematischen Runden, aber Microsoft spricht in seiner Hilfe lediglich vom Standard IEEE 754. Die englische Fassung von Wikipedia bezeichnet das Round half up als mathematisches Runden, wobei dort eine fehlende Fußnote bemängelt wird. Das Runden nach IEEE 754 (half to even) wird als unbiased rounding, convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding, or bankers' rounding bezeichnet, nicht aber als mathematisches Runden.

Ich würde den Artikel der deutschen Wikipedia insofern als fehlerhaft einstufen.

23.01.2010 - 13:22 Uhr

Dazu kommt, dass ich beim Rechnen im Mathematikunterricht nicht mathematisch, sondern kaufmännisch runden musste.

Das ist schon seit einer Stunde in meinem Kopf. Ich meine nämlich auch, dass ich damals in der Schule kaufmännisch runden musste. Das mathematische Runden ist mir zumindest in der Schule nie unter gekommen.

Ich halte auch die Aussage in der deutschsprachigen Wikipedia für falsch. Es gibt keine Zahl genau in der Mitte, da bei den reelen Zahlen 2,0 nicht ausgeschlossen ist. 2,50 ist damit genau die erste Zahl der zweiten Halbmenge, 2,49 die letzte der ersten, wobei beide Teilmengen (in diesem Beispiel) aus 50 Zahlen bestehen.

Ich kann da auch keinen systematischen Fehler erkennen. Dieses würde erst auftreten, wenn man 3,0 in die Betrachtung einbeziehen würde, was jedoch aus meiner Sicht systematisch falsch wäre. offensichtlich aber die Grundlage dieser Überlegung zu sein scheint. Dann ist natürlich eine Rundungsverfahren notwendig, welches den falschen Systemansatz wieder ins Lot bringt.

Völlig verwirrt,
Hinrich

21.01.2010 - 16:12 Uhr

Aufgebaut ist es wie folgt - es gibt eine mainForm, die enthält das DockPanel.
Dann erzeuge ich 1 bis viele DockContents (die alle von Form erben) - diese lassen sich dann ans DockPanel andocken. Anschließend rufe ich .dispose() der DockContents auf.

Die 1 bis vielen Forms erben hoffentlich von DockContent und nicht von Form direkt. Und in dem jeweiligen Fenster ist dann auch die Eigenschaft HideOnClose auf false gesetzt, nehme ich an. Außerdem weiß das Fenster auch, dass es zu einem DockPanel gehört?


public partial class PanelForm : WeifenLuo.WinFormsUI.Docking.DockContent
{
    // ...
}

public partial class Form1 : Form
{
    // ... hat irgendwo DockPanel dockPanel1

    void openPanelForm()
    {
        var form = new PanelForm(this.dockPanel1);
        form.HideOnClose = false;
        // andere Einstellungen
        form.Show();
    }
}

Dann sollte ein Close() im Unterfenster auch die Resourcen freigeben, es sei denn, Du hast sie noch irgendwo anders zwischengespeichert.

Hinrich