Laden...
J
Jelly myCSharp.de - Member
Burden (Luxemburg) Dabei seit 09.09.2007 1.114 Beiträge
Benutzerbeschreibung

Forenbeiträge von Jelly Ingesamt 1.114 Beiträge

25.10.2009 - 14:22 Uhr

Was ist denn scan ?

Da du das Ganze im FormLoad Event schreibst, wird der Code nur einmal bei der Instanzierung der Form ausgeführt.

24.10.2009 - 13:58 Uhr

Ohne jetzt zu sehr auf die Win7 Tauglichkeit einzugehen, möchte ich mich trotzdem kurz bedanken für die Ausschweifungen von michlG und MagicAndre1981. So wie es also aussieht, sollte die Grafikkarte im Grunde reichen, und mit meinen 1.5GB RAM steht dann ja eigentlich keinem Versuch was im Weg.

Also wenn ich dann schon testen kann, wirds wohl die Win 7 Professional sein.

24.10.2009 - 09:41 Uhr

Ich würde ja gerne Win7 einsetzen. Ich weiss nur nicht ob mein Laptop den Anforderungen gewachsen ist 😃

Weiss jemand ob die Geforce 6600 128 MB RAM mit dem ganzen Grafikgedöhns in Win7 klarkommt (Aero usw.). Auch hab ich nur einen Single Prozessor 1,7 GHz drinne, da seh ich allerdings nicht so das grösste Problem

23.10.2009 - 15:41 Uhr

Ein geeignetes Stichwort wäre Hook.

Was genau willst du denn anstellen?

23.10.2009 - 15:40 Uhr

Den SQL Server gibts bei Microsoft. Und Zugriff aus der .NET Welt heraus geht z.B. über ADO.NET. Interessant hierzu sind die Klassen aus dem System.Data.SqlClient Namespace (SqlConnection, SqlCommand usw.)

23.10.2009 - 15:30 Uhr

Der SQL Server kann nach wie vor nur T-SQL, und es bleibt eine relationale Datenbank, d.h. flache Tabellenn, die du über Foreign Keys verknüpfen kannst. Du musst dir also schon deine rekursive Struktur in Tabellen aufbauen. Mittels geeigneten Select-Statements, die eventuell auch wieder reukursiv sein müssen, kommst du an alle Daten ran. Der Inhalt einer Datei wird dir aber trotzdem nicht als Pfad zur Verfügung stehen, sondern du wirst clientseitig wieder mit Blob Feldern arbeiten müssen. D.h. du kriegst ein Array of byte, das du dann interpretieren kannst wie du möchtest (z.B. als Datei lokal speichern o.ä.). Es ist keineswegs gewollt, dass Clients direkt auf ein Filesystem des SQL Servers zugreifen können.

23.10.2009 - 11:38 Uhr

Du kannst auch problemlos die EXE als Assembly referenzieren, und dann die öffentlichen Klassen daraus problemlos nutzen.

Oder unter VS unter den Projekreigenschaften den Application->Output Type ändern zu "Class Library"

23.10.2009 - 10:39 Uhr

MSSQL 2008 kann die Daten ja verwalten und ganz normal in einem Verzeichnis speichern (also nicht wie das klassische BLOB innerhalb der DB).

Naja, normal nicht. Der MSSQL Server kümmert sich um die Dateibenennung, und auch um das transaktionelle Löschen von Datensätzen.

Aber wie kann ich im Explorer z.B. jetzt einen Verzeichnisbaum simulieren? Also in anderen Worten: wenn ich mich durch das FIlesystem klicke soll er nicht in NTFS nachschaun sondern im MS SQL

Du hast da was falsch verstanden, glaub ich. Der FILESTREAM Typ ist eine MSSQL Sache. Es wird dir dabei nicht ermöglicht, das Dateisystem auf diese Art nach Verzeichnissen zu strukturieren. Einzig und allein der SQL Server ist für die Strukturierung zuständig, nicht du. Du kannst auf diese Art also keine Baumstruktur reinbringen. Die solltest du dir in geeigneter Weise in deinen relationalen Tabellen anlegen.

Der FILESTREAM Typ ist nicht viel anderes als das gute alte Blob Feld, nur dass der Inhalt eben getrennt in einer extra Datei abgelegt wird und nicht direkt im mdf File. Das hat den Vorteil, dass das MDF kleiner bleibt.

Also finger weg von den Dateien die der SQL Server anlegt.

20.10.2009 - 08:51 Uhr

Hier steht die Antwort, und als ersten Link krieg ich gleich das hier

19.10.2009 - 14:21 Uhr

Die Syntax ist ja auch falsch (EDIT: würde nur bei boolschen Typen gehen).
Wenn die strings gleich srein müssen dann wäre wohl eher == angebracht.

Sorry, war ein Tippfehler.

@snowy:
Was meinst du mit ((d.Name1) && (d.Name2)). Und was ist A und B und C? In deinem Eingangspost ist nur von Name | Position | Code die Rede.

Willst du 2 Records vergleichen oder sind Name1 und Name2 einfach nur 2 Properties aus einem Struct... Dann wäre das hier die lösung:

List<MyStruct> newList = myData.FindAll((d) => d.Name1 == d.Name2);
19.10.2009 - 13:27 Uhr

Wenn ich eine 1dim Liste hätte ok.

Aber sie enthält ja structs, und in den structs möchte ich in den Werten von A und B suchen.Wenn beide stimmen dann möchte ich den Wert C haben..

Jedes Eintrag deiner Liste kann doch problemlos ein Objekt oder Struct sein. Und suchen kannst du auch ziemlich easy in einer Liste:

// Suchen in Listen... DU erhälst eine neue Liste zurück
List<MyStruct> newList = myData.FindAll((d) => d.Name = "Bubu");

19.10.2009 - 08:58 Uhr

Greif auf eine einzelne Datei mal per UNc und nicht per Netzlaufwerk zu:

\192.168.0.1\data\audio\Mein.mp3

Damit ist auf alle Fälle mal Windows aussen vor. Wenn es dann noch langsam läuft, dann liegt das entweder an dem NAS oder deinem Programm.

Das kann ich nur unterstreichen. Ich habe auch ein NAS daheim, allerdings von Lacie, und dort gab es ähnliche Probleme, sobald viele Dateien auf das NAS kopiert waren. Das Verhalten war sogar nicht nur auf einen Ordner beschränkt, sondern allgemein. Zugriffe auf egal welche Datei in irgendeinem x-beliebigen Verzeichnis war a****lahm. Hatte dann Kontakt mit dem Hersteller aufgenommen: es war wohl ein Problem mit dem Controller. Das wurde behoben und seitdem läuft das Ding wie ne Eins.

Vielleicht hilft es also mal, das Problem dem Hersteller zu melden.

Ansonsten: Wenn dein NAS auch FTP Zugriff erlaubt, probiers mal damit.

15.10.2009 - 09:46 Uhr

Die .cs gehört auch nicht auf den Server, sondern nur eine DLL. Ich habe keine Ahnung, was bei dir schief läuft. Bei mir klappt ein "Publish" wunderbar, und im Unterverzeichnis App_Code liegt bei mir eine DLL.

Wenns eh nur ein Beispielprojekt ist, kannst du ja mal eventuell das Ganze hier im Forum hochladen.

14.10.2009 - 20:30 Uhr

Welche DB steckt denn dahinter? Wenns ein SQL2005 oder 2008 ist, dann würd ichs über die SqlDependency Klasse des .NET Frameworks machen. Darüber werden die Clients dann benachrichtigt, wenn sich was an der Tabelle ändert. Such mal im Forum, da gibts ein paar Beispiele zu. Ich denk, das ist die einfachste und schnellste Art, die Clients zu benachrichtigen.

14.10.2009 - 16:34 Uhr

Lokal im Intranet klappt das auf jeden Fall. Der CodeBehind (alsoe deine WebService1.Service1.cs Datei), wird bei mir im Unterverzeichnis bin unter dem Namen App_Code.dll veröffentlicht.

Was für einen Namespace hast du denn im WebService Attribut gewählt. Diese tempuri Sache sollte da auf jeden Fall mal weg.

Bringt zwar wahrscheinlich nix zur Lösung deines Problems bei, aber deine Namenswahl Service1 ist sicherlich nicht die bestgewählte.

14.10.2009 - 16:25 Uhr

Was sind das denn für Benachrichtigungen? Werden da massiv Daten übertragen, oder soll das z.B. einfach nur dazu genutzt werden, dass der Client eventuell seine Daten aktualisieren soll?

14.10.2009 - 15:15 Uhr

Ich kann doch sicher nicht einfach das Verzeichnis unter C:\Inetpub\wwwroot\MeinWebservice in einem belieben Verzeichnis im meinem Webspace kopieren und anschließend die asmx File aufrufen, oder?

Warum denn nicht? Ausserdem was spricht dagegen, es einfach zu probieren.

Geht dieser Umzug vielleicht auch mit Visual Studio?

Auch das geht, sogar noch einfacher, und auch nicht wirklich schwer zu finden. Einfach Rechtsklick auf dein Projekt im Solution Explorer und auf "Publish Website" gehen.

Es wär aber sicherlich auch nicht zuviel verlangt, selbst mal danach zu suchen, denn so versteckt ist die Publish Funktion aber nun auch wieder nicht.

14.10.2009 - 15:10 Uhr

Wenn ich die Datenbank in einem Setup verpacke und auch mit ausliefere, liegt sie
auf dem KundenPC auf z.B. C:\Programme\ck\myApplikation\Data\xy.mdb.

Das ist wahrlich ein denkbar schlechter Speicherort, da normale Benutzer in der Regel keine Schreibrechte auf c:\Programme besitzen. Das solltest du auf jeden Fall berücksichtigen.

14.10.2009 - 08:50 Uhr

Um .NET Webservices zu hosten muss dein Provider eigentlich lediglich ASP.NET können. Im Notfall kannst du das aber gleich beim Provider nachfragen. Die meisten geben dir auch einen Testaccount.

11.10.2009 - 17:29 Uhr

Ich kann zwar nicht für den Programmierer sprechen, aber SVN ist ein Quellcode Versionierungstool, und eigentlich dazu gedacht, komplette Updates einer Software darüber laufen zu lassen. Ausserdem braucht es dazu einen SVN Client, der auch nicht unbedingt als "vorausgesetzt" gesehen werden kann.

09.10.2009 - 08:42 Uhr

Du hast noch 2 Alternativen:*Du kannst den Dienst unter einem anderen Konto laufen lassen *Du kannst du User/Password Anmeldung am SQL Server nutzen, statt dich auf Windows Identies zu berufen. Da der Serverprozess ja normalerweise auf einer Kiste läuft, auf der die User keinen Zugriff haben, sehe ich keine Bedenken, den Usernamen und Passort dort in einer Config abzulegen. Es ist bei dir ja scheinbar so, dass WCF Service und SQL Server auf dem gleichen Rechner laufen, oder?

09.10.2009 - 08:36 Uhr

Was kann man noch am Code optimieren?

Wenn du im Exception Handling nicht mehr machst wie hier:

try
{
    SqlCommand command = new SqlCommand(cmd, connection);
    command.Parameters.AddWithValue("@TerminID", terminId);
    command.Parameters.AddWithValue("@FileName", fileName);

    command.ExecuteNonQuery();
}
catch (Exception ex)
{
    throw new Exception(ex.Message, ex);
}

Dann kannst du dir das auch ganz sparen, und einfach schreiben:

SqlCommand command = new SqlCommand(cmd, connection);
command.Parameters.AddWithValue("@TerminID", terminId);
command.Parameters.AddWithValue("@FileName", fileName);

command.ExecuteNonQuery();
05.10.2009 - 16:29 Uhr

TotalHours liefert die Industriestunden (falls es den Begriff gibt). Die Industrieminuten erhält man dann einfach durch Multiplikation mit 100.

Naja, ich lag ja nur um 2 Grössenordnungen daneben 😉

05.10.2009 - 08:13 Uhr

Für die Darstellung von Zeit- bzw. Datumsdifferenzen ist die DateTime Klasse nicht geeignet. Stattdessen gibt es die TimeSpan Klasse.. Hier ein Beispiel, wie die Industrieminuten dargestellt werden können:

DateTime t1 = new DateTime(2009, 10, 5, 7, 0, 0);
DateTime t2 = DateTime.Now;
TimeSpan dt = t2 - t1;

Console.WriteLine(dt.TotalHours.ToString());
03.10.2009 - 08:44 Uhr

Du willst also eine Art Baum erstellen, richtig?
Wenn die Baumtiefe immer nur maximal eins besteht (also immer nur auf Hauptgruppen verwiesen wird, aber niemals tiefer verschachtelt), sollte das relativ leicht sein und mit einem Selcfjoin lösbar sein...

Ist jetzt ungetestet, aber könnte irgendwie so aussehen:

select 
	s1.zeichnungsnr, s1.teilebezeichnung, s1.hauptbaugruppe, s1.verweis 
from 
	sma_stueckliste_eintrag s1
inner join	
	sma_stueckliste_eintrag s2 on s2.Verweis = s1.ZeichnungsNr or s2.Verweis is null
where 
	s1.projektnr=54
order by
	isnull(s2.Verweis, '0')
30.09.2009 - 15:43 Uhr

Wenn alles in einer Liste angezeigt wird : Klick auf die Spalte "Name", so dass nach Name sortiert ist, und dann die Taste "M" drücken.

Ich ärgere mich immer über Applikationen die Paging verwenden, da man meistens ewig rumklicken muss.

Ich wollte eigentlich auch nicht ausdrücken, dass ich Paging gut finde, sondern dass ich 150.000 Datensätze in einem Grid bescheuert finde.

Ich bleibe bei der Ansicht, dass es geschickter ist, denm Anwender eine intuitive Suchmaske zu geben, und nur die relevanten Datensätze anzeige.

Für sowas steh' ich auf "Suchen innerhalb des Ergebnisses" und Auto-Completion.

Das verwende ich auch sehr gerne, aber natürlich nur sinnvoll bis zu einem bestimmten Grad. (150.000 Einträge in eine AutoCompleteCustomSource List zu packen ist natürlich unsinnig).

30.09.2009 - 14:27 Uhr

Das erzähle mal meinen Anwendern !

Denen kann man ganz locker aus der Hüfte mit dem "Performanceprobleme" Argument zuschiessen. Und wenn das nicht reicht, kann man immer noch argumentieren, dass dann halt auf jeden Schreibtisch ein Dual Quadcore System mit 4GB RAM her muss, damit die Anwendung dann überhaupt noch läuft.

Das Problem seh ich also eher als zweitrangig.

30.09.2009 - 14:21 Uhr

Da fällt mir noch ein... Falls du die Möglichkeit hast, einen SQL 2005 einzusetzen, kannst mittels CTE (Common Table Expression) eine Art Paging erstellen (ähnlich dem Limit-Befehl bei MySQL)... Hier mal ein Beispiel:

with MyRecords as
(
	select IncidentId, Row_Number() over (order by IncidentId) as RowNumber
	from Incident
)

select * from MyRecords where RowNumber between 50 and 60
30.09.2009 - 14:13 Uhr

Gibt es denn prinzipiell ne Möglichkeit Datensätze schrittweise (nach Bedarf) zu laden?

Ich sags nochmal... Kein Mensch wird sich durch diese 150.000 Zeilen durchscrollen. Das frisst zudem, wie du auch schon erkannt hast, einfach zuviel Resourcen am Client.

Um eine Art "Paging" einführen zu wollen, kannstu das TOP Statement benutzen,.

30.09.2009 - 13:42 Uhr

Ich habe eine Tabelle (ca. 150'000 Datensätze), die ich anzeigen möchte.

Warum? Kein Mensch wird sich in den 150.000 Datensätzen zurecht finden. Wenn du eine Telefonummer suchst, blätterst du ja auch nicht durch ein 5 cm dickes Telefonbuch sondern suchst nach Ort und Namen. Genauso solltest du es auch mit deinen Datensätzen handhaben. Lass den Benutzer direkt über eine Scuhmaske einen eigenen Filter definieren und zeige nur noch die gefundenen Datensätze an. Filtern tust du dann direkt über SQL, das ist (geeignete Indexwahl vorausgesetzt) wesentlich resourcenschonender und auch wesentlich schneller.

30.09.2009 - 13:23 Uhr

Bei den Threads verstehe ich irgendwie nur Bahnhof, wahrscheinlich weil ich erst seit kurzen in C# arbeite

Dann kuck dir mal die BackgroundWorker Klasse an, die ist recht einfach zu handhaben.

29.09.2009 - 12:13 Uhr

Eine Frage noch: Was haltet ihr allgemein von Firebird

Imho die beste freie Datenbank. Ich möchte nicht behaupten, sie sei performanter als ein SQL Express beispielsweise, aber sie lässt sich sehr leicht administrieren und schluckt gerade auf Workstations nur wenig Resourcen. Als Oberfläche kann ich dir IBExpert empfehlen.

, welches ja eine Weiterentwicklung der Interbase/delphi Datenbank ist.

Firebird ist keine Weiterentwicklung, sondern ein Parallelentwicklung. Irgendwann vor einigen Jahren wurde Interbase 6 OpenSource. Und seitdem gibt es 2 Entwicklungsrichtungen: neuer Interbase Server sind wieder kostenpflichtig, und parallel dazu wurde Firebird entwickelt, der auf Interbase 6 basiert.

29.09.2009 - 11:10 Uhr

Die Logik beim Löschen ist folgende:
Es werden alle Dateien gelöscht die beim Updatevorgang angelegt wurden. Ist nach dem Löschen der Ordner leer (was normalerweise der Fall ist), wird der komplette Ordner gelöscht - aber auch nur dann.

Das ist gut 😉

Ein Problem sehe ich allerdings dann wenn du bei 400PCs immer den Ordner \server$_936DA01F-9ABD-4d9d-80C7-02AF85C822A8 verwendest. Würden nun zwei PCs gleichzeitig ein Update durchführen würde ja vllt der eine Prozess dem anderen die Ordner weglöschen.

Ich hab da vielleicht was falsch verstanden, aber ich gehe davon aus, dass ICH in der AppDater Klasse diesen Pfad selbst mit übergebe. Wenn dem so ist, würde ich natürlich somit für jeden Client seinen eigene guid-Pfad verpassen. Gearbeitet wird dann also nur in dem Pfad.
Oder dachtest du an die Möglichkeit, diesen Pfad in deiner AppDate Gui irgendwo fest anzugeben. Dann hast du natürlich Recht und ein Update könnte kritisch werden.

29.09.2009 - 10:40 Uhr

Also erstmal Klasse dass du dir die Zeit genommen hast, um das Gesagt umzusetzen.

  1. UserSpecified: Verwende ein benutzerdefiniertes Verzeichnis

Da spricht ja dann auch nix dagegen, ein Netzpfad als temporäres Verzeichnis zu verwenden, oder? Denn erneut ist es schwer generell für jeden PC ein Verzeichnis zu nennen, in das jeder Benutzer schreiben kann. Das ist PC spezifisch, und somit schwer handlebar. In einer AD Umgebung jedoch kann ich mir temporäre Verzeichnisse selbst definieren, und da gibt es keine Probleme mehr mit Schreibrechten.

Frage noch hierzu: Wenn ich ein Tempverzeichnis à la _\server$936DA01F-9ABD-4d9d-80C7-02AF85C822A8 angebe (die Guid würde ich selbst erstellen wollen), wird nach dem Update diese Verzeichnis wieder gelöscht oder nicht? Wenn nicht, dann sammelt sich im Laufe der Zeit dort eine Menge an.

An dieser Stelle wäre auch denkbar sich direkt in der DLL noch vor dem Aufruf der updater.exe per Impersonation am Konto des Benutzers anzumelden der das Update durchführen soll und in dessen Temp-Ordner zu schreiben. Eventuell füge ich diese Funktion dann später noch hinzu.

Das wird meines Erachten schief gehen. Wenn sich der impersonifizierte Benutzer noch nie an dem Rechner eingeloggt hat, so steht ihm auch kein Profil unter c:\Dokumente und Einstellungen\ImpUser zur Verfügung, und er besitzt somit auch kein eigenes Temp Verzeichnis. Diese Option würde ich komplett ausser Acht lassen und gar nicht erst anbieten.

Auch habe ich nun die Einstellmöglichkeiten unter "Rechte" geändert. Bisher war es ja nur möglich entweder Adminrechte zu fordern oder ein anderes Benutzerkonto zu verwenden. Allerdings ist das ja quatsch. Denn das eine schließt das andere ja nicht aus. Somit stehen nun 4 Szenarien zur Verfügung unter denen ein Update durchgeführt wird

  1. Angemeldeter Benutzer, keine Adminrechte
  2. Angemeldeter Benutzer, Adminrechte
  3. Anderes Benutzerkonto, keine Adminrechte
  4. Anderes Benutzerkonto, Adminrechte

Das ist Klasse, wenn man ein Adminkonto erzwingen kann, und das in jedem Fall und nicht nur wenn was schief läuft wegen mangelnder Rechte.

Ich würde versuchen, die Einstellmöglichkeiten nicht durch zuviele Optionen zu erschlagen. Ich würds so sehen, dass eigentlich ein Flag Admin ja/nein reicht, und wenn ja, dann können noch die Authentifizierungsdaten eines Admins angegeben werden, oder leer gelassen werden, dann eben beim Update nachfragen. Aber das ist nur meine bescheidene Meinung als Anwender 😃

28.09.2009 - 11:22 Uhr

Naja. Das mit dem Installer SDK ist mir ein bischen overkill. Und es klappt noch nicht mal, habs grad installiert und das Beispielskript aus deinem Link verwendet.

Ich sag mal, ich kann schon zur Not damit leben, die Eigenschaft händisch mit Orca einzupflegen. Sinn des Ganzen ist es ja, dass es läuft.

Da fällt mir noch eine weitere Frage ein, auch passend zum Thema. Wenn ich mein msi über
meinSetup.msi /passive

starte, so wird direkt installiert, mit Fortschrittsbalken. Genau wie ich's haben will. Der Benutzer braucht nichts einzustellen, sieht eine Progressbar und merkt, dass sich was tut. Aber auch hier gilt wieder das Problem, das ich von aussen diesen /passive Parameter übergeben muss. Ich habe versucht über Orca dies ebenfalls zu definieren, das klappt dann aber leider nicht.

Ist sowas denn möglich?

28.09.2009 - 09:52 Uhr

Kann ich denn irgendwie dieses Setting per default festlegen, so dass einfach durch Starten des msi alles korrekt eingestellt wird.

Enen Weg hab ich gefunden, find ich allerdings recht aufwendig.

Über das Tool Orca kann ich das von VS erstellte MSI File öffnen, und dort in der Tables List "Property" auswählen, un eben dieses DISABLEADVTSHORTCUTS=1 hinzufügen.

Geht das denn aber nicht irgendwie direkt über's VS Setup Projekt?

EDIT: ] vergessen
EDIT2: Die Property heisst DISABLEADVTSHORTCUTS und nicht DISABLEADVSHORTCUTS

28.09.2009 - 09:21 Uhr

Das mit ADDLOCAL=ALL hat nix gebracht, DISABLEADVTSHORTCUTS=1 allerdings schon. Es wurden also tatsächlich diese "Advertised Shortcuts" angelegt. Und das ist auch daran zu erkennen, dass unter den Shortcut Eigenschaft kein Button mit "Find Target" zu finden war. Mit der DISABLEADVTSHORTCUTS=1 Eigenschaft gehts also jetzt.

Kann ich denn irgendwie dieses Setting per default festlegen, so dass einfach durch Starten des msi alles korrekt eingestellt wird.

28.09.2009 - 08:55 Uhr

Ich behaupte mal, dass du das ganze als advertised und per-user installiert.

Wo hätte ich das denn im VS-Projekt eingestellt? Wissentlich hab ich jedenfalls nichts geändert. Einzig und allein in den Eigenschaften des Setupprojektes selbst hab ich "InstallAllUsers" auf true stehen, damit mir die Shortcuts korrekt angelegt werden. Das hab ich in anderen Setupprojekten jedoch auch, und da klappts.

28.09.2009 - 08:47 Uhr

Ich habe jetzt mal mit dem ProcessMonitor das Ganze beobachtet, leider noch ohne grossen Erfolg. Es wird beim Start der Anwendung als normaler User nochmals massiv die msiexec.exe ausgeführt, und der Process Monitor spuckt mir dann alleine für die Registry Zugriffe über 13000 Zeilen aus. Die geh ich sicherlich nicht alle durch. Vor allem, weil das die unglaublichsten Zugriffe drinstehen, für den HKCR so Dinge wie "Audio Compression Manager". Alles Sachen die ich ¨überhaupt nicht nachvollziehen kann.

Ich hab keine Ahnung warum bei einer simplen MSI Installation ein Logfil von über 80000 Zeilen bei rauskommt. Das ist ja Wucher :evil:

Ich forsche aber mal weiter!

27.09.2009 - 09:41 Uhr

vielen Dank erstmal. Ich probier deine Vorschläge am Monta im Büro mal aus.

25.09.2009 - 16:34 Uhr

Ich habe ein Phenomän das ich einfach nicht in den Griff kriegen will. Ein Visual Studio Setup Projekt installiert meine Anwendung über ein MSI. Natürlich als Admin. Die Shortcuts werden für alle User sowohl auf dem Desktop als im Startmenu erstellt. Starte ich die Anwendung als Installateur, gibts keine Probleme.

Logge ich mich als normaler User auf der Machine ein, sind die Shortcuts vorhanden. Starte ich die EXE direkt aus dem Explorer heraus, läuft sie einwandfrei, d.h. es fehlen keine Registryeinträge oder sonst was. Starte ich sie über einen der "All Users" Shortcuts, werd ich nochmal nach dem MSI Paket gefragt. Das ist untragbar, zumal normale User noch nicht einmal Leserechte auf das Setup Verzeichnis haben.

Wie gesagt, ich habe bereits alle Optionen in meinem Setupprojekt durchleuchtet, und ich finde wirklich keine Userspezifischen Einstellungen mehr.

**Warum wird der Benutzer also nochmal zu dem MSI Paket aufgefordert? **

Übrigens, wenn ich ihm Zugriff auf das MSI gewähre läuft die Anwendung. Ich hab aber keine Ahnung was dann da noch nachinstalliert wird?

25.09.2009 - 16:26 Uhr

Danke Peter.. Werd mich da mal durchlesen.

25.09.2009 - 16:24 Uhr

Vielen Dank für den kleinen Ausflug. Das war mir bislang nicht bewusst. :evil:

25.09.2009 - 11:58 Uhr

Ja, das mit der Sessionverwaltung sollte so wie Peter es schildert eigentlich einleuchtend sein.

Ich hatte mal eher das Phenomän, dass der IIS ganze ASP.NET Webseiten freigibt, wenn sie über einen bestimmten Zeitraum nicht mehr aufgerufen wurden. Das kann mal in den Eigenschaften der Webseite einstellen. Jedoch hat meine Erfahrung gezeigt, dass diese Zeitspanne nicht eingehalten wird, sondern die ganzen Seiten viel früher freigegeben werden. Da habe ich dann auch den Verdacht, dass der Garbage Collector zuschlägt, ohne dass der IIS das mitbekommt. Es war in der Hinsicht ziemlich störend, da ein erneuter Aufruf der ASP.NET Seite dadurch immer wieder ne halbe Minute gedauert hat. In den Griff bekommen hab ich das nicht, und deshalb läuft lokal ein Service, der nichts anderes macht, als alle 2 Minuten mal eine popelige leere Seite aus der Web aufruft. Seitdem läuft die Webseite einwandfrei ohne Unterbrechung.... Aber das passt eigentlich nur indirekt in die Frage in diesem Thread rein.

25.09.2009 - 11:53 Uhr

Ich glaub ich hab mich mit seiner Klassendefinition verlesen. Ich dachte seine xBASModularForm Klasse wäre schon von was geerbt. Da sollte man doch dann aber schon base() in der vererbten Klasse aufrufen!

25.09.2009 - 09:47 Uhr

auch wenn das an deinem Problem vermutlich nichts ändert, würde ich schreiben:

  
        public xBASModularForm()  
        {  
            InitializeComponent();  
        }  
  

Ich würd sogar noch einen Schritt weiter gehen und


        public xBASModularForm() : base()
        {
            InitializeComponent();
        }

schreiben

25.09.2009 - 09:21 Uhr

dass geschieht allerdings in einem Temp-Ordner - vllt läuft da aber auch etwas schief.
In welchem denn, dann kann ich das überprüfen!

Also wenn ich das richtig sehe, legst du die temporären Dateien hier ab:

C:\Documents and Settings\Tom\Local Settings\Temp\appdater\20090925_085153506

Wenn du jetzt deinen Benutzer impersonifizierst (z.B. auf den Benutzer Admin), kann es dann sein, dass versucht wird ins Temp Verzeichnis vom Benutzer Admin zu schreiben. Das schlägt dann aber definitiv fehl, wenn der Benutzer Admin sich noch nie auf dem System eingeloggt hat, da dann nämlich noch sein Benutzerprofil fehlt, und somit auch sein Temp Ordner an sich. Imho machst du da also was falsch, überhaupt diesen Ordner als Puffer heranzuziehen.

Noch eine Bemerkung zu dem ganzen Logging... Ich starte die Updateprüfung jeweils direkt nach dem Start des Programms. Dein ausgeprägtes Logging sorgt dann bei mir dafür, dass zumindest im %Temp%\AppDater Ordner ein neuer Unterordner mit dem aktuellen Datum erstellt wird (z.B. 20090925_085908266), in der dann zumindest die updates.xml Datei landet. Das passiert auch, wenn überhaupt kein Update erfolgt weil der Client schon die aktuellste Version hat. Unschön an dem Ganzen ist einfach, dass nach jedem Programmstart immer wieder ein neuer Ordner angelegt wird, und so kommt es dass ich jetzt alleine schon durch mein Testen 180 Ordner dort liegen habe. Un weil ich so ausgiebig getestet habe, habe ich natürlich auch einie Updates erwzungen, und alle diese Updatedaten legst du dann auch unwiderruflich in diesem Temp Ordner ab, und das sowohl als Original Zip Datei, die Backup Dateien und die entpackten Dateien aus dem Zip Archiv. Dadurch ist mein %Temp%\AppDater Ordner mittlerweilen auf 600MB angeschwollen. Völliger Verschwendung würd ich meinen. Wenn ich mir vorstelle, dass ich eine Anwendung hier im Haus auf 400 PCs laufen habe, die über 2 Jahre hinweg jeden Tag (sogar wenn auch nur ein einziges mal) auf jedem PC gestartet wird, dann legt der AppDater insgesamt 4002365 Ordner an. Das sind fast 150.000 Ordner, die wir schön fleissig jeden Tag zentral backupen.

Ich denke, deine Logging Sache sollte nochmals gründlich überdacht werden, gerade auch in Bezug auf das Impersonifikationsproblem.

Nimm meine Kritik bitte nicht persönlich. Ich liebe das Projekt nach wie vor. Nur sollten diese Dinge unbedingt behoben werden bevor damit produktiv gearbeitet werden kann. Das wollte ich hier klarstellen mit meinem Post, nicht dass plötzlich irgendwelche Benutzer böse Erfahrungen mit AppDater machen müssen.

25.09.2009 - 09:21 Uhr

dass geschieht allerdings in einem Temp-Ordner - vllt läuft da aber auch etwas schief.
In welchem denn, dann kann ich das überprüfen!

Also wenn ich das richtig sehe, legst du die temporären Dateien hier ab:

C:\Documents and Settings\Tom\Local Settings\Temp\appdater\20090925_085153506

Wenn du jetzt deinen Benutzer impersonifizierst (z.B. auf den Benutzer Admin), kann es dann sein, dass versucht wird ins Temp Verzeichnis vom Benutzer Admin zu schreiben. Das schlägt dann aber definitiv fehl, wenn der Benutzer Admin sich noch nie auf dem System eingeloggt hat, da dann nämlich noch sein Benutzerprofil fehlt, und somit auch sein Temp Ordner an sich. Imho machst du da also was falsch, überhaupt diesen Ordner als Puffer heranzuziehen.

Noch eine Bemerkung zu dem ganzen Logging... Ich starte die Updateprüfung jeweils direkt nach dem Start des Programms. Dein ausgeprägtes Logging sorgt dann bei mir dafür, dass zumindest im %Temp%\AppDater Ordner ein neuer Unterordner mit dem aktuellen Datum erstellt wird (z.B. 20090925_085908266), in der dann zumindest die updates.xml Datei landet. Das passiert auch, wenn überhaupt kein Update erfolgt weil der Client schon die aktuellste Version hat. Unschön an dem Ganzen ist einfach, dass nach jedem Programmstart immer wieder ein neuer Ordner angelegt wird, und so kommt es dass ich jetzt alleine schon durch mein Testen 180 Ordner dort liegen habe. Un weil ich so ausgiebig getestet habe, habe ich natürlich auch einie Updates erwzungen, und alle diese Updatedaten legst du dann auch unwiderruflich in diesem Temp Ordner ab, und das sowohl als Original Zip Datei, die Backup Dateien und die entpackten Dateien aus dem Zip Archiv. Dadurch ist mein %Temp%\AppDater Ordner mittlerweilen auf 600MB angeschwollen. Völliger Verschwendung würd ich meinen. Wenn ich mir vorstelle, dass ich eine Anwendung hier im Haus auf 400 PCs laufen habe, die über 2 Jahre hinweg jeden Tag (sogar wenn auch nur ein einziges mal) auf jedem PC gestartet wird, dann legt der AppDater insgesamt 4002365 Ordner an. Das sind fast 150.000 Ordner, die wir schön fleissig jeden Tag zentral backupen.

Ich denke, deine Logging Sache sollte nochmals gründlich überdacht werden, gerade auch in Bezug auf das Impersonifikationsproblem.

Nimm meine Kritik bitte nicht persönlich. Ich liebe das Projekt nach wie vor. Nur sollten diese Dinge unbedingt behoben werden bevor damit produktiv gearbeitet werden kann. Das wollte ich hier klarstellen mit meinem Post, nicht dass plötzlich irgendwelche Benutzer böse Erfahrungen mit AppDater machen müssen.

25.09.2009 - 08:44 Uhr

Eine (frei verfügbare) Gesamtlösung für das am Anfang des Thread genannte Problem gibt es scheinbar nicht ?

Was heisst schon frei verfügbar. Es gibt gewisse Technologien, die dein Vorhaben realisieren können. Aber nur vom technischen Aspekt her.

Befinden sich deine Clients und der WCF Server in einem LAN in derselben Domäne (oder trustet zumindest)? Wenn ja, dann hoste deinen WCF Server in einem Windows Dienst, nutze NetTcp Binding an irgendeinem freien Port und den passenden DuplexChannel. Ich hab das mal gemacht, und es läuft wirklich reibungslos. Im LAN gehts kaum noch schneller, und die Verbidnung selbts ist sogar noch trotzdem verschlüsselt.

Bei mir wurde der Callback einfach nu genutzt, um am Client ein Event auszulösen, damit der weiss dass sich was am Server getan hat, und somit z.B. seine Datensicht aktualisieren soll. Du solltest jedenfalls nicht zu grossen Daten über den Callback Kanal schicken, da dann sehr die Performance darunter leiden kann bei vielen Clients.

25.09.2009 - 08:12 Uhr

Der Garbage Collector sammelt nur Objekte ein, auf die nicht mehr referenziert wird.

Bist du dir in diesem Fall sicher. Ein http Request ist stateless, was doch heisst dass nach einem Aufruf der Seite dann erst mal das Objekt in der Session nicht mehr referenziert wird, oder? Ist es nicht so, dass der IIS nach einem Timeout, also wenn nicht auf ein bestimmtes Sessionobjekt zugegriffen wird, diese Session dann kickt?

Auf der anderen Seite kann der Garbage Collector auch von Zeit zu Zeit diese Sessionobjekte löschen. Das würde zumindest bei mir das Phenomän erklären, dass trotz allen korrekten Timeouteinstellungen im IIS die Objekte dann doch ohne Grund schon viel früher gelöscht werden.