Laden...
G
GarlandGreene myCSharp.de - Member
Softwareentwickler .NET / ABAP Emmerich, NRW Dabei seit 18.08.2006 497 Beiträge
Benutzerbeschreibung

Forenbeiträge von GarlandGreene Ingesamt 497 Beiträge

11.02.2008 - 14:25 Uhr

http://forum.hibernate.org/viewtopic.php?t=953234&highlight=timestamp+xml

anscheinend muss das Timestamp- oder Version-Attribut direkt unterhalb des ID-Attributs auf Klassenebene eingebaut werden, also noch vor dem ersten definierten <property>.

10.02.2008 - 21:22 Uhr

http://de3.php.net/manual/de/function.hash.php

PHP hash() gibt standardmässig lowercase hex aus. Du könntest den raw_output-Schalter benutzen und das Ergebnis dann base64 encoden, dann sollte dasselbe rauskommen wie bei deinem c#-Beispiel.

08.02.2008 - 09:41 Uhr

Danke für deine prompte Antwort.
Ich habe aber keinerlei Erfahrung mit PostgreSQL, kann man es genauso einfach in ASP.NET integrieren wie Mysql?

Treffen deine genannten Vorteile nicht auch auf Mysql zu (bis auf die programmierbarkeit)?

du brauchst ja nur den OleDB-Provider. Alles andere läuft wie mit MySQL auch. Postgres ist einfach die erwachsenere Datenbank. Bei wachsenden Projekten ist es nie verkehrt, auf hohe Erweiterbarkeit und Ausfallsicherheit zu achten. Es gibt im Prinzip nichts, was Postgres im Vergleich zu MySQL nicht kann.

Edit: großer Vorteil von postgres: Online Backup. MySQL kann das nur mit diversen Einschränkungen (entweder Storageengine-spezifisch wie z. B. mit dem kostenpflichtigen InnoDB hot backup oder mit read locks bei mysqldump, was einer Downtime gleichkommt). Bei Postgres kannst du die komplette Datenbank im laufenden Betrieb ohne Einschränkungen sichern, dazu sicherst du die Write Ahead Logs, nach einem Crash kannst du mit dem (inkonsistenten) Dateibackup und den WAL-Dateien eine konsistente Datenbank wiederherstellen.

08.02.2008 - 09:33 Uhr

mir fallen auf Anhieb zwei Varianten ein.

Variante 1: du merkst dir in myClass, ob diese Klasse schon aufgerufen wurde. Falls ja, führst du in setOutputs einfach nichts mehr aus. Du müsstest vor dem setOutputs-Aufruf in der obersten myClass-Instanz aber einen "Reset" dieses Statusfelds durchführen, damit alle myClass-Instanzen wieder zurückgesetzt werden und beim ersten setOutputs-Aufruf auch loslegen.

Variante 2: du hälst eine statische List<myClass> vor, die vor dem ersten setOutputs-Aufruf geleert wird und alle Elemente enthält, die bereits aufgerufen worden sind. In setOutputs selbst prüfst du mit List<myClass>.Contains(myClass class), ob das aufgerufene Objekt schon in der Liste ist. Falls nein, iteriert das Objekt durch seine Referenzen, ansonsten macht es nichts.

Ich weiß jetzt nicht, mit welcher Methode List<T>.Contains() arbeitet. Es könnte sein, daß du Equals() überschreiben musst um sicherzustellen, dass nach Objektreferenz verglichen wird.

Variante 1 hat den Vorteil daß du die statische Liste nicht benötigst. Je nachdem, wie oft und an wie vielen Stellen des Programms dieser Aufruf stattfindet, könnte die Liste sehr hinderlich sein (bei Multithreading wäre sie tödlich, da sich zwei Aufrufe in die Quere kommen könnten).

Edit 2: es gäbe noch eine Variante mit einer Liste: du könntest eine neue List<myClass> erzeugen, beim Aufruf von setOutputs jeweils die Referenz der Liste übergeben und innerhalb setOutputs in dieser Liste auf Contains() prüfen. Dann hättest du eine Liste für einen Aufruf, threadsicher und es muss nichts weiter vor dem Aufruf beachtet werden. Könnte man auch so aufbauen, daß setOutputs eine neue Liste generiert und mit der loslegt, wenn als List-Parameter NULL übergeben wird. Dann musst du die Liste nichtmal vor dem Aufruf erzeugen.

08.02.2008 - 09:12 Uhr

MySQL ist beliebt, weil es relativ simpel zu administrieren ist. Ab einer gewissen Datenbankgröße und bei steigender Anzahl von komplexeren Abfragen scheinen andere Datenbanken aber schneller zu sein. Als freie Datenbank bietet sich Postgres an. Sehr schnell, stabil, clustering-fähig, programmierbar, transaktionssicher.

07.02.2008 - 20:12 Uhr

laut Google gibts das, aber unter Umständen nur bei Hibernate (der schon deutlich länger existierenden Java-Variante, auf der NHibernate aufbaut). Kann sein, daß das bei NH (noch) nicht unterstützt wird. In Hibernate hat die Session die Methode Persist(), die auf dieses Attribut zurückgreift.

07.02.2008 - 11:12 Uhr

ganz simpel: Save() speichert nur das Objekt, das du ihm übergibst. Im AudioCD-Objekt sind AudioTrack-Objekte, die noch nicht gespeichert sind. Die einfach mit Save() auch speichern, fertig.

€: alternativ kannst du auch befehlen, dass er das Save auch auf referenzierte Objekte erweitern soll. Dazu das Mapping im Set, Bag oder many-to-one um cascade="save-update,persist" erweitern.

07.02.2008 - 08:55 Uhr

als Many-To-One. In der Klasse deklarierst du anstelle einer Int32-Eigenschaft eine AudioCD-Eigenschaft (get und set hab ich jetzt nicht implementiert, die müssen natürlich mit rein).


        private AudioCD m_CD;
        
        public virtual AudioCD CD
        { get; set; }

Das Mapping läuft dann so:


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="MeinNamensraum.AudioTrack, MeinNamensraum" table="audiotracks">
        <id name="AudioTrackId" column="autoId" type="int">
            <generator class="identity" />
        </id>
        <property name="TrackNr" column="tracknr" type="int"/>
        <property name="Artist" column="artist" type="string" />
        <property name="Title" column="title" type="String"/>
        <property name="Genre" column="genre" type="String" />

        <!-- Mapping der Audio-CD -->
        <many-to-one name="CD" column="cdid" class="AudioCD" lazy="false"/>        

        <property name="Path" column="pfad" type="String"/>
        <property name="Checksum" column="checksumme" type="String"/>
        <property name="InsertDate" column="insertDate" type="DateTime"/>
        <property name="UpdateDate" column="lastUpdateDate" type="DateTime"/>
    </class>
</hibernate-mapping>

Voraussetzung dafür ist, dass das Tabellenfeld "cdid" der AudioTrack-Tabelle das Fremdschlüsselfeld für die Tabelle mit den AudioCD-Datensätzen ist. NHibernate mappt das so, dass der Inhalt aus "cdid" der Primärschlüssel der Klasse AudioCD ist.

lazy=false habe ich angegeben, da es bei einzelnen Entities nicht so "teuer" ist, sie sofort mitzuladen.

06.02.2008 - 16:05 Uhr

Zum COM:

Also is eigentlich recht einfach. Ich lass mir alle COMPorts liefern, und versuche zu jedem eine verbindung aufzubauen und einen Befehl hin zu schicken. Vom Messgerät erwarte ich eine bestimtme Antwort. Kommt die, dann hab ich den richtigen Port gefunden, und das ganze wird gespeichert.

Wenn ich das über die Events mache, dann liefert er mir den falschen COM, nämlich den im Array eins weiter stehenden.

hört sich für mich an, als hättest du da ein kleines Logikproblem bei der Ermittlung des COM-Ports. Denn wenn du COM-Port X anfragst, geht die Anfrage auch dahin raus. Kann sein, daß du bei asynchroner Abfrage bereits den nächsten COM-Port abfragst, während die letzte Abfrage noch gar kein Timeout erhalten hat. Aber das kann man ohne Quellcode nicht sagen...

06.02.2008 - 16:02 Uhr

Das bedeutet aber, daß du Benutzername und Passwort für diesen Benutzer irgendwo hinterlegen musst. Mit dem Namen und dem Passwort hat man ja Berechtigungen innerhalb der Domäne, das ganze wäre ein gewisses Sicherheitsrisiko.

Man kann zwischen Domänen Vertrauensstellungen aufbauen. Details kann dir wohl eher ein Netzwerkadmin vermitteln, aber im groben dient das dazu, Nutzern einer anderen Domäne in der eigenen Domäne Berechtigungen zu geben. Damit man nicht jedem Nutzer von Hand eine Verzeichnisberechtigung hinzufügen muss, macht man das auch eher über Gruppenberechtigungen. Gruppe bekommt Leserecht, neue Nutzer werden der Gruppe hinzugefügt. Impersonation sehe ich da eher als unsauberen Flicken für ein Problem, das eigentlich in der Netzwerkadministration zu suchen ist.

06.02.2008 - 15:57 Uhr

Vielen Dank.

2.3)

AudioCD.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>  
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">  
  <class name="MeinNamensraum.AudioCD, MeinAssembly" table="audiocds">  
  	<id name="AudioCDId" column="cdid" type="int">  
  		<generator class="identity" />  
  	</id>  
  	<property name="CDName" column="cdname" type="String"/>  
  	<property name="Year" column="year" type="int" />  
  	<property name="Genre" column="genre" type="String"/>  
  	<property name="Artist" column="artist" type="String" />  
  	<property name="InsertDate" column="insertDate" type="DateTime"/>  
  	<property name="UpdateDate" column="lastUpdateDate" type="DateTime"/>  
  	<property name="DiscId" column="discid" type="String" />  
  	<set name="AudioTracks">  
  		<key column="cdid" />  
  		<one-to-many class="MeinNamensraum.AudioTrack, MeinAssembly" />  
  	</set>  
  </class>  
</hibernate-mapping>  

AudioTrack.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>  
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">  
  <class name="MeinNamensraum.AudioTrack, MeinNamensraum" table="audiotracks">  
  	<id name="AudioTrackId" column="autoId" type="int">  
  		<generator class="identity" />  
  	</id>  
  	<property name="TrackNr" column="tracknr" type="int"/>  
  	<property name="Artist" column="artist" type="string" />  
  	<property name="Title" column="title" type="String"/>  
  	<property name="Genre" column="genre" type="String" />  
  	<!--<property name="CD" column="cd_id" type="Int32"/>-->  
  	<property name="Path" column="pfad" type="String"/>  
  	<property name="Checksum" column="checksumme" type="String"/>  
  	<property name="InsertDate" column="insertDate" type="DateTime"/>  
  	<property name="UpdateDate" column="lastUpdateDate" type="DateTime"/>  
  </class>  
</hibernate-mapping>  

sieht bis auf ein Detail ganz gut aus. Du hast das Feld "cd_id" im AudioTrack-Mapping ausgeklammert. Im ersten Mapping heisst das Feld, das den Fremdschlüssel in der AudioTracks-Tabelle enthält, auf einmal "cdid".

ich hab meine Mappings bzw. die Klassen- und Namespace-Deklaration aber minimal anders aufgebaut. Assembly und Namespace definiere ich im <hibernate-mapping>-Node. Beispiel:


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyApp.Data" namespace="Data">
	<class name="Activitiy" table="activities">

		<id name="Id" column="id" type="Int32" unsaved-value="0">
			<generator class="native">
			</generator>
		</id>
		<bag name="ActivityFileAttachmentsList" inverse="true" lazy="true" >
			<key column="activity" />
			<one-to-many class="ActivityFileAttachments" />
		</bag>
		<many-to-one name="Contact" column="contact" class="Contact" lazy="false"/>
		<property column="activitytype" type="Int32" name="Activitytype" not-null="true" />
		<property column="activitydate" type="DateTime" name="Activitydate" not-null="true" />
		<property column="subject" type="String" name="Subject" not-null="true" length="60" />
		<property column="description" type="String" name="Description" length="2147483647" />
		<property column="medium" type="Int32" name="Medium" not-null="true" />
		<property column="ref_id" type="Int32" name="RefId" />
		<property column="ref_type" type="Int32" name="RefType" />
		<property column="companycontact" type="String" name="Companycontact" not-null="true" length="100" />
		
	</class>
</hibernate-mapping>

2.4) Dann ist eine Bag flexibler und nutzt eine Framework Collection? Wieso sollte man dann ein Set nutzen. Ich möchte das Set sowieso auf ein List<MeinTyp> mappen. Was empfehlst du mir? So ganz klar ist mir das leider noch immer nicht.

wenn du es eh auf einen eigenen Typ List<T> mappen willst, kannst du auch ein Bag mit einer IList<T> nehmen.

  1. Existiert bei einer Session eine dauerhafte Verbindung zur Datenbank? Was ist wenn die Verbindung getrennt wird, z.B. durch Netzwerkprobleme. Wird die Verbindung wieder hergestellt und die Session ist dauerhaft gültig. Oder muss zu diesem Zeitpunkt eine neue Session erstellt werden?

wenn einmal eine Datenbankverbindung auf ist und die Session bestehen bleibt, wird die Verbindung wahrscheinlich nicht von allein geschlossen. Das Szenario mit einer abgebrochenen Verbindung hab ich bisher selbst noch nicht getestet, da ich relativ viel mit ASP.Net und Webservices arbeite und Sessions da nur für einen Request leben.

Zum Thema Get und Load: Load holt anscheinend erstmal nur einen Proxy für das angefragte Objekt und lädt die Daten erst, wenn wirklich darauf zugegriffen wird. Get lädt das Objekt und gibt NULL zurück, wenn kein Objekt gefunden wurde. Load gibt immer den Proxy zurück und schmeisst eine Exception, wenn hinter dem Proxy keine Daten gefunden werden konnten.

06.02.2008 - 15:30 Uhr

im Debugger läufts eh alles etwas anders, vor allem bei Multithreading-Anwendungen. Schliesslich pfuschst du da ziemlich ins Timing und gerade da vermutest du ja dein Problem.

Was den COM-Port angeht: Hä?

06.02.2008 - 14:22 Uhr

ich würde anstelle des Thread.Sleep() einfach ständig die Daten des Messgeräts entgegennehmen, den letzten gelesenen Wert irgendwo ablegen und dann auf diesen Wert zurückgreifen, sobald der Barcodescanner Daten geschickt hat. Könnte man mit einem Timestamp (der zusammen mit dem gemessenen Wert des Messgeräts aktualisiert wird) kombinieren, damit man sicher sein kann, daß die Daten zum Zeitpunkt des Scans passen und das Messgerät oder der dazugehörige Thread sich nicht zwischenzeitlich aufgehängt hat.

06.02.2008 - 14:10 Uhr

zu 1) kann ich jetzt auch nicht sagen, wie das genau gemeint ist.

zu 2.2) ja.
zu 2.3) gute Frage, Mappingfehler sind etwas nervig. Es könnte sein, daß er den Typ AudioTrack aus irgendeinem Grund nicht findet. Namespace nicht angegeben, Assembly fehlt. Kannst du die beiden Mappingdokumente mal komplett reinstellen?
zu 2.4) Set und Bag sind ähnliche Implementationen, man kann sich im Prinzip das raussuchen, was man möchte. Beim Set kann man halt nicht über eine IList arbeiten, sondern muss die externe Library Iesi.Collections nutzen. Das kann innerhalb einer Bibliothek, die von verschiedenen Anwendungen genutzt werden soll, unerwünscht sein. Was den Hinweis auf eine nicht initialisierte IList sagen soll, weiß ich jetzt nicht. Kann natürlich sein, daß ein Entity keine Unterobjekte in einer Collection hat und die IList nicht erzeugt wurde (also NULL ist). Ich fange das bei mir in den Entity-Klassen über den Getter ab, der in so einem Fall ein List<>-Objekt erzeugt und das dann rausgibt.

06.02.2008 - 13:55 Uhr

Hmm
aber usecase1 ist ja keine Klasse sondern der Name des enums. und tim schrieb ja anstatt enum sollte ich den namen des enums schreiben im Konstruktor
Und was der Compilerfehler sagt (CS0118) weiss ich ja auch schon aber werd daraus nicht so richtig schlau

du sollst in der Konstruktorsignatur den Namen des Enums (das ist der Klassenname!) schreiben. Aber du hast anscheinend nicht ganz verstanden, was du da eigentlich machst. Der Konstruktor erhält einen Parameter vom Typ (!) usecase1, die Variable heisst uc1. Jetzt willst du diesen übergebenen Parameter irgendwo innerhalb der Klasse in einem Feld oder einer Eigenschaft ablegen. Dazu musst du aber erstmal ein Feld oder eine Eigenschaft definieren. Im Moment gibst du anstelle eines Feldnamens den Klassennamen des Enums an - das macht weniger als gar keinen Sinn.

so könnte das aussehen:


public enum usecase1 {Dummy};

public class Err
{
        usecase1 m_usecase;

        public Err(usecase1 uc1)
        {
            m_usecase = uc1;
        }
}

und wenn du die Klasse Err jetzt im Code instanzieren willst:



public void blubb()
{
        Err errObject = new Err(usecase1.Dummy);
}


06.02.2008 - 13:24 Uhr

Hallo

Irgendwie ist die Exception wenig aussagekräftig:

"An error message cannot be displayed because an optional resource assembly containing it cannot be found"

Daywalker2333

bezüglich dieser seltsamen Fehlermeldung: http://blogs.msdn.com/netcfteam/archive/2004/08/06/210232.aspx

wenn du das gemacht hast und dann die "echte" Fehlermeldung siehst, kannst du den Fehler genauer analysieren.

06.02.2008 - 13:14 Uhr

sowohl als auch. Man könnte auf Domänenseite über eine Vertrauensstellung Usern einer anderen Domäne Zugriff geben und damit das Problem beseitigen. Des weiteren wäre es möglich, sich über Impersonation die Zugriffsrechte einer anderen Domäne zu besorgen und mit diesen dann auf die Daten zuzugreifen. Ich persönlich würde es eher über die Domäne regeln, da ein Dateizugriff auf eine Freigabe erstmal ein reines Berechtigungsproblem ist und mit Bordmitteln der ADS gelöst werden kann.

06.02.2008 - 12:27 Uhr
  1. Nach einem Commit (es wird übrigens die Transaktion committed, nicht die Session) ist die Session weiter vorhanden. Die Transaktion könnte aber weg sein, hab ich bisher nie drauf geachtet.

  2. mehrere Anmerkungen, erstmal zum Mapping:

Gemappte Eigenschaften müssen mit "virtual" deklariert sein. NHibernate überschreibt da zur Laufzeit Setter und Getter fürs Lazy Loading.

NHibernate benötigt als Set-Listentyp Iesi.Collections.ISet nicht List. Welchen Listentyp NHibernate da tatsächlich reinschiebt, weißt du vorher nicht. Welcher Collection-Typ welchen Listentyp benötigt, kannst du hier sehen: http://www.hibernate.org/359.html#A9
ich nutze für meine Collections normalerweise ein Bag und als Liste eine IList.

Die "associated class not found"-Meldung deutet eher darauf hin, daß deine Mappings irgendwo noch Fehler enthalten. Falls der Fehler nach den Änderungen oben noch auftaucht, nimm testweise mal die Sets, Bags und One-To-Manys aus dem Mapping raus. Und schau vor allem nach, ob alle hbm.xml als eingebettete Ressource in die Assembly eingefügt werden, wenn du über AddAssembly konfigurierst.

06.02.2008 - 12:13 Uhr

damit ist die Zuweisung im Konstruktor gemeint. usecase1 ist eine Klasse, der kannst du keinen Wert zuweisen.

06.02.2008 - 10:12 Uhr

nö, ganz so einfach ist es nicht. Wenn man sich eine Session von der Sessionfactory erzeugen lässt, ist das erstmal eine neue Session. Da man ein Entity durchaus in mehreren Sessions laden und verändern kann, benutzt NHibernate eine abgekoppelte Entity nicht automatisch mit einer anderen Session (geht auch gar nicht, da die abgekoppelte Entity die neue Session gar nicht kennt). Man kann allerdings mit der Session.Lock()-Methode die Entity wieder an eine Session ankoppeln.

Bei ASP.Net hat man kaum eine andere Wahl, als sich detailliert Gedanken zum Thema Lazy Loading zu machen, da ein Objekt, das man im SessionState sichert, nach einem Roundtrip immer abgekoppelt ist. Bei Windows Forms-Anwendungen kann man durchaus mit einer einzelnen Session arbeiten, die über das Singleton-Pattern beim ersten Bedarf erzeugt und die ganze Zeit verwendet wird. Da die Entities dadurch nie von einer Session abgekoppelt sind, funktioniert das Lazy Loading auch automatisch.

06.02.2008 - 09:54 Uhr

hast du beim Assemblyverweis angegeben, daß eine lokale Kopie erstellt werden soll?

25.01.2008 - 08:23 Uhr

nix. Ich hab was geschrieben, festgestellt, daß es auf deine Frage gar nicht zutrifft und hab es wieder entfernt. Was ist daran so schwer zu verstehen?

24.01.2008 - 15:41 Uhr

Notiz an mich selbst: erst lesen, dann schreiben.

23.01.2008 - 22:44 Uhr

ein ORM macht etwas mehr als nur typisierte Zugriffe. Anstelle von IDs werden z. B. ganze Objekte gemappt. Man kann Subklassen bauen. Automatisiertes spätes initialisieren von gemappten Collections. Versionierung. Einen ORM auf den typisierten Zugriff auf ein Feld zu reduzieren, würde u.a. die Jungs von Hibernate nicht unbedingt glücklich (und ziemlich schnell arbeitslos) machen.

23.01.2008 - 22:40 Uhr

http://www.json.org/

da findest du einige C#-Libraries. Wenn eine davon quelloffen ist, kannst du sie unter Umständen fürs Compact Framework kompilieren.

23.01.2008 - 09:44 Uhr

wo genau knallts? Ein ganz kleines bisschen Quellcode wäre da schon sinnvoll. Aber wahrscheinlich hast du nur vergessen, irgendwo auf NULL zu prüfen. Oder die Datenbank lässt in einem Feld keine Nullwerte zu und du hast im Insert dieses Feld nicht mit angegeben - das Feld wäre NULL, Datenbank weigert sich. Lösung: Feld übergeben oder NULL in der Datenbank erlauben.

Aber wie gesagt: etwas Quellcode von der Stelle, an der der Fehler auftritt, wäre hilfreich.

23.01.2008 - 09:05 Uhr

du kannst dir ja mal den Quellcode von so einem typisierten Dataset anschauen. Im Prinzip kapselt das Ding nur den Zugriff auf die von dir angegebenen Tabellen und Spalten in einem normalen Dataset. Das Ding macht alles genauso, wie man es mit einem untypisierten Dataset "zu Fuss" machen würde (inklusive händischer Casts, NULL-Prüfung und so weiter). Ist ne kleine Erleichterung und man vermeidet Vertipper bei Spaltennamen, aber viel mehr leistet das Ding nicht.

22.01.2008 - 17:02 Uhr

so ein typisiertes Dataset ist nur eine Klasse, die um ein Standard-Dataset herumgebaut wird (bzw. die DataSet-Klasse um ein paar Methoden erweitert und stark typisierte Zeilen- und Tabellentypen erzeugt) und einem das Casten abnimmt. Da steckt keine echte Intelligenz dahinter. Im Hintergrund werkelt weiterhin das "gute alte" DataSet.

22.01.2008 - 16:40 Uhr

würde mich wundern. DataTable.Select() läuft im Speicher ab und durchläuft die in der DataTable liegenden Daten. Da wird keine Verbindung zur Datenbank aufgebaut, also wird der Index auch keine Rolle spielen.

22.01.2008 - 13:28 Uhr

man kann das ganze auch in einen einzelnen Workerthread zusammenfassen, der einfach nur nacheinander alle Zugriffe abarbeitet. Das ist eine reine Designentscheidung. 90 Threads halte ich aber für etwas zuviel für ein paar kleine Datenbankzugriffe. Am besten, man gibt dem Thread beim Start die Liste der Objekte mit (oder hält eine statische Liste der abzuarbeitenden Objekte parat) und der arbeitet sie der Reihe nach ab. Je nachdem, wie die Aktualisierung gestaltet werden soll, muss man sich dann was zum erneuten Aktualisieren nach dem ersten Durchlauf ausdenken.

Events werden, wie auch in dem FAQ-Beispiel ersichtlich wird, in dem Thread ausgeführt, in dem sie ausgelöst worden sind. Besonders wichtig bei GUI-Aktualisierungen. Aber auch beim Aktualisieren von Listen, auf die mehrere Threads zugreifen könnten, muss man hier aufpassen (Stichwort Schlüsselwort "lock").

22.01.2008 - 10:09 Uhr

man könnte das ganze so programmieren, daß ein Objekt nach Beendigung seiner Arbeit explizit die Anzeige aktualisiert. Wenn aber viele Aufgaben im Hintergrund passieren sollen, während die GUI den aktuellen Status anzeigen soll, ist Threading eigentlich der bessere Weg. Die Arbeit in einen Workerthread auslagern, der über Events Statusänderungen nach aussen publiziert. Die GUI abonniert diese Events und reagiert entsprechend. Zu dem Thema gibt es auch schon ein paar Beiträge in der FAQ, u.a. : Controls von Thread aktualisieren lassen (Control.Invoke)

21.01.2008 - 16:25 Uhr

du kannst einen Dienst ja per Hand starten, indem du ihn anklickst und dann auf "Dienst starten" klickst. Das startet den Dienst manuell, die Startart wird nicht geändert. Wenn du mit einem Rechtsklick auf den Dienstnamen, dann Klick auf "Eigenschaften" die Eigenschaften des Dienstes aufrufst, kannst du die Startart des Dienstes von "Manuell" auf "Automatisch" umstellen. Das bewirkt, daß der Dienst beim Start des Rechners automatisch mitgestartet wird.

Und wie gesagt: was du da im Code angibst, spielt überhaupt keine Rolle.

21.01.2008 - 15:01 Uhr

hast du den Dienst einfach nur per Hand gestartet oder wirklich die Startart von "Manuell" auf "Automatisch" geändert? Falls die Startart schon auf "Automatisch" steht, kann es sein, daß deine Dienstanwendung abstürzt und deswegen kurz nach dem Start schon nicht mehr läuft. Das kann man dann in der Ereignisanzeige sehen. Könnte dann unter anderem an einer nicht eingetragenen Abhängigkeit liegen (z. B. wenn dein Dienst Netzwerkzugang voraussetzt, die Netzwerkdienste aber erst später hochfahren). Aber schau wie gesagt erst mal, ob da schon die richtige Startart hinterlegt ist.

21.01.2008 - 10:47 Uhr

In der Systemverwaltung unter Dienste die Startart des Dienstes ändern. Programmatisch geht das innerhalb der Dienstanwendung nicht, da die Programmlogik ja erst durchlaufen wird, wenn der Dienst gestartet wird. Man kann allerdings beim Anlegen des Dienstes die Startart mit angeben.

15.01.2008 - 12:10 Uhr

ich find grad bei den Zebras die Tatsache, daß man die Windows-Druckertreiber nicht benötigt, so gut. Ich hab bei unseren Z4M nach mehreren Stunden mit den Windows-Treibern aufgegeben (wobei ich nicht weiß, ob das jetzt an den Treibern oder am Crystal Reports lag), die Variante mit den Druckerbefehlen funktioniert im Gegenzug absolut reibungslos und zuverlässig. Vor allem muss man sich nicht mit Etikettenstandards und der Ausrichtung im Designer rumquälen.

15.01.2008 - 10:07 Uhr

schreib das ganze in eine temporäre Datei, kopiere die Datei dann per FileInfo.CopyTo() auf die Druckerfreigabe. Beispiel:


...snip
                            FileInfo tmpFile = new FileInfo(System.IO.Path.GetTempFileName());
                            FileStream writeStream;
                            if (!tmpFile.Exists)
                                writeStream = tmpFile.Create();
                            else
                                writeStream = tmpFile.OpenWrite();
                            StreamWriter writer = new StreamWriter(writeStream);
                            writer.Write(sbTemplate.ToString());
                            writer.Close();
                            tmpFile.CopyTo(currentConfig.PrinterName);
                            tmpFile.Delete();

sbTemplate ist ein StringBuilder, der die auszuführenden Druckbefehle enthält.
currentConfig.PrinterName enthält den Druckernamen, beispielsweise "\spoolsrv\zebra1"

rein zum Testen kann man den Drucker auch als Textonly-Drucker installieren und per Notepad (Wordpad geht nicht) drucken. Ganz praktisch, um das Layout des Etiketts anzupassen.

03.01.2008 - 15:57 Uhr

codeproject.com kennst du schon?

03.01.2008 - 15:14 Uhr

verdammt, ich hab's mir verkniffen.

02.01.2008 - 14:52 Uhr

Wenn in der Web.config irgendwas von unbekannten oder undefinierten ConfigSections steht, dann liegt das meist an der fehlenden Definition für diese Sektion - oder evtl. an einer fehlenden Referenz auf die Bibliothek, die den Parser für diese Sektion bereitstellt.

02.01.2008 - 14:47 Uhr

Das wird wohl phpMyAdmin sein, das wahrscheinlich eine andere Einstellung für den zu verwendenden Zeichensatz benutzt.

13.12.2007 - 15:18 Uhr

als Treiber muss "NHibernate.Driver.MySqlDataDriver" eingetragen werden. Zusätzlich muss der .Net-Connector von MySql AB installiert bzw. die darin enthaltene Assembly "MySql.Data" referenziert sein.

NHibernate benötigt immer eine eindeutige Id. Das Fehlen dieser Id wird den Mappingfehler erzeugen.

10.12.2007 - 11:53 Uhr

bei mobilen Geräten siehts im Prinzip genauso aus wie auf dem Desktop (nur, daß da auch noch die gefühlten 12.000 Bugs des Compact Frameworks und die Unzulänglichkeiten der Windows Mobile-Umgebungen dazukommen). Performanceseitig ist es kein Problem, einzelne Klassen über eigenen Code in andere Klassen umzuwandeln (bzw. aus dem erhaltenen Objekt ein Objekt einer eigenen Klasse zu bauen). Serialisierung läuft auf den Dingern aber etwas schleppender. Ich vermute, daß Reflection im CF vergleichsweise viel Leistung benötigt (oder einfach aufgrund der begrenzten Ressourcen stärker ins Gewicht fällt).

Wenn du auf dem mobilen Gerät auch ohne deine eigenen Klassen auskommst (du müsstest eh ein neues Projekt dafür erzeugen, da du keine Desktop-Projekte in Compact Framework-Projekten referenzieren kannst), dann nutze nur die, die VS dir anhand des WSDL-Dokuments erzeugt. Denk dir einfach deinen Webservice und den ganzen Code dahinter weg und entwickle so, als hättest du gar keinen Zugriff auf den Backend-Code. Das ist im Prinzip auch der Hintergedanke beim Aufbau derartiger Systemlandschaften - einzelne Komponenten weitgehend unabhängig voneinander gestalten, so dass man sie unabhängig voneinander ändern oder austauschen kann.

10.12.2007 - 08:45 Uhr

so funktioniert das (leider) nicht. Visual Studio erzeugt beim Hinzufügen des Webverweises neue Klassen in deinem Projekt. VS kann ja nicht wissen, daß du die Bibliothek in beiden Projekten referenzierst. Abgesehen davon ist es ja eher selten der Fall, daß man einen Webservice beansprucht, den man selbst entwickelt hat und auf dessen Ressourcen man zugreifen kann. Deshalb erzeugt VS neue Klassen anhand der WSDL-Beschreibung deines Dienstes, die du dann für den Zugriff auf den Webservice nutzen musst.

Rein theoretisch könntest du den von VS erzeugten Webservice-Proxy weglassen und die Webservice-Behandlung komplett in die eigene Hand nehmen. Da könntest du dann aus der Webdienst-Rückmeldung wieder Klassen des ursprünglichen Typs machen. Ob der Aufwand sich dafür lohnt, kannst du nur selbst beurteilen.

Alternativ kannst du einen Typumwandler basteln, der aus den Klassen, die für den Webservice erstellt wurden, wieder deine Klassen erzeugt.

€: nochmal zum Verständnis: es sind NICHT mehr dieselben Klassen, die da zum Einsatz kommen. Deine ursprüngliche Klasse wird auf Webservice-Seite durch einen XmlSerializer gejagt, auf der Gegenseite passiert dasselbe nochmal. Das einzige, was übermittelt wird, sind ein paar Eigenschaften und öffentliche Felder, sämtliche privaten Felder und Methoden werden über den Webservice nicht übertragen. Von daher sind die von VS erzeugten Klassen eher als Hilfsklassen für den einfacheren Zugriff auf den Webservice zu verstehen, nicht als Repräsentation der Klassen, die im Webservice selbst zum Einsatz kommen. Da wird nur ein bisschen dummes XML übers Netz hin und her geschoben.

09.12.2007 - 23:13 Uhr

der Konstruktur der Seite wird bei jedem Aufruf, also auch jedem Postback aufgerufen. Du erzeugst bei jedem Klick auf den Button ein neues RemoteGallery-Objekt. Pack die Erzeugung des Objekts ins Page_Load und prüf mit Page.IsPostback ab, ob es sich um den ersten Aufruf oder um ein Postback handelt. Nur beim ersten Aufruf sollte das Objekt erzeugt werden, da du innerhalb des Objekts ja wahrscheinlich Statusinformationen zum aktuellen (und damit indirekt zum nächsten zu liefernden) Bild hälst.

Das Verhalten von Winforms- und ASPNet-Anwendungen ist in einigen Bereichen grundverschieden, da hier ganz unterschiedliche Konzepte vorliegen. Erfolgreiche Tests in WinForms-Anwendungen können nicht unbedingt auf den Einsatz in ASPNet-Anwendungen übertragen werden.

24.11.2007 - 19:42 Uhr

das Problem bei diesem abgeschalteten Check ist, daß du damit ein absolut nicht vorhersagbares Verhalten bekommst. Falls zwei Threads gleichzeitig auf ein Objekt zugreifen, ist nicht mehr sichergestellt, daß das ganze fehlerfrei abläuft. Beispielsweise könnte der Anwender in dem Moment, in dem der neue Thread auf das Listcontrol zugreft, die Auswahl in der Liste ändern. Je nachdem, wo im Code der Hintergrundthread in dem Moment gerade ist, kann das zu ganz witzigen und sehr seltsamen Effekten führen. Ein simpler Absturz aufgrund einer nicht abgefangenen Exception ist da noch einer der harmloseren Effekte.

Lies dich besser gleich etwas intensiver in das Thema Invoke und Delegaten ein. Einmal verstanden ist das ganze halb so wild und du rätst nicht mehr wild in der Gegend rum. Deine "Lösung" geht weit am Thema vorbei.

24.11.2007 - 18:49 Uhr

generell: niemals aus einem anderen Thread auf Formularelemente zugreifen. Dafür verwendet man Invoke und Delegaten, alles andere schreit geradezu nach Ausnahmen am laufenden Band. In deinem Fall sorgt schon die erste Zeile der Methode ThreadKopiereDateien für eine potentielle Ausnahme, da du vom Thread aus auf die Controls lst_quellen und tbx_ziel zugreifst. Dazu schiesst du noch eine Messagebox aus dem neuen Thread ab, was ebenfalls nicht gemacht werden sollte.

Was das "Keine Rückmeldung"-Problem angeht: am Ende des Threads führst du Application.Exit aus. Keine Ahnung, was das verursacht, wenn du das aus einem Hintergrundthread aufrufst und im Vordergrund noch eine GUI läuft.

14.11.2007 - 14:37 Uhr

eine EDI-Nachricht sieht für jeden Empfänger ein bisschen anders aus. Deshalb setzen Unternehmen normalerweise EDI-Konverter (z. B. den von Seeburger) ein, die aus unternehmensinternen Datenformaten EDI-Datenformate erstellen (z. B. aus einem R3-Idoc Typ INVOIC01 eine EDI-Invoice-Nachricht).

Die in einer EDI-Nachricht erlaubten Segmente kann man u.a. auf der Seite EDIFactory einsehen. Dazu bietet die UN ein Verzeichnis, in dem man die diversen EDI-Standards einsehen kann: http://www.unece.org/trade/untdid/welcome.htm. Ich würde an deiner Stelle vom Lieferanten die EDI-Nachrichtenregeln anfragen, wenn der Lieferant das anbietet. Anhand dieses Leitfadens kannst du dann das Dokument aufbauen.

03.11.2007 - 15:16 Uhr

string myConnectionString = "Data Source=192.168.1.120;User Id=root;Password=pwd;Database=synchroniser;";

30.10.2007 - 22:15 Uhr

was spricht gegen "einfach mal ausprobieren"?