Laden...

Forenbeiträge von RBA285 Ingesamt 68 Beiträge

05.03.2013 - 18:42 Uhr

So, nachdem wir nun unseren Server migriert haben, möchte ich hier noch ein Feedback abgeben. Ich habe mich jetzt doch nicht für Azure entschieden, sondern für einen Windows 2012 vServer von qualityhosting.de. Die gewählte 8 GB RAM/ 500 GB HDD-Variante kostet uns 89 Euro netto/ Monat, dass ist für diese Leistungsklasse in Ordnung. Bereitstellung, Geschwindigkeit und Zugang hat alles bestens geklappt, es gibt bis jetzt keinen Kritikpunkt. Das System selbst war auch sauber aufgesetzt, die benötigen Features (IIS8, ASP.NET usw.) können problemlos über die Management-Konsole nachinstalliert werden, Web-Deploy über den wpilauncher. Dies nur als Hinweis, falls jemand auch Bedarf an leistungsfähigen Windows 2012 vServern für ASP.NET Apps hat.

Robin

04.02.2013 - 13:51 Uhr

Trotz anscheinend jahrelanger Hardware-Erfahrung =) wird ein heimisches Notebook mit 32GB NON-ECC mit einem 4 GB ECC RAM vServer verglichen. Zudem wird dann ein Windows mit einem Linux vServer verglichen. Allein die Infrastruktur der Hoster muss hier schon eine völlig andere sein.
Ist das gleiche, als ob man einen heimischen Rasenmäher mit einem Mähdrescher auf dem Bauernhof vergleicht 😉){gray}

Die Mehrkosten für ECC RAM sind abolut gesehen Banane. Was sind schon ein paar Hundert Euro Mehrkosten verteilt über einen Abschreibungszeitraum X bei Y Usern? Teuer ist der Service und der Unterhalt der Gesamt-Infrastruktur: Personal, Räumlichkeiten, Brandschutz wg. den Versicherungsprämien, Klimatisierung, Racks, SAN, Strom usw. Sicher hast Du auch eine fundierte Erklärung dafür, weshalb bei einem Linux vServer > 10 GB sinnvoll sind und bei einem ein Windows 2012 Server nicht. Zuerst hast Du das Kostenarguemnt für ECC ins Feld geführt, jetzt ist es die "völlig andere Infrastruktur". Bekommt man ECC RAM für Linux Systeme günstiger oder ist Linux soviel ressourcenhungriger? Ich lerne immer gerne dazu.

04.02.2013 - 11:51 Uhr

Danke, dass ist doch mal ein heißer Tipp. Das Azure habe ich schon mal beim Web Deployment Tool gesehen, wusste aber nicht, was es damit auf sich hat.

Merci,
Robin

04.02.2013 - 11:47 Uhr

Tja, dann musst Du das mal der Wirtschaft sagen.
Dein Notebook ist aus Hardware-Sicht ein Witz gegen ein Server-System. Ein echtes Server Mainboard fängt bei 800€ an. Xeon CPUs liegen bei 1000€ pro Stück. Server verbauen zudem ECC Speicher, die 4-5 mal so viel kosten wie Dein NON-ECC Speicher.

Ich möchte jetzt nicht in eine Hardware-Diskussion einsteigen, da ich selbst viele Jahre bei einem großen euopäischen Hardwarehersteller gearbeitet habe (u. a. Blade-Server) und mich rudimentär mit der Materie auskenne. Zudem gibt es sehr wohl Anbieter am Markt, die auch vServer > 20 GB RAM anbieten, (z. B. blu), leider eben nicht mit den von uns gewünschten Softwaremerkmalen sondern auf Linux-Basis.

Deshalb wäre ich sehr dankbar, wenn jemand etwas zur Sache selbst beitragen könnte oder aus eigener Suche die Erfahrung gemacht hat, dass es noch nichts entsprechendes gibt. Bei Centron sind wir auf der Mailingliste, die wollen etwas entsprechendes die nächsten Monate rausbringen, aber alles unverbindlich. Was ich nicht brauche sind Tipps, warum das was wir umsetzen wollen, falsch sei. Wir wissen war wir tun.

Robin

04.02.2013 - 09:59 Uhr

vServer und so viel Resourcen / Anforderungen? Das passt nicht.
Damit wirst Du einen RootServer haben wollen.

Nein, möchte ich nicht. Warum sollte das nicht passen? Selbst auf meinem Notebook (32 GB) läuft ein Win2012 Server Teststystem (8 GB) und ein VS Development-System (Win 8 mit 4 GB) virtuell mit Hyper-V ohne Probleme (Wirtsystem ist Win 8 Pro). Speicher ist heutzutage doch kein Thema mehr. Das (teure) Lizenzthema ist bekannt. Soweit ich das sehen konnte, bietet Hetzner nur Win 2008 Server. Also absolut nicht das, was wir wollen, sorry.

Robin

04.02.2013 - 08:00 Uhr

Wir migrieren gerade unseren Win 2003 Server und unsere ASP.NET Applikationen auf Win 2012 Server. Trotz intensiver Suche scheint da noch nicht viel am Markt zu existieren.

Konkret geht es um diese (Wunsch-)Konfiguration:

  • vServer mit Windows 2012 Server
  • 4-6 GB RAM, 100 GB Plattenplatz
  • ASP.NET bis v4.5 inkl.
  • Web Deploy für ASP.NET sollte vorhanden oder installierbar sein (PHP & Co. wird nicht benötigt)
  • Uneingeschränkter Zugang mit Remote Desktop zu allen Systemfunktionen
  • Features müssen nachinstallierbar sein
  • SQL Server 2012 Express muss installierbar sein
  • hMail Server muss installierbar sein
  • Patch-Management inklusive oder durch uns
  • Automatisiertes oder manuelles Backup der gesamten Partition

Traffic bewegt sich im üblichen Rahmen, rd. 25 Mailboxen und ein paar Webauftritte, aber nichts dramatisches.

Hat da jemand einen Tipp?

Danke,
Robin

04.02.2013 - 07:45 Uhr

Ok, Problem gelöst, funktioniert mit Windows Search (fast) identisch, habe mir das komplizierter vorgestellt. Wer auch vor diesem Problem steht, folgende Hinweise zur Migration:

  1. Zuerst das betreffende Web in den Search-Index aufnehmen. Über Charms-Leiste nach "Indizierungsoptionen" suchen und Programm starten. Web in die Indizierung aufnehmen (z.B. C.\intetpub\myweb), fertig. Windows Search muss natürlich als Dienst laufen.

  2. Im Source OLEDB von Index-Server Suche auf Windows Search umstellen:

odbSearch.ConnectionString = "Provider=Search.CollatorDSO;Extended Properties=\"Application=Windows\"";
            
cmdSearch.Connection = odbSearch;

cmdSearch.CommandText = "SELECT System.Title, System.FileName, System.ItemPathDisplay, System.Search.Rank, System.FileDescription, System.Size" +
                                    " FROM SystemIndex WHERE SCOPE='file:C:/inetpub/myweb' AND CONTAINS('" + txtSearch + "')" +
                                    " AND  (System.FileExtension=\'.aspx\' OR System.FileExtension=\'.pdf\')" +
                                    " ORDER BY System.Search.Rank";

odbSearch.Open();

Achtung: Die Felder und deren Inhalte unterscheiden sich zum Teil von denen, die man im Index Search verwenden konnte. Z. B. gibt es keinen vPath mehr. Da muss man sich eine kleine Funktion basteln, die aus dem absoluten Pfad den Web-Pfad bastelt.

Eine Übersicht der zur Verfügung stehenden Felder und Attribute für die Search gibt es hier:
System

Infos zum verwendeten SQL-Syntax für die Suche gibt es hier:
Querying the Index with Windows Search SQL Syntax

Robin

21.01.2013 - 09:07 Uhr

Hallo Zusammen,

bin gerade am Migrieren einer 3.5 ASP.NET Webapplikation (C#, Server 2003) auf einen Windows 2012 Server mit .NET 4.5. Dabei hänge ich bei der implementierten Volltextsuche des Web-Contents im Userfrontend, die auf einen Catalog des Indexing-Service aufgesetzt ist (Windows 2003 Server). Was ich durch intensiveres Googeln herausgefunden habe ist, dass der Indexing Service im 2012 Server wohl nicht mehr existiert und stattdessen Windows Search verwendet werden soll. Hat jemand von euch Erfahrung, bzw. ein Codebeispiel in C#, wie man Windows Search für eine Volltextsuche eines Web-Contents verwendet (wird auf der Website angeboten)? Bisher wurde das in der Applikation so gelöst (mit Indexing-Service über einen Catalog, gleichzeitig werden gewisse Verzeichnismuster und Files herausgefiltert):


        public bool Search(string txtSearch)
        {
            bool bError = false;

            OleDbConnection odbSearch = new System.Data.OleDb.OleDbConnection();
            OleDbCommand cmdSearch = new System.Data.OleDb.OleDbCommand();
            OleDbDataReader rdrSearch;

            this._searchItems.Clear();

            //assign the connecting string to the oledb connection object , replace Catalog Name with the name of index catalog created earlier 
            odbSearch.ConnectionString = "Provider=\"MSIDXS\";Data Source=\"AppCatalog\";";
            //assign connection to command object cmdSearch 
            cmdSearch.Connection = odbSearch;

            //Query to search a free text string in the catalog in the contents of the indexed documents in the catalog 

            try
            {
                // Make freetext search in the contents and retreive document titles , path , rank from the index catalog
                cmdSearch.CommandText = "SELECT doctitle, filename, vpath, rank, characterization, size FROM SCOPE('DEEP TRAVERSAL OF \"\\\"') WHERE " +
                                        "CONTAINS(Contents, '\"" + txtSearch + "\"') AND " +
                                        "NOT CONTAINS(vpath, '\"_vti_\" OR \".config\"') AND " +
                                        "NOT CONTAINS(filename, '\".cs\" OR \".css\" OR \".txt\" OR \".config\"') AND " +
                                        "CONTAINS(filename, '\".aspx\" OR \".htm\" OR \".html\"') " +
                                        "ORDER BY RANK DESC";
                odbSearch.Open();
                try
                {
                    rdrSearch = cmdSearch.ExecuteReader();

                    while (rdrSearch.Read())
                    {
                        this._searchItems.Add(new SearchItem(rdrSearch[0].ToString(), rdrSearch[1].ToString(), rdrSearch[2].ToString(), rdrSearch[3].ToString(), rdrSearch[4].ToString(), rdrSearch[5].ToString()));
                    }
                }
                catch (Exception ex)
                {
                    bError = true;
                }
                odbSearch.Close();
            }
            catch (Exception ex)
            {
                bError = true;
            }

            return (!bError);
        }


Danke euch!
Gruß
Robin

03.04.2011 - 12:17 Uhr

Hallo Zusammen,

folgende Situation: Eine größere Webapplikation (C#/ASP.NET/VS2008) verwendet Panels, die mittels AjaxControlToolkit mit Drag&Drop auf der Website bewegt werden können. Daneben läuft noch einiges an Javascript im Hintergrund, der die Panels sichtbar/unsichtbar setzt oder diese mittels Timer bewegt.

Seitdem ich auf IE9 upgegradet habe, funktionieren die Panels (weder sichtbar noch drag&drop) nicht mehr. Wenn ich im IE9 den "gesicherten Mode" deaktiviere oder die Domain der App zu den trusted sites schiebe, funktioniert wieder alles. Ich vermute deshalb ein Security-Thema.

Seltsamerweise ist das nur beim IE9 so, weder beim IE8, noch bei den neuesten Versionen von FF, Safari und Chrome.

Kennt jemand das Thema? Kann man das irgendwie lösen, ohne das der User an den Browsereinstellungen etwas ändern muss?

Vielen Dank!
Robin

14.10.2010 - 19:05 Uhr

Problem gelöst, es saß, wie so oft, vor dem PC.
Die Settings werden über über Cookies gespeichert. Das Cookie-Handling
wiederum ist bei mir in einer Web-Lib ausgelagert, an der ich was geändert hatte.
Tja, die Änderung bewirkte, dass die Cookies nicht mehr gesetzt wurden. :evil:

Hatte also nichts mit der Collection zu tun, sorry für die Störung, hatte einfach
ewig an der falschen Stelle gesucht.

Robin

14.10.2010 - 17:01 Uhr

Hallo,

Im Codebehind werden mehrere Subsets von
RadioButtons innerhalb einer asp:Table vom Programm (!) generiert.
An welcher Stelle / in welchem Handler?

Derzeit im Page_Load (ruft entsprechende Methode auf). Es geht aber
nicht darum, dass die Controls zu spät generiert werden, sondern dass die
vom User gesetzten Werte der RadioButtons durch das erneute Rendern
beim PostBack verloren gehen. Deshalb gehen die I-Net Lösungen vermutlich
auch alle über das individuelle Event des Controls.

Mir ist schon klar, dass die gesetzten Werte durch das erneute Rendern
und generieren der RB-Controls verlorengehen (müssen)
Nicht unbedingt.
Dynamisch generierte Controls sollten im Page_PreInit erstellt werden, dann
müssten ViewState (sofern eingeschaltet) und Post-Daten dafür sorgen, daß die
Werte immer richtig besetzt werden.
Siehe auch
>
,
vor allem im Abschnitt Lebenszyklusereignisse. Da steht welche Aktionen wann
stattfinden (sollen).

Viewstate ist an, mit Page_Init hatte ich schon mal einen Versuch angestellt, aber
PreInit noch nicht, da werde ich nachher mal einen Versuch starten.

Danke!
Gruß
Robin

14.10.2010 - 16:24 Uhr

Hallo Zusammen,

folgende Situation: Im Codebehind werden mehrere Subsets von
RadioButtons innerhalb einer asp:Table vom Programm (!) generiert.
Die SubSets sind immer die gleichen, d.h. die Anzahl und die Gruppen
der Radiobuttons sind immer identisch.

Gibt es irgendeine Möglichkeit, über die Control-Collection beim PostBack auf die
gesetzten Werte (checked) mit foreach zuzugreifen, oder muss man tatsächlich
Button-Individuell über das entsprechende Click-Event gehen?
Umfangreichere I-Net Recherchen bringen nur die Event-Lösung zu Tage.

Mir ist schon klar, dass die gesetzten Werte durch das erneute Rendern
und generieren der RB-Controls verlorengehen (müssen), aber vielleicht gibt es ja
einen speziellen Kniff, genau dies zu umgehen, zumindest solange, bis die
einzelnen Werte (checked/unchecked) beim Postback ausgelesen sind.

Danke,
Gruß
Robin

22.08.2010 - 15:02 Uhr

Es ist schon die große Frage, warum x++ so verbreitet ist,
obwohl so gut wie alle Analogieüberlegungen für ++x sprechen.

Eventuell auch deswegen, weil in der Qualitätsliteratur (für mich hauptsächlich
Addison Wesley und O'Reilly) alle Beispiele und Sniplets den postfix verwenden
und der präfix meist nur der Vollständigkeithalber erwähnt wird.

In Summe tippe ich auf historische Gründe, da beim for-next in den alten
Hochsprachen das inkrement erst beim next, d.h. im nachhinhein erfolgte.
Auch bei alten, assemblernahen Sprachen wie z.B. Forth stand der operator immer
am Ende, z.B. 25 10 + (UPN).

Ich denke beide Lösungen sind o.k., der Lesbarkeit tut es in Summe keinen
Abbruch, da dass inkrement bei der Analyse fremden Codes das kleinste Problem
hinsichtlich der Lesbarkeit darstellen dürfte.

Robin

21.08.2010 - 22:59 Uhr

den (object) cast kannst du dir sparen. in c# ist ja alles ein object!

Schon klar, war auch nur ein Versuch zur "Besänftigung" des Compilers,
da er den generischen Typ nicht als signaturkonformes Objekt akzeptieren wollte.

Robin

21.08.2010 - 22:40 Uhr

Hallo herbivore,

Hier meckert der Compiler wieder, dass er das <T>-Argument vermisst.

object System.Collections.IEnumerator.Current  
{  
   get { return this.Current; }  
}  
  

Generell siehe
>
.

schon klar was der Compiler bemängelte, allerdings war mir nicht bewusst,
weshalb, deshalb hilft dieser Link - zumindest mir in diesem Fall - nicht weiter.

Hm, ich halte mich da an meine "Bibel" (C# 3.0 kurz & gut von O'Reilly) ...
... die du allerdings missdeutet hast. Sicher wird für foreach ein Enumerator
benötigt. Aber dieser wird von foreach per IEnumerable<T>.GetEnumerator ()
abgerufen. Also muss deine Klasse IEnumerable<T> implementieren, um in
foreach benutzt werden zu können.

Ok, danke, dass ging aus den Beispielfragmenten nicht hervor.

Nach längeren Versuchen und Anpassung eines (nicht ganz passenden)
Beispiels aus dem I-Net habe ich es jetzt doch noch hinbekommen:
(Anforderung war die Erstellung eines eigenen Dictionarys auf Basis zweier
eindimensionaler Listen).

namespace DictionaryEigenes
{
    //----------------------------------------
    class MyDictionary<TKey, TValue> : IEnumerable<TKey>
    //----------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;

        //----------------------------------------
        public MyDictionary()
        //----------------------------------------
        {
            _keys = new List<TKey>();
            _values = new List<TValue>();
        }

        //----------------------------------------
        public void Add(TKey key, TValue value)
        //----------------------------------------
        {
            _keys.Add(key);
            _values.Add(value);
        }

        //----------------------------------------
        public void Remove(TKey key)
        //----------------------------------------
        {
            int index = _keys.IndexOf(key);
            if (index >= 0)
            {
                _keys.RemoveAt(index);
                _values.RemoveAt(index);
            }
        }

        //----------------------------------------
        public int IndexOf(TKey key)
        //----------------------------------------
        {
            return _keys.IndexOf(key);
        }

        //----------------------------------------
        public TValue GetValue(TKey key)
        //----------------------------------------
        {
            int index = this.IndexOf(key);
            if (index >= 0)
                return this._values[index];
            else
                return default(TValue);
        }

        //----------------------------------------
        public TKey this[int index]
        //----------------------------------------
        {
            get
            {
                return _keys[index];
            }
        }

        //----------------------------------------
        public int Count()
        //----------------------------------------
        {
            return _keys.Count;
        }

        //----------------------------------------
        public IEnumerator<TKey> GetEnumerator()
        //----------------------------------------
        {
            return new Enumerator(this);
        }

        //----------------------------------------
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        //----------------------------------------
        {
            return this.GetEnumerator();
        }


        //----------------------------------------
        public class Enumerator : IEnumerator<TKey>
        //----------------------------------------
        {
            private MyDictionary<TKey, TValue> _internalDictionary;
            private int _index;
            private TKey _current;

            //----------------------------------------
            internal Enumerator(MyDictionary<TKey, TValue> internalDictionary)
            //----------------------------------------
            {
                if (internalDictionary == null)
                    throw new ArgumentNullException("reference list cannot be null!");

                this._internalDictionary = internalDictionary;
                this._index = 0;
                this._current = default(TKey);
            }

            //----------------------------------------
            public TKey Current
            //----------------------------------------
            {
                get { return this._current; }
            }

            //----------------------------------------
            public void Dispose()
            //----------------------------------------
            {
                this.Reset();
            }

            //----------------------------------------
            object System.Collections.IEnumerator.Current
            //----------------------------------------
            {
                get { return (object)this.Current; }
            }

            //----------------------------------------
            public bool MoveNext()
            //----------------------------------------
            {
                if (this._index < this._internalDictionary.Count())
                {
                    this._current = this._internalDictionary[this._index];
                    this._index++;
                    return true;
                }
                return false;
            }

            //----------------------------------------
            public void Reset()
            //----------------------------------------
            {
                this._index = 0;
                this._current = default(TKey);
            }
        }

    }
}

Das muss ich mir morgen nochmals in Ruhe zu Gemüte führen, die
Generics haben es in sich.

Robin

21.08.2010 - 21:17 Uhr

du machst einmal deine generische implementierung

  
public TKey Current  
{  
   get {   
      if(_keys.Count <= 0) throw new ApplicationException();  
     return _keys[_index];  
   }  
}  
  

Funktioniert soweit....

und dann deine explizite implementierung für IEnumerator

  
object IEnumerator.Current  
{  
   get { return this.Current; }  
}  
  

Hier meckert der Compiler wieder, dass er das <T>-Argument vermisst.
Ich wüsste jetzt auch nicht, wie die Signatur "richtig" aussehen sollte.
Zudem bemängelt er noch immer, dass der Rückgabewert kein Object ist.
Casting bringt leider auch nix...

bist du aber sicher, dass du deine collection von Ienumerator und nicht von Ienumerable ableiten willst?

Hm, ich halte mich da an meine "Bibel" (C# 3.0 kurz & gut von O'Reilly).
In dieser steht, dass der Enumerator den Cursor für die foreach-Schleife
mit MoveNext usw. zur Verfügung stellt, inkl. Beispiel. Mir geht es hauptsächlich
um die generische Implementierung dieser Funktionalität und das dadurch
(hoffentlich) tiefere Verständnis von Generics, weniger um Alternativen.

Danke,
Robin

21.08.2010 - 20:27 Uhr

Hallo Forum,

folgende Klassen-Signatur ist gegeben:

class MyDictionary<TKey, TValue> : IEnumerator<TKey>

Diese Klasse soll eine eigene Dictionary-Funktionalität ähnlich des system-
eigenen Dictionarys bereitstellen. Aber darum geht es eigentlich nicht. Es
geht um die Frage, wie die Content-Property des generischen IEnumerators
implementiert wird bzw. werden soll.

Implementiere ich die Property so

public TKey Current 
                {
            get
            {
                if (_keys.Count > 0)
                    return (_keys[this._index]);
                else
                    return (default(TKey));
            }
        }

dann meckert der Compiler, dass Current keine gültige Implementierung
von IEnumerator ist, da als Rückgabewert ein Object erwartet wird.

Implementierte ich die Property so

public Object Current 
                {
            get
            {
                if (_keys.Count > 0)
                    return ((Object)_keys[this._index]);
                else
                    return ((Object)default(TKey));
            }
        }

dann meckert der Compiler, dass er eine Implementierung von Current
erwartet, die als Typ TKey zurückgibt. 8o

In der MSDN ist zudem noch dokumentiert, dass man nach Möglichkeit auf die
Implementierung des generischen IEnumerator verzichten soll und stattdessen
den nicht generischen verwenden soll. Das würde m. E. folgender
Klassensignatur entsprechen:

class MyDictionary<TKey, TValue> : IEnumerator

Dann allerdings meckert der Compiler, dass er das <T>-Argument bei
IEnumerator vermisst. Also auch keine Lösung.

Wo liegt mein (Verständnis-)Fehler?

Danke!
Robin

07.08.2010 - 12:22 Uhr

Nachdem ich jetzt auch mt dem Problem konfrontiert war, habe
ich mich nach längerem Suchen für eine sehr schlanke und einfache
Methode entschieden (VS2008):

Im Pre-Build Event des Projektes werkelt folgender Zweizeiler:

IF "$(ConfigurationName)"=="Debug"  COPY /Y "$(ProjectDir)WebDev.config" "$(ProjectDir)Web.config"
IF "$(ConfigurationName)"=="Release" COPY /Y "$(ProjectDir)WebProd.config" "$(ProjectDir)Web.config"

Im Root der Applikation liegen drei .configs:
Web.config => wird beim compilieren überschrieben von
WebDev.Config => Wenn mit "Debug" compiliert wird
WebProd.Config => Wenn mit "Release" compiliert wird

Vielleicht nicht so mächtig wie andere Lösungen, aber einfach zu handhaben
und tut genau das, was es soll.

Robin

20.06.2010 - 12:44 Uhr

Hallo Forum,

nachdem wir nun schon seit geraumer Zeit suchen und von keinem
Angebot so richtig überzeugt waren, hat hier von den Experten vielleicht jemand
den goldenen Tipp für uns.

Wir brauchen:

  • Skalierbarer VServer auf Basis Windows 2008/IIS7
    (Skalierbar = +RAM + HDD)
  • Uneingeschränkter Remote-Desktop Zugriff
  • ASP.NET vorhanden (oder selbst installierbar/upgradebar)
  • SQL Server 2008 vorhanden (oder selbst installierbar/upgradebar)
  • Automatisches Backup des VServers (ideal: täglich, ok: wöchentlich)
  • Server-Reboot über dedizierte Verwaltungskonsole (falls der Server "hängt")
  • Preislich nach Möglichkeit nicht über 50 Euro/Monat (also keine dedizierte
    Hardware für 299,-/Monat)

Kein Muss:

  • Exchange Server mit ungefähr 20 CAL (alternativ nehmen wir hmail)

Bei den Angeboten im Internet fehlte bisher immer das eine oder das andere,
oder es war nicht ganz klar, wie der RD-Zugriff erfolgen soll (mit irgendeiner
propritärer Verwaltungssoftware), oder inwieweit selbst Software installiert
werden durfte/konnte.

Danke,
Robin

17.05.2010 - 16:30 Uhr

Dies bedeutet, ich habe ich kleines Bild neben einer Textbox und
möchte beim Draufklicken einen Kalendar erscheinen lassen. Nur leider erscheint
beim Draufklicken nichts.
Woran könnte das liegen? Hat vielleicht einer eine Idee? Ich komme gerade echt
nicht weiter..
Danke schon mal für eure Hilfe.

Hm, bei meinem AjaxControlToolKit lässt sich diese Funktionalität ohne Probleme
abbilden:


<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>    
<asp:Image ID="Image1" runat="server" ImageUrl="images/img04.jpg" />
<ajaxControlToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</ajaxControlToolkit:ToolkitScriptManager>
<ajaxControlToolkit:CalendarExtender ID="CalendarExtender1" runat="server" 
TargetControlID="TextBox2" PopupButtonID="Image1">
</ajaxControlToolkit:CalendarExtender>

Welches Toolkit verwendest Du? Ist das Toolkit als Assembly registriert?
Mich verwundert das ASP:-Prefix bei Deinem Kalender, bei mir ist der AJAX-
Kalender nicht Bestandteil der Standard-Ajax Lib (VS2008).

Robin

17.05.2010 - 09:47 Uhr

danke erstmal für den Tipp. Aber das ist ja genau immer das
Problem. Solche Sachen funktionieren immer mal da und mal da, aber am liebsten
hätte ich eine ID, die immer funktioniert. X(

Dann musst Du spezifizieren, wie bei Dir "ein Rechner" definiert ist. Ich dachte
Du meinst die konkrete Hardware. Wenn Du mit irgendwelchen Software-IDs
des OS hantierst solltest Du beachten, dass diese sich im Falle einer
Neuinstallation des OS ändern. Spielt das keine Rolle, sind die Vorschläge von
herbivore und JAck30lena sicher die bessere Wahl. Wenn der Zugriff am
User und nicht an der Hardware hängt, ist der Lizenzschlüssel-Vorschlag von
herbivore eine der besten Lösungen, wenn nicht sogar die Beste.

Robin

17.05.2010 - 08:35 Uhr

In so einem Fall würde ich die Serialnummer des Rechners aus dem BIOS
verwenden. So kommst Du an die Info:


using System.Management;

class Program
    {
        static void Main(string[] args)
        {
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_BIOS");

            foreach (ManagementObject obj in searcher.Get())
                   Console.WriteLine(obj["SerialNumber"].ToString());
        }

    }

Das Ganze evtl. noch in einen try/catch-block, falls ein Rechner die entsprechende
BIOS-Property nicht liefert.

Robin

17.05.2010 - 00:48 Uhr

So etwas lässt sich relativ einfach mit dem System.IO.File namespace,
ein bischen Stringverarbeitung und ggf. regular expressions im Rahmen
einer Windows-Form App abfackeln. Aber wenn Du mit diesen Themen bisher
noch keinerlei Berührungspunkte hattest, ist es natürlich sehr schwierig.
Die Dateiendung spielt keine Rolle.

Da Du Excel erwähnt hast: Eine einfache VBA-App, die das File einliest
und in Exel darstellt geht nicht?

Robin

17.05.2010 - 00:36 Uhr

Bin auch deiner Meinung wegen dem DataContext mit LINQ,
denn ich möchte nicht jedesmal die Datenbank öffnen für die Query. Ich brauche
eine Mechanismus ala Cache welche alle 30min oder 60min, die Daten in den
Cache aktualisert. Es wird immer der DataContext verwendet.
Wie wird sowas realisiert, ist das viel Aufwand?

Sofern ich das Thema überblicke, gibt es zwei Möglichkeiten:

  1. Über LINQ. Dazu schau Dir bitte die Beispiele an, die ich Dir bei meiner Antwort
    verlinkt habe. Dort werden verschiedene LINQ-Möglichkeiten mit Query- und
    LAMDA-Syntax beispielhaft erklärt.

  2. Der Vorschlag von ErfinderDesRades mit dem typisierten Dataset. Dieser ist
    vermutlich noch eleganter und besser geeignet. Mehr Infos dazu habe ich hier
    gefunden: http://msdn.microsoft.com/de-de/library/bwy42y0e(v=VS.100).aspx
    Hier wird aber auch zuerst direkt auf die DB via SQL-Command zugegriffen.
    Persönlich halte ich das für besser, da Du dadurch die Möglichkeiten von SQL
    direkt im Zugriff hast.

Robin

16.05.2010 - 22:49 Uhr

Gibt es Verbesserungsvorschläge?

Ja. Ich würde entweder alles in ein SQL-Command packen oder alles
via LINQ bzw. über einen DataContext abhandeln. Zuerst einen direkten SQL-
Command absetzen und auf dieses resultset wieder eine Query zu starten halte
ich nicht für optimal.

Robin

16.05.2010 - 22:39 Uhr

Hallo, ich möchte mit LINQ auf eine Datenbank eine Abfrage
starten, diese soll alle vorkommenden strings aus einer Spalte liefern.
DB: **MyData **-> Table: **Posts **-> Spalte: Title

Wenn Du mit einer SQL-Connection direct eine query an die DB senden willst,
könnte das grundsätzliche Gerüst so aussehen:


class Program
    {
        static void Main(string[] args)
        {

            string connString = @"..................................";
            SqlConnection SQLConnection = new SqlConnection();

            try
            {
                SQLConnection.ConnectionString = connString;
                SQLConnection.Open();
            }
            catch (Exception Ex)
            {
                if (SQLConnection != null)
                    SQLConnection.Dispose();

                Console.WriteLine("Fehler...");
                return;
            }

            string SQLStatement = "SELECT TOP 10 * FROM SHOP_KUNDEN_STAMM";

            SqlDataAdapter SQLDataAdapter = new SqlDataAdapter(SQLStatement, SQLConnection);
            DataTable dtResult = new DataTable();

            SQLDataAdapter.Fill(dtResult);

            foreach (DataRow drRow in dtResult.Rows)
            {
                Console.WriteLine(drRow["KUNDEN_NACHNAME"].ToString().Trim() + ", " + drRow["KUNDEN_VORNAME"].ToString().Trim());
            }

            SQLDataAdapter.Dispose();
            SQLConnection.Close();
            SQLConnection.Dispose();
        }
    }

Ob man direkt auf die DB zugreifen soll, bin ich persönlich etwas hin- und
hergerissen. Ich kenne die Mächtigkeit von SQL und die Möglichkeiten, bin
aber noch zu wenig in der LINQ-Thematik drin, um beurteilen zu können, dass
damit alle bzw. zumindest die meisten Möglichkeiten von SQL abgebildet werden
können.

Für LINQ-SQL, LAMDA & Co. gibts hier ein gutes Tutorial:
http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx

Robin

16.05.2010 - 16:17 Uhr

Warum verwende ich dann nicht gleich einfach

  
public void GenericMethod(Object obj)  

? Was macht das für einen
Unterschied? Und wann setze ich was am besten ein?
Ich hoffe, dass das keine ultimativ blöde Frage ist, weil ich grade ziemlich aufm
Schlauch stehe.

Wenn Du nur mit Objekten arbeiten würdest, müsstest Du ziemlich viel
mit Casting und Boxing arbeiten, zudem prüft der Compiler bei den generischen
Typen schon beim Compilieren auf Typsicherheit. Ich meine auch, dass das
Laufzeitverhalten bei der Objekt-Lösung stark nachteilig ist.

Wann immer möglich, setze Generics anstatt einfache Objekteverweise
mit Boxing/Casting ein.

Hier wird es auch noch mal ganz gut anhand von Beispielen erklärt:
http://www.dotnetjohn.com/articles.aspx?articleid=250

Robin

16.05.2010 - 13:41 Uhr

Hallo,
für so etwas verwende ich immer gerne XDocument:


static void Main(string[] args)
        {
            XDocument xdoc;
            xdoc = XDocument.Load(@"D:\test.xml");

            IEnumerable<XElement> xmlItems = xdoc.Root.Elements(); 

            foreach (XElement xmlItem in xmlItems)
            {
                Console.WriteLine(xmlItem.Elements().ElementAt(0).Attribute("name").Value.ToString()); // IP 
                Console.WriteLine(xmlItem.Elements().ElementAt(1).Attribute("name").Value.ToString()); // Server 
                Console.WriteLine(xmlItem.Elements().ElementAt(0).Value.ToString()); // IP Inhalt
                Console.WriteLine(xmlItem.Elements().ElementAt(1).Value.ToString()); // Server Inhalt
            }
        }

Finde ich persönlich klarer und strukturierter als das ganze Node- und Child-
Gehüpfe.

Robin

16.05.2010 - 10:13 Uhr

Hier hat einer eine Extension geschrieben, die zur Laufzeit queries
anhand einer Parameter-Repository erstellt. Scheint genau das zu sein,
was Du suchst:

http://tomasp.net/articles/dynamic-linq-queries.aspx

Hier ist auch noch eine Lib, die das leistet:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Bitte beachte auch die Hinweise zum Thema Security/SQL-Injection, dass ist
bei solchen dynamischen Geschichten nicht ohne.

Robin

16.05.2010 - 09:34 Uhr

danke für deine Arbeit und das Veröffentlichen. Darf man deinen
Rechner frei benutzen, oder gibt es eine spezielle Lizenz?

Hallo Realnub,

herbivore hat ja schon auf die Lizenzbedingungen hingewiesen, d.h. ja,
Du darfst die Sourcen frei verwenden und ggf. auch ergänzen. Wenn Du noch
irgendein Feature vermisst, gib' mir Bescheid, sofern es meine Zeit zulässt
bau ich das dann noch ein.

Robin

15.05.2010 - 22:46 Uhr

Hat jemand eine idee was ich da machen könnte oder kann mir
bitte jemand einfach die dll schicken??

Bei mir lief der Compiler fehlerfrei durch, schau mal ob Du mit der DLL
was anfangen kannst (VS2008, x86, download Version 1.31),
ich selbst nutze das Produkt nicht.

Robin

15.05.2010 - 18:46 Uhr

das wird Probleme geben, weil beim umregistrieren, der
alte eventhandler nicht deregistriert wird. (Das ist zb in VB nett gelöst mit
WithEvents-Feldern und Handles-Klausel. Die generieren im Hintergrund eine
Property, deren Setter die Event-Registrierung sauber handelt)

Stimmt, ich hätte im entsprechenden Event bei "Linse" das Event noch
deregistrieren müssen. Das habe ich übesehen.

Die fachliche Problemstellung ist mir noch immer nicht ganz klar, ich meine
es geht so oder so etwas einfacher.

Robin

15.05.2010 - 18:33 Uhr
  1. Oft nimmst du werte aus der XML ohne Validierung, das kann sehr gefärlich
    werden.
    4a. Du machst oft int.Parse, dh du gehst immer davon aus das es zu parsen ist
    4b. Im "Holiday" splittest du Formula an dem punkt und verwendest Item 0 und 1
    direkt, keine Überprüfungen ob vorhanden.

  2. Du überprüft nicht ob die übergebenen Xml Dateien überhaupt existieren vor
    dem einlesen

Die Validierung des XML geschieht beim Einlesen. Wenn etwas nicht stimmt
wird eine Exception geworfen. Natürlich könnte man noch schöne
Fensterchen mit Hinweisen bauen, wer aber als Dev mit XML-Sourcen und fremden
APIs arbeitet, sollte wissen was er tut. Wie die files aussehen sollen ist hinreichend
dokumentiert und mit Beispieldateien ergänzt. Wer damit nicht klarkommt,
dem helfen m.E. auch zusätzliche Fehlermeldungen nicht weiter.

Würde ich das Modul kommerziell für Enduser zum Kauf anbieten, wären sicherlich
weitaus mehr Sicherheitsabfragen, vermutlich auch diverse Wizards und eine
ausführliche Doku dabei. Das Modul hier tut robust was es tun soll und wer
mehr braucht, darf auf dieser Basis gerne aktiv werden, es ist hier ja ein
Developer-Forum. Das ist nicht böse gemeint von mir, ich habe schlicht nicht
die Zeit dafür, jeden Wunsch zu erfüllen.

  1. Sicher das Convert.ToDateTime so immer korrekt arbeitet? Auch in
    jeder Culture? Bin nicht sicher das eine Englische Culture die Deutsche Syntax
    validiert, müsste man schauen wie man das löst.

Wer auf Nummer sicher gehen will, soll alle date-Informationen im ODBC-
Format eintragen, das klappt immer, auch z.B. bei US-Formaten.
D.h. "YYYY-MM-TT". Auch hier wieder: Wer ein entsprechendes Modul zur
Kalenderberechnung in seine Lib integrieren und über diverse Cultures streuen
will, sollte grundsätzlich Erfahrungen mit Datumsformaten und deren richtige
Verwendung mitbringen.

Konnte leider nicht lesen was Du zu meinem Programmierstil geschrieben hast,
möglich das über 10 Jahre Assembler bei mir einen speziellen Einschlag mit
sich gebracht haben. Lesbarkeit und Struktur sind für mich sehr wichtig,
deshalb auch die explizite Hervorhebung von Klassen und Methoden, auch wenn
die "Striche" in den Klassen- und Methoden-Heads für manche seltsam aussehen
mögen.

Robin

15.05.2010 - 14:19 Uhr

Klasse Arbeit, gefällt mir 🙂

Danke 😁

Die SAP-Schnittstelle wird dann kostenpflichtig. 😉

Robin

15.05.2010 - 14:17 Uhr

Eine Lösung mit Events wäre bspsw. die:


    //-------------------------------------------------------------------------
    class Program
    //-------------------------------------------------------------------------
    {
        //-------------------------------------------------------------------------
        static void Main(string[] args)
        //-------------------------------------------------------------------------
        {
            Linse linse = new Linse();
            linse.interaktionsverhalten = new ObjektInteraktionsverhalten(linse);
            linse.interaktionsverhalten.Verhalten();    //Ausgabe: ObjektInteraktionsverhalten

            linse.interaktionsverhalten.linksloslassen();
            linse.interaktionsverhalten.Verhalten();    //Ausgabe: PortalInteraktionsverhalten

            Console.ReadLine();
        }
    }

    //-------------------------------------------------------------------------
    class Linse
    //-------------------------------------------------------------------------
    {
        private Interaktionsverhalten iv;

        //---------------------------------------------------------------------
        public Linse()
        //---------------------------------------------------------------------
        {
        }

        //---------------------------------------------------------------------
        public Interaktionsverhalten interaktionsverhalten
        //---------------------------------------------------------------------
        {
            get { return this.iv; }
            set
            {
                this.iv = value;
                iv.LinksloslassenEventhandler += 
                    new EventHandler(Linse_LinksloslassenEventhandler);
            }
        }

        //---------------------------------------------------------------------
        void Linse_LinksloslassenEventhandler(object sender, EventArgs e)
        //---------------------------------------------------------------------
        {
            this.interaktionsverhalten = new PortalInteraktionsverhalten(this);
        }
    }

    //-------------------------------------------------------------------------
    class Interaktionsverhalten
    //-------------------------------------------------------------------------
    {
        protected Linse linse;
        public event EventHandler LinksloslassenEventhandler;

        //---------------------------------------------------------------------
        public Interaktionsverhalten(Linse l)
        //---------------------------------------------------------------------
        {
            this.linse = l;
        }

        //---------------------------------------------------------------------
        public void linksloslassen()
        //---------------------------------------------------------------------
        {
            OnLinksloslassen(EventArgs.Empty);
        }

        //---------------------------------------------------------------------
        protected virtual void OnLinksloslassen(EventArgs e)
        //---------------------------------------------------------------------
        {
            if (this.LinksloslassenEventhandler != null)
                this.LinksloslassenEventhandler(this, e);
        }

        //---------------------------------------------------------------------
        public virtual void Verhalten()
        //---------------------------------------------------------------------
        {
        }
    }

    //-------------------------------------------------------------------------
    class ObjektInteraktionsverhalten : Interaktionsverhalten
    //-------------------------------------------------------------------------
    {
        //---------------------------------------------------------------------
        public ObjektInteraktionsverhalten(Linse l) : base(l)
        //---------------------------------------------------------------------
        {
        }

        //---------------------------------------------------------------------
        public override void Verhalten()
        //---------------------------------------------------------------------
        {
            Console.WriteLine("ObjektInteraktionsverhalten");
        }
    }

    //-------------------------------------------------------------------------
    class PortalInteraktionsverhalten : Interaktionsverhalten
    //-------------------------------------------------------------------------
    {
        //---------------------------------------------------------------------
        public PortalInteraktionsverhalten(Linse l): base(l)
        //---------------------------------------------------------------------
        {
        }

        //---------------------------------------------------------------------
        public override void Verhalten()
        //---------------------------------------------------------------------
        {
            Console.WriteLine("PortalInteraktionsverhalten");
        }
    }

Allerdings werde ich das Gefühl nicht los, dass hier von hinten durch die Brust
ins Auge ein evtl. einfache Problemstellung unnötig verkompliziert wird.

Was ist denn die fachliche Aufgabenstellung?

Robin

15.05.2010 - 07:07 Uhr

Außerdem sollten die Konfigurationsdateien die Möglichkeit
bieten, einen Gültigkeitszeitraum anzugeben, der dann von der Bibliothek auch
berücksichtigt wird. Immerhin kann man ja auf den Gedanken kommen, die Zahl
der Arbeitstag über mehrere Jahre (z.B. zwischen 1985 und 2000) zu berechnen
und innerhalb dieser Zeit hat sich ja die Lage des "Tags der Deutschen Einheit"
geändert und der "Buß- und Bettag" wurde in den meisten Bundesländern
abgeschafft.

Hallo herbivore,

lauter gute Ideen und anbei ist die Umsetzung 😃

Grundlage des neuen Konstrukts ist eine universelle Feiertagsmatrix, die sich aus
zwei XML-Files füllt. Die erste XML-Datei beschreibt die möglichen geographischen
Regionen (bei uns z.B. Bundesländer) mit den Country und Language als
globale Keys/Matchcodes. Die Struktur sieht wie folgt aus (Auszug):


<?xml version="1.0" encoding="utf-8"?>
<States.Config>
  <Country>
    <CountryCode>DE</CountryCode>
    <Language>DE</Language>
    <States>
      <State>
        <StateID>0</StateID>
        <StateName>Catalog</StateName>
      </State>
      <State>
        <StateID>1</StateID>
        <StateName>Deutschland Gesamt</StateName>
      </State>
      <State>
        <StateID>2</StateID>
        <StateName>Bayern</StateName>
      </State>
    </States>
  </Country>
</States.Config>

Mit dem Ländercode (hier: "DE") und dem Sprachcode (hier: "DE") legt man
den Gültigkeitsbereich für eine (Bundes-)Staatenliste fest. So sind auch
innerhalb eines Landes verschiedene Sprachen abbildbar und innerhalb
eines Landes anhand der Sprache sogar unterschiedliche Ausprägungen.

Das XML-File für die Feiertage hat einen ähnlichen Aufbau (Auszug):
CountryCode und Language müssen bei beiden Files matchen!


?xml version="1.0" encoding="utf-8"?>
<Holidays.Config>
  <Country>
    <CountryCode>DE</CountryCode>
    <Language>DE</Language>
    <Catalog>
      <Holiday>
        <HolidayID>10</HolidayID>
        <HolidayName>Neujahr</HolidayName>
        <HolidayFormula>F:1.1</HolidayFormula>
        <HolidayDuration>1</HolidayDuration>
        <HolidayValidFrom>01.01.1900</HolidayValidFrom>
        <HolidayValidTo>31.12.2099</HolidayValidTo>
        <StateIDList>0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17</StateIDList>
      </Holiday>
      <Holiday>
        <HolidayID>20</HolidayID>
        <HolidayName>HeiligeDreiKönige</HolidayName>
        <HolidayFormula>F:6.1</HolidayFormula>
        <HolidayDuration>1</HolidayDuration>
        <HolidayValidFrom>01.01.1900</HolidayValidFrom>
        <HolidayValidTo>31.12.2099</HolidayValidTo>
        <StateIDList>0,2,3,15</StateIDList>
      </Holiday>
     </Catalog>
  </Country>
</Holidays.Config>

Die StateIDList gibt an, für welche (Bundes-)Länder der jeweilige Feiertag
gültig ist. Dabei ist "0" das Minimum, die 0 steht für den Catalog, d.h. in
diesem befinden sich alle Feiertage. Mit Duration lassen sich sogar "Feiertage"
realisieren, die mehrtägig sind.

Mit dem integrierten Formel-Parser kann man eigene Formeln für die
Feiertagsberechnung mitgeben und neue Feiertage berechnen lassen.

Der Aufbau einer Feiertagsformel sieht wie folgt aus: "Typ:Modifizierer"

Beispiele:
F:1.1 // Fester Feiertag am 1.1 (Neujahr)
E:0 // Ostersonntag
E:1 // Ostermontag
E:-2 // Karfreitag
RP:0 // Buß- und Bettag
MD:0 // Muttertag
AD:0 // Vierter Advent
AD:-7 // Dritter Advent

Ausser dem festen Feiertag "F", dem als Modifizierer immer Tag und Monat mit
Punkt getrennt mitgegeben werden, haben alle anderen Feiertagstypen
("floating") einen Offset, der ausgehend von einem anderen Feiertag berechnet
werden kann (meist ausgehend von Ostersonntag).

Klingt evtl. kompliziert, die Handhabung ist aber recht einfach:

Die XML-Files werden mit der HolidayMatrix-Klasse eingelesen:


HolidayMatrix holidayMatrix = new HolidayMatrix("DE", "DE", @"D:\states.config.xml", @"D:\holidays.config.xml");
holidayMatrix.CurrentStateID = 2;  // Bayern als Bundesland setzen

Wichtig ist, die StateID-Property richtig zu setzen (ID des Bundeslandes aus
der XML-Datei), ansonsten zieht default ID=0, dass ist der Catalog, d.h. alle in der
XML-Datei für das Land definierten Feiertage inkl. Muttertag & Co.!
In diesem Fall steht die 2 für Bayern (0=Catalog, 1=BaWü, 2 = Bayern usw.).

Dann wird die Matrix auf den eigentlichen Rechner gemappt:


CalendarCalculator calendar = new CalendarCalculator( holidayMatrix );

Und schon kann man rechnen:


 int days = calendar.GetWorkingDays(new DateTime(2010, 3, 31), new DateTime( 2010,5, 3));

Die üblichen Properties stehen auch wieder zur Verfügung:


HolidayMatrix.Holidays  // Liefert Liste aller Feiertage des gewählten Landes, Untergruppe Sprache und Untergruppe Bundesland/State

CalendarCalculator.IsHoliday( DateTime )
CalendarCalculator.GetHolidayName( DateTime )

CalendarCalculator.SaturdayIsWorkingDay = false;  // Samstag Arbeitstag ja/nein
CalendarCalculator.SundayIsWorkingDay = false;    // Sonntag Arbeitstag ja/nein

usw. usf. Alles andere steht in der Source, ist dokumentiert.
Beigefügt sind ausserdem noch die XML-Dateien für Deutschland komplett
(Alle Bundesländer+Alle Feiertage).

Robin

13.05.2010 - 20:33 Uhr

Jetzt also meine Frage: was kann man machen? Lohnt es sich
irgendwie einen eigenen Datentyp aus Integers zusammenzubasteln? Z.B. einen
der sich alle Nachkommastellen einzeln merkt? Oder gibt es schon so eine Lösung?

Nimm decimal.

decimal (C#-Referenz)

Robin

13.05.2010 - 19:55 Uhr

Sonntagsarbeit geht nicht?

Doch, steht doch in der Erklärung bei dem Beispiel für Samstag:
Gilt sinngemäß für Sonntag, also

meinKalender.SonntagIstArbeitstag = ...

Kann man sich die vorbelegten Feiertage
anzeigen lassen?

Liegen als Enum List-Elemente vor, können somit über eine einfache Property
nach aussen geführt werden. Ist nun drin:

public List<Feiertage> GetFeiertagList

Wenn schon deutsch dann korrigiere mal 😁
"Sylvester" -> "Silvester"
"MariaHimmelfahrt" -> "MariäHimmelfahrt"

In der Anlage mit den besprochenen Korrekturen. 😁

Robin

EDIT: Weiter unten gibt es eine aktuellere Version.

13.05.2010 - 19:43 Uhr

Hallo Zusammen,

danke für das Feedback. Normalerweise kommentiere ich alles in
Englisch und verwende auch nur englische Variablen/Begriffe (s. auch das
Game, dass ich hier veröffentlicht habe), da ich manches auch in US-Foren
poste.

Allerdings ist dieser Feiertagskalender sehr stark an den deutschen
Sprachraum gekoppelt, so dass ich mich genaus aus diesem Grund hier
für die deutschen Begriffe entschieden habe. Vor allem, da es bei vielen
Sonder- und Feiertagen m.W. keinen entsprechenden englischen Begriff gibt,
bzw. dieser wiederum im Deutschen unbekannt ist.

Ich möche in diesem Zusammenhang noch auf eine Besonderheit der
Arbeitstageberechnung in diesem Modul hinweisen: Sie ist m.M. im
Vergleich zu anderen Lösungen die ich bisher gesehen habe sehr schnell und
eignet sich deshalb auch für umfangreiche Bearbeitungen, z.B. in Verbindungen
mit Datenbanken.

Robin

13.05.2010 - 17:03 Uhr

Hi Forengemeinde,

wer einen Kalenderrechner für die Berechnung von tatsächlichen
Arbeitstagen benötigt, soll sich die Klasse in der Anlage ansehen.

Berücksichtigt werden Wochenenden und Feiertage (alle Bundesländer).
Zudem lassen sich betriebliche "Feiertage" wie z.B. Rosenmontag flexibel
hinzufügen und entfernen.

So funktionierts:

KalenderRechner meinKalender = new KalenderRechner( KalenderRechner.BundesLänder.Bayern );

Wird das Bundesland-Enum im Konstruktor weggelassen, ziehen automatisch
die bundeseinheitlichen Feiertage.

Möchte man "Feiertage" hinzufügen, geht das z.B. einfach über:

meinKalender.AddFeiertag(KalenderRechner.Feiertage.AugsburgerFriedensfest);

Und wieder weg:

meinKalender.RemoveFeiertag(KalenderRechner.Feiertage.AugsburgerFriedensfest);

Die für das jeweilige Bundesland einheitlichen Feiertage sind immer
richtig vorbelegt! Gibt es Feiertage die innerhlb des Bundeslands nicht
einheitlich sind, müssen diese mit der Add-Methode hinzugefügt werden.
Das gleiche gilt für evtl. betriebliche Feiertage wir Rosenmontag usw.

Wenn Samstage als Arbeitstage zählen:

meinKalender.SamstagIstArbeitstag = true;

Für Sonntage sinngemäß.

Beispiel-Berechnung der tatsächlichen Arbeitstage zwischen zwei Datumswerten:

uint tage = meinKalender.GetArbeitstage(new DateTime(2009, 12, 6), new DateTime( 2010, 11, 10));

Datum 1 = Beginndatum
Datum 2 = Endedatum

Zurückgegeben werden nur die tatsächlichen Arbeitstage unter Berücksichtigung
von Feiertagen und Wochenenden.

Weitere Member und Methoden:

public bool IsFeiertag(DateTime dtDate)
public Feiertage GetFeiertagName(DateTime dtDate)
public DateTime GetFeiertagDatum(Feiertage feiertag, int iYear)
public DateTime GetOstersonntag(int iYear)

Liste (Enum) der bisher implementierten, möglichen Feiertage:


            Neujahr,
            HeiligeDreiKönige,
            Valentinstag,
            RosenMontag,
            FaschingsDienstag,
            Aschermittwoch,
            GrünDonnerstag,
            Karfreitag,
            OsterSonntag,
            OsterMontag,
            Muttertag,
            TagDerArbeit,
            ChristiHimmelfahrt,
            PfingstMontag,
            PfingstSonntag,
            Fronleichnam,
            AugsburgerFriedensfest,
            MariaHimmelfahrt,
            TagDerDeutschenEinheit,
            Reformationstag,
            Allerheiligen,
            BußUndBettag,
            Nikolaus,
            ErsterAdvent,
            ZweiterAdvent,
            DritterAdvent,
            VierterAdvent,
            Heiligabend,
            ErsterWeihnachtsfeiertag,
            ZweiterWeihnachtsfeiertag,
            Sylvester,
            KeinFeiertag

Für konstruktives Feedback bin ich wie immer dankbar.

Robin

EDIT: Weiter unten gibt es eine aktuellere Version.

11.05.2010 - 00:28 Uhr

Hallo Forengemeinde,

folgendes Szenario: Eine Website verwendet Index Services für die Volltextsuche.
Die Volltextsuche wird mit dem üblichen Query durchgeführt:

cmdSearch.CommandText = "SELECT doctitle, filename, vpath, rank, characterization, size FROM SCOPE('DEEP TRAVERSAL OF \"\\\"') WHERE " +
                                        "CONTAINS(Contents, '\"" + txtSearch + "\"') AND " +
                                        "NOT CONTAINS(vpath, '\"_vti_\" OR \".config\"') AND " +
                                        "NOT CONTAINS(filename, '\".cs\" OR \".css\" OR \".txt\" OR \".config\"') AND " +
                                        "CONTAINS(filename, '\".aspx\" OR \".htm\" OR \".html\"') " +
                                        "ORDER BY RANK DESC";

Funktioniert alles bestens.

Das Eingabefeld für die Volltextsuche verwendet zusätzlich ein AutoComplete
AJAX-Control, um Vorschläge für die Volltextsuche zu generieren.
Momentan werden diese Vorschläge noch manuell über ein List-Element
vorgegeben.

Frage: Wie bekomme ich eine Wortliste aus den Index-Services, um diese
für das AJAX-Control verwenden zu können? Habe mir schon einen Wolf
gesucht, aber nichts gefunden. Klar könnte ich den Content selbst spidern,
in eine SQL-DB schreiben und quasi die Index Services "nachprogrammieren".

Es muss doch eine Möglichkeit geben, den Index-Services die indizierte
Wortliste zu entlocken, oder?

Ach ja: Plattform VS2008, .NET 3.51, IIS 6.0 und ASP AjaxControlToolKit

Danke,
Robin

11.05.2010 - 00:18 Uhr

Hm, die meisten controls bieten die CssClass-Property an, über dass
du das Stylesheet setzen kannst - sofern ich dich richtig verstanden habe.

Robin

11.05.2010 - 00:14 Uhr

Hier ist ein m. E. klasse Tutorial:

http://www.15seconds.com/issue/010430.htm

Robin

06.05.2010 - 16:25 Uhr

Hi Forengemeinde,

folgende Situation: Webauftritt einer Firma komplett in ASP.NET/C# 3.51, IIS6
Volltextsuche über Content via OleDB auf entsprechenden Indexserver-Catalog
vorhanden.

Nun werden verschiedene (Content-)Elemente zur Laufzeit erzeugt, die sich auf
verschiedenen Seiten wiederholen. Z.B. über einen Repeater.

Leider werden diese Inhalte nicht vom Index Server erfasst und somit führt
auch die Trefferliste der Volltextsuche diese Seiten logischerweise nicht auf.
Mir ist schon klar, dass normalerweise dynamischer Content auch nicht
indiziert werden sollte, aber der Output aus ein paar statischen Klassen finde
ich schlicht eleganter als z.B. mit alten, serverseitigen include-techniken
und statischen HTML-Seiten zu arbeiten.

Gibt es dafür eine Lösung? In Google und Forum konnte ich dazu nichts finden.

Danke,
Robin

05.05.2010 - 08:28 Uhr

Hier gibts eine Klasse, die die web.config zur Laufzeit ändert:
http://bytes.com/topic/net/answers/674339-runtime-editing-web-config

Google-Suche nach "modify web.config runtime" liefert noch mehrere Tipps.

Ich würde zuerst das Debug-Setting auslesen und dann in Abhängigkeit
des hostnames das Setting entsprechend setzen.

Hier gibts noch eine coole Lösung, die mit verschiedenen web.configs hantiert
und diese in Abhängigkeit des Builds (debug/release) per script setzt:
http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx

Gefällt mir persönlich eigentlich noch besser.

Robin

04.05.2010 - 13:21 Uhr

Warum die Zeile "this=bc" so nicht geht ist mir klar. Ich
würde ja dam Objekt den Boden unter den Füssen wegziehen. Was ich aber
möchte ist, alle Properties des übergebenen Objekts im Konstruktor zu
übernehmen, ohne dass ich einzeln _"this.baseProperty=bc.baseProperty;
this.anotherproperty=bc.anotherproperty... etc. "_angeben muß.

Wie erreiche ich das?

Schau mal hier:
http://johnsadventures.com/archives/2006/07/an_intelligent_copy_constructor_in_c_usi/

Robin

04.05.2010 - 01:17 Uhr

Hallo zusammen,

derzeit werfe ich einen vorsichtigen Blick in Richtung Spieleprogrammierung.
Nichts Großes, ich beschränke mich vorerst mal auf das zweidimensionale mit
GDI+ (Performance spielt eher eine untergeordnete Rolle - ob je ein fertiges
Produkt entsteht, ist sowieso fraglich 😁 ).

Schau Dir mal das 2D Tutorial von Riemer Grootjans an:

http://www.riemers.net/

Damit habe ich es gelernt und einen Shooter daraus gebaut. 😁
Ist zwar für XNA/DirectX aber die mathematischen Grundlagen sind wohl die
gleichen. Wenn Du mit dem Gedanken spielst, solltest Du evtl. überlegen,
gleich mit dem XNA Framework zu arbeiten. Das macht das Leben deutlich
einfacher.

Robin

04.05.2010 - 01:03 Uhr

Entweder ich habe etwas missverstanden oder ich mache
etwas falsch.

Ein kleiner Logikfehler noch: Das Delegate wird aus dem Thread heraus
aufgerufen, also zu einem Zeitpunkt, an dem der Thread noch lebt!

Ändere die Main-Methode wie folgt:

Form1:


private void test()
{
  ....
  testPanel.Visible = true;
  test1 = new TestClass();
  test1.Event_FromThread += (test1.EigenesEvent)Event_FromThread;
  test1.startMethode()
  Thread.Sleep(1); // Warten bis thread gestartet ist
  while (test1.Thread.IsAlive) Thread.Sleep(100);      // Thread prüfen auf "Leben"
  Console.WriteLine("IsAlive=" + test1.Thread.IsAlive); // Jetzt ist er tot....
}

Du musst natürlich den Thread selbst über ein public Attribut "Thread" in TestClass
sichtbar machen.

Robin

03.05.2010 - 23:20 Uhr

Dann füge mal ein using System.Collections; an den Anfang der Codedatei ein.

Danke. Das hat das Problem zwar nicht gelöst, mich aber auf die richtige
Spur gebracht: Der Knackpunkt war, dass ich nicht von IEnumerable und
IEnumerator direkt abgeleitet hatte, sondern mich von der "Original"-
Dictionary Signatur von IEnumerable<KeyValuePair<TKey, TValue>> und
IEnumerator<KeyValuePair<TKey, TValue>> habe in die Irre führen lassen.
Diese stehen nicht in der System.Collections, sondern in der
System.Collections.Generic, deshalb fiel mir das fehlende using nicht auf!

Hier die funktionierende Lösung:

    
    //---------------------------------------------------------------
    public class MeinDictionary<TKey, TValue> : IEnumerable
    //---------------------------------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;

        //---------------------------------------------------------------
        public MeinDictionary()
        //---------------------------------------------------------------
        {
            this._keys = new List<TKey>();
            this._values = new List<TValue>();
        }

        //---------------------------------------------------------------
        public void Add( TKey key, TValue value )
        //---------------------------------------------------------------
        {
            this._keys.Add(key);
            this._values.Add(value);
        }

        //---------------------------------------------------------------
        IEnumerator IEnumerable.GetEnumerator()
        //---------------------------------------------------------------
        {
            return this.GetEnumerator();
        }

        //---------------------------------------------------------------
        public MeinDictionaryEnum<TKey, TValue> GetEnumerator()
        //---------------------------------------------------------------
        {
            return new MeinDictionaryEnum<TKey, TValue>(this._keys, this._values);
        }
    }

    //---------------------------------------------------------------
    public class MeinDictionaryEnum<TKey, TValue> : IEnumerator
    //---------------------------------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;
        int _position;

        //---------------------------------------------------------------
        public MeinDictionaryEnum(List<TKey> keys, List<TValue> values)
        //---------------------------------------------------------------
        {
            this._keys = keys;
            this._values = values;
            this._position = -1;
        }

        //---------------------------------------------------------------
        public bool MoveNext()
        //---------------------------------------------------------------
        {
            this._position++;
            return (this._position < this._keys.Count);
        }

        //---------------------------------------------------------------
        public void Reset()
        //---------------------------------------------------------------
        {
            this._position = -1;
        }

        //---------------------------------------------------------------
        public object Current
        //---------------------------------------------------------------
        {
            get
            {
                try
                {
                    return new KeyValuePair<TKey, TValue>(this._keys[this._position], this._values[this._position]);
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }
    }

Jetzt kann man auch schön mit foreach / KeyValuePair durch das Dictionary
marschieren. Der Rest ist jetzt einfach. Genau das wollte ich.

Nochmals danke für Deine Hilfe!

@herbivore: In dieser Compilerfehlerliste habe ich in diesem Zusammenhang
auch schon fleißig gewühlt. Nur leider war auch die Fehlermeldung irreführend,
da ich versuchte, die Interfaces fälschlicherweise mit den KeyValuesPair-Generics
zu implementieren. Der Compiler wies mich zwar hin, dass die Implementierung
nicht richtig war, aber hat verschwiegen, dass die Implementierung mit dieser
Ausprägung der Interfaces nicht funktionieren konnte. Trotzdem auch Dir danke
für den Hinweis.

Robin

03.05.2010 - 21:34 Uhr

Genau an dieser Stelle beisst sich die Katze wieder in den Schwanz.

Ergänze ich


        //---------------------------------------------------------------
        IEnumerator IEnumerable.GetEnumerator()
        //---------------------------------------------------------------
        {
            return this.GetEnumerator();
        }

bemängelt er den fehlenden Generic-Parameter:

Die Verwendung von Typ "System.Collections.Generic.IEnumerator<T>"
(generisch) macht das 1-Typargument erforderlich.

Füge ich den dazu, bemängelt er das Fehlen einer GetEnumerator-Methode ohne
Generics. X( Das hatte ich schon versucht.

Robin