Wenn Du gewisse Systemrechte benötigst, dann kannst Du das dem Betriebssystem beim Start der Applikation mitteilen, sodass diese Informationen direkt zur Verfügung stehen.
@Abt: hast Du dafür irgendwelche Quellen / Seiten auf denen ich mich schlau machen kann ?
(...)
Das ist in meinen Augen dann einfach nur ein (selbstverschuldeter, oder durchaus auch unternehmerische) Fehler des Zeitmanagements.
Ich seh zB. so viele Teams, dessen Verantwortliche 120% der Zeit der Entwickler mit Inhalte vollballern.
Die Entwickler haben also nie ne Chance sich zeitlich weiterzubilden oder sich um grundlegende Dinge zu kümmern: da hat der Entwickler keine Schuld, das ist ein klassischer Unternehmensfehler.
Dem habe ich nichts hinzuzufügen ... 😎 - muß aber damit leben (wie so viele andere auch ...)
Im Endeffekt ist es nur die Trennung von Authentifizierung und Authorisierung; das ist die Basis jedes Berechtigungssystem, was wirklich jeder Entwickler im Griff haben muss (meine Meinung!). Wenn ein Entwickler nicht weiß, was Authentifizierung und Authorisierung sind und worin sie sich unterscheiden, dann fehlt extrem viel Basis für jede Sicherheit, jede Architektur und jeder realen Betriebsumgebung.
Entschuldige @Abt: aber das ist mir zu Pauschal...
Ich gehöre zu der älteren Generation (1965) , die das objektorientierte Programmieren mehr oder weniger rudimentär gelernt haben.
Wir (ich) habe(n) schon mitbekommen, das sich seit Vista grundsätzlich etwas geändert hat (und auch die Gründe) ...
Nur hatten wir den Nachteil, das wir nicht, so wie die jüngere Generation, in der Uni etwas darüber lernen konnten.
Und Du als MVP hast sicherlich noch mehr Hintergrund Wissen als der gemeine Programmierer, richtig ?
Ich habe leider nicht die Möglichkeit noch einmal die Schulbank zu drücken (obwohl das sicherlich seinen Reiz hätte...) - ich muß meine Brötchen verdienen ... 😉
Das werde ich wohl nie begreifen, warum ein Admin nicht alles auf einem Rechner sehen kann - zumal er es mit dem Windows-Explorer offensichtlich kann 😢
Bei Outlook kann ich es ja noch verstehen (Spammer-Programme) aber beim OFD schon nicht mehr ...
irgendwie begreife ich nicht, was AutodiscoverUrl jetzt wirklich für einen Wert von mir erwartet ?
(bei Google hab ich schon alles gesehen von Web-Adressen, Email-Adressen, UserName, etc... wobei das wahrscheinlich mit den verschieden Exchange-Servertypen (Netzwerk, Internet) zusammen hängt)
Ich will auf einen lokalen (in Netzwerk) Exchange-Server zugreifen , also ...
//Initialize Service
ExchangeService service = new ExchangeService();
//Use Integrated Authentification
service.UseDefaultCredentials = true;
und dann muss ich anscheinend den Zugriff benennen:
nehme ich meine E-Mail-Adresse läufts auf einen Fehler...
Fehler
the autodiscover service couldn´t be located.
Was wohl bedeutet, das dieser Dienst nicht installiert / freigeschaltet ist (also mit der IT reden ...)
Wobei ich auch irgendwie nicht verstehe, warum ich das brauche / dort was eintragen muss, denn ich will ja mit
service.UseDefaultCredentials = true;
die gespeicherten Anmeldedaten benutzen ...
Ich will ja nicht für jeden Rechner, auf dem dieses Programm ausgeführt wird, die Userdaten / E-Mail-Adressen / Passworte fest hinterlegen.
Gibt es keine Möglichkeit über das Intranet sich einfach "nur" einzuloggen ? Der User hat ja schon durch seine Anmeldung das Recht auf Exchange zuzugreifen, sonst würde Outlook ja nicht arbeiten, oder ?
Kann da jemand mal bitte Licht ins Dunkel bringen ?
beim Massenversand habe ich nun feststellen müssen , das der Aufruf
lo_OutApp = new Microsoft.Office.Interop.Outlook.Application();
recht lange dauert (gefühlt fast zwei Sekunden) ...
Also habe ich folgendes versucht, um das etwas zu beschleunigen ...
public class sendmail
{
#region Outlook
Microsoft.Office.Interop.Outlook.Application lo_OutApp = null;
Microsoft.Office.Interop.Outlook.NameSpace lo_NSpace = null;
Microsoft.Office.Interop.Outlook.MAPIFolder lo_Folder = null;
public Boolean Outlook_starten()
{
Boolean x_retwert = true;
if (System.Diagnostics.Process.GetProcessesByName("OUTLOOK").Count() > 0)
{
try
{
lo_OutApp = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
}
catch (COMException ex) { x_retwert = false; }
}
else
{
try
{
lo_OutApp = new Microsoft.Office.Interop.Outlook.Application();
}
catch (COMException ex) { x_retwert = false; }
}
return x_retwert;
}
public void send()
{
if (lo_OutApp != null)
{
lo_NSpace = lo_OutApp.GetNamespace("MAPI");
(usw)...
}
}
}
public void xyz()
{
sendmail x_sendmail = new sendmail();
if (x_sendmail.Outlook_starten())
{
foreach()
{
...
x_sendmail.send();
...
}
}
}
Das funktioniert bei der ersten E-Mail einwandfrei, bei der zweiten knallt es dann beim Aufruf von
lo_NSpace = lo_OutApp.GetNamespace("MAPI");
mit folgender Fehlermeldung:
Fehler
********** Fehlermeldung vom : 03.06.2021 10:22:20 **************************************************
Meldung: Der RPC-Server ist nicht verfügbar. (Ausnahme von HRESULT: 0x800706BA)
bei Microsoft.Office.Interop.Outlook.ApplicationClass.GetNamespace(String Type)
****************************************************************************************************
Google zählt verschieden Dinge auf, die aber irgendwie nichts mit Outlook zu tun haben...
geht so etwas nicht, oder was übersehe ich ?
Ich weiß, das ich das vermutlich auch mit EWS lösen könnte, aber da der Kunde wünscht, das (zu Kontollzwecken) die Mails nicht sofort raus gehen, muss die Möglichkeit des Offline-Betriebes möglich sein - u. da weiß ich nicht, ob das mit EWS möglich ist (wenn ich das richtig verstanden habe, dann übergeht EWS ja Outlook, richtig?)...
(...)Wenn du jetzt aber sagst du hast 30 Parameter, dann vermute ich, dass diese wohl einen großen Einfluss auf den eigentlichen Ablauf des Querys haben.
Z.B. könnte ich mir vorstellen das aus einer TabelleA nur 1 Datensatz benötigt wird und bei einem neuen Lauf mit geänderten Parameter benötigt man vielleicht 10.000 Datensätze.
genau so ist es - die Parameter sind vereinfacht gesagt von/bis-Eingrenzungen
Zitat von Tom
(...)Mein Tipp ist, wenn das Query schnell genug ist und es wird mit OPTION (RECOMPILE) behoben, dann lass es so. (...)
Ich werde es mal testeten u. berichten ...
Zitat von Tom
(...)Wenn nicht, dann solltest du dir Gedanken machen wie du das große Query in kleinere unterteilen kannst.
Oder vielleicht mal die ganze Architektur überdenken, weil vernünftig hört sich das mit 30 Parameter nicht an (...)
Ich habe (bis jetzt) die Erfahrung gemacht, das es immer noch schneller ist, ein großes SQL-Script zu benutzen, als die Daten unter c# zu verarbeiten / zusammen zu führen..
(was sich dann jetzt wohl durch den Speicherhunger von DataTables teilweise erklärt...)
(...)
Ob das schneller ist weiß ich nicht. Aber man kann dem Anwender eine Progressbar anzeigen und einen Abbruch Button zur Verfügung stellen.
Bei mir hat alles was länger als 2 Sekunden dauert eine Progressbar.
Auch ein guter Einwand ... 👍
Zitat von BerndFfm
(...)
Außerdem prüfe ich den Hauptspeicherbedarf. Wenn ein Anwender versucht eine Liste mit 100 Millionen Datensätzen anzuzeigen kommt eine entsprechende Fehlermeldung.
Wie kannst Du das denn, wenn doch der Reader strikt vorwarding ist, du also noch gar nicht weißt, wie viele Daten kommen werden?
Wirst ja hoffentlich nicht ständig den SQL Server neustarten wollen ...
Schönen Gruß
Tom
Hi,
tatsächlich will ich das natürlich nicht ...
Danke für den Tip /Link 👍 - wieder was dazu gelernt ...
Wenn ich das richtig verstanden habe, dann löscht "RECOMPILE" den Batch aus den SQL-Server-Speichern, so das beim nächsten Aufruf es wieder frisch eingelesen und verarbeitet werden kann ...
Das ist natürlich für eine dauerhafte Programmierung kontraproduktiv (damit wäre ja der Geschwindigkeitsvorteil dahin...)
Weißt Du in welcher sys-Tabelle solche Batches gespeichert werden ? (in der sys.objects augenscheinlich nicht) - dann könnte man ja dort gezielt ein "sp_refreshview" durchführen 7 oder den Eintrag löschen ...
(...) Die Parameter haben noch den Vorteil dass der SQL Server jedes Kommando nur einmal übersetzen muss wenn sich nur die Parameter ändern.
Das war auch meine bisherige Info und Intention ...
Zitat von BerndFfm
Lieber DataReader und selber durchgehen.
Was meinst Du genau,
using (SqlDataReader x_reader = x_ermittle_verpackungen_kunde.ExecuteReader())
{
cBestaende.Load(x_reader);
}
ist doch auch ok oder ist
using (SqlDataReader x_reader = x_ermittle_verpackungen_kunde.ExecuteReader())
{
while (x_reader.Read())
{
/// werte ermitteln und in DataTable einfügen
}
}
um das ganze aufzulösen: es lag(warum auch immer) am SQL-Server beim Kunden ...
Nach einem Neustart funktionierte alles wieder.
Ich danke allen für die Inputs (ich werde zukünftig auf die DataAdapter verzichten...) 😃
Zum Verständnis meinerseits:
Was passiert eigentlich genau (physikalisch) wenn ich einen SqlCommand ausführe?
Übergibt er den Command wirklich als Batch-File an den SQL-Server, so das dieser die eigentliche Verarbeitung durchführt u. (in meinem Fall) die Ergebnistabelle zurück liefert oder macht das der Command alles selber ?
Was wird denn nun genommen / gemacht ? Kannst Du mir da ein paar Links / Stichworte nennen ?
(Irgendwie scheine ich wohl mit meinem Wissen stehen geblieben zu sein ...)
Ich vermute mal ganz stark, das es dabei auch auf den verwendeten Berichtsdesigner ankommt, richtig?
Hast du mal geprüft welcher SQL Befehl beim SQL-Server ankommt? Ich vermute hier einen/mehrere Parameter welche hier Probleme verursachen.
Blöde Frage: wie kann man das denn ?
Zitat von Abt
(...) Warum willst Du überhaupt SqlDataAdapter nutzen, wenn Du schon ein fertiges Script hast und das auch direkt ausführen kannst?
Das ist doch DER Weg (so lese ich das jedenfalls im Netz), um ein Ergebnis direkt in eine DataTable zu bekommen; ok. man könnte einen DataReader nehmen u. durch alle Rows iterieren und "von Hand" in eine DataTable eintragen, aber das wäre sicherlich auch nicht schneller, oder ?
Zitat von BerndFfm
Was passiert wenn Du exakt den gleichen SQL Befehl im Code ausführst wie der aus dem Management Studio ?
Der im Management Studio ausgeführte Code ist der aus dem SQL-Command herauskopierte Code ...
folgendes Problem habe ich auf einem Kunden-System (und nur dort!) :
Ich habe ein 400-zeiliges SQL-Script mit 30 Parametern, welches Daten aus einer WaWi sammelt.
Dieses Script habe ich als Text hinterlegt und lese ihn in ein entsprechenden SQL-Command ein.
Die Parameter werden alle mit ihrem korrekten Datentyp und IsNullable = true erstellt.
Rufe ich nun einen entsprechenden DataAdapter auf
using (SqlDataAdapter da_su = new SqlDataAdapter(x_ermittle_verpackungen_kunde))
{
da_su.Fill(cBestaende);
}
dann laufe ich jedesmal auf ein Timeout
Zitat
"Das Ausführungstimeout ist abgelaufen. Der Timeoutzeitraum wurde überschritten, bevor der Vorgang beendet wurde, oder der Server antwortet nicht. ..."
Der Fehler verweist auf die Zeile "da_su.Fill(cBestaende)" ...
Den (das?) Timeout habe ich dabei schon auf 180 sek hoch gesetzt ...
Nun zu dem eigentlichen Problem:
Rufe ich das Script im Management Studio auf (mit über declare erstellte u. mit set entsprechend gefüllte Parameter) so funktioniert es einwandfrei und braucht nicht einmal zwei Sekunden ...
Auf meinem Entwicklungssystem habe ich keine Probleme ...
Kennt jemand ein solches Phänomen oder kann mir Tips nennen, wie man noch an das Problem heran kommen kann ?
Folgender Aufbau:
- TabControl mit mehrerern Reitern
- in einem Reiter befinden sich zwei ineinander verschachtelte SplitContainer
- in dem inneren SplitContainer ist ein (User)DataGridView
die SplitContainer sind auf TabStop = false gesetzt, das DataGridView auf TabStop = true...
ich habe die Doku zum CellContentClick gelesen, dort steht:
Zitat
Dieses Ereignis tritt auf, wenn auf den Zellen Inhalt geklickt wird. Sie tritt auch auf, wenn der Benutzer die LEERTASTE drückt und freigibt, während eine Schaltflächen Zelle oder eine Kontrollkästchen Zelle den Fokus besitzt, und für diese Zelltypen zweimal auftritt, wenn auf den Zellen Inhalt beim Drücken der Leertaste geklickt wird.
Wie gesagt, der Sinn erschließt sich mir nicht ...
das KeyDown, war mein Versuch die Leertaste vorher abzufangen - hat aber leider nicht funktioniert ...
Auch wenn das schon recht lange her ist, aber mein Problem hat damit zu tun:
Die vorgestellte Methode hat leider den Nachteil, das sie auch auf das Drücken der Leertaste reagiert (mir fehlt das Verständnis für den Sinn dahinter gänzlich ...)
Wie kann ich verhindern, das auf die Leertaste reagiert wird ?
Nur zum Verständnis:
Wenn ich deinem Bespiel folge, dann kann (sollte) ich ja im Prinzip alles was ich Auslöse mit async / await machen, oder würdest Du das auch machen, wenn tatsächlich "nur" visible gesetzt würde und das "füllen" an anderer Stelle passiert (und dann das "füllen" mit async /await machen)?
Macht dieses Vorgehen dann den BgWorker nicht gänzlich überflüssig?
Zu meinem tatsächlichen Problem:
Ist das denn für Dich nachvollziehbar, das ich zusätzlich zum Spring auch das Autosize auf true gesetzt haben muss, oder ist das tatsächlich ein Bug?
P.S.: kann man hier irgendwie einen Beitrag als gelöst / erledigt markieren ?
@Abt:
ich bin weiß Gott nicht allwissend und weit davon entfernt perfekt zu sein, aber die Antwort finde ich doch etwas herablassend ...
Wenn Du es weißt, wäre es dann nicht besser, andere an deinem Wissen teil haben zu lassen ?
Mittlerweile weiß ich, was passiert (Bug?):
der StatusStrip steht auf AllowMerge = true, in ihm sind zwei Objekte enthalten:
- ein StatusStripText welches Spring = true und AutoSize = false eingestellt ist
- eine ProgressBar welche auf Visible = false ist
Wenn ich nun die Form starte und die Größe(Breite) ändere, dann passt sich der StatusStripText entsprechend an (wie erwartet).
Gem Microsoft Docs bedeutet Spring:
Zitat
Eigenschaftswert
Boolean
true, wenn ToolStripStatusLabel beim Ändern der Größe des Formulars automatisch den verfügbaren Leerraum von StatusStrip füllt; andernfalls false. Der Standardwert lautet false.
Nach meinem Verständnis würde das bedeuten, das wenn ein anderes Objekt hinzukommt, der verfügbare Leerraum kleiner wird u. dementsprechend auch der StatusStripText kleiner werden müsste - dem ist aber nicht so !
Wenn man nun, nachdem man die ProgressBar programmatisch auf Visible = true gesetzt hat, die Form langsam (so das der Rechner das noch zeichnen kann) in der Breite verändert, passiert immer noch nichts - wenn man das aber ruckartig macht, erscheint plötzlich die ProgressBar ...
Die Eigenschaft AutoSize des StatusStripTextes ist der entscheindende Wert - ich hatte ihn auf false gestellt, da ich glaubte, das das zusammen mit Spring nicht sauber funktionieren würde (doppelt gemoppelt)...
Aber: wenn ich AutoSize auf true stelle, dann funktioniert es sofort - ist für mich nicht wirklich nachvollziehbar, aber es ist so ...
Du siehst: es hatte wirklich nichts mit Threading zu tun ...
Ich wehre mich bestimmt nicht gegen Hilfe und bin dafür auch dankbar (so bin ich auch dankbar für den Hinweis auf asynchrone Programmierung, die bisher noch nicht auf meinem Radar war (in VFP gänzlich unbekannt...) - aber ich werde mich da mal einlesen...)
@Th69:
Ich hab mal ein System.Threading.Thread.Sleep(15000); eingebaut um das zu testen - Ja, die Form ist aktiv (lässt sich verschieben) und bedienbar (Klick auf Abbrechen-Button wird ausgeführt) ...
Das mit ProgressChanged kann hier doch noch gar nicht greifen, ich will doch erst einmal die ProgressBar sichtbar machen...
"Außerdem kann man die gesamte Funktionalität besser mit asynchroner Programmierung umsetzen." - dabei könnte ich aber dem User nicht zeigen, wie weit die Datei ist (außer ich würde für jede Datei eine ProgressBar erstellen) ...
Und, ich sehe im massenhaften parallelen Upload ein Performance-Problem (alleine schon durch die Bandbreite ...)
@Abt:
Es liegt nicht am BGWorker - wenn ich
SetProgressBar(true);
aus der Form direkt aufrufe, dann durchläuft er die "else"-Schleife , steht wieder die Eigenschaft richtig, aber es wird nicht angezeigt ...
Ich werde halt damit leben müssen, das ich die ProgressBar in der Entwicklung auf visible=true und dann direkt beim Aufruf wieder auf visible = false setzten muß - nur verstehen tue ich das nicht ...
Das war auch zuerst meine Vermutung, deshalb habe ich mir den Artikel durchgelesen - aber: die Aktionen sind keinesfalls "langlaufend".
Dagegen spricht auch, das alles funktioniert, wenn man die ProgressBar beim Initialize schon auf Visible = true hat (und dann direkt wieder auf Visible = false setzt) ...
Und ja, da die eigentliche Codeausführung (Upload von Dateien) länger dauern kann, wird das ganze aus einem BgWorker heraus (gleich zu Beginn) aufgerufen ...
Die ProgressBar soll dabei den Fortschritt anzeigen.
Nochmal: das ist nicht mein Problem ! er geht in keine Exception !!!
Im Anhang des Screenshots im Debug-Modus (vor dem setzen):
(eingefühte IMGs werden leider nicht akzeptiert...)
er führt die Befehle aus, die Progressbar wird aber trotzdem nicht sichtbar ...
Was ich aber vergessen habe zu erwähnen:
Der StatusStrip sitzt auf einer vererbten Form, auch der hier gezeigte Quellcode ist in der vererbten Form, der Aufruf erfolgt in der "Unterform" mit
SetProgressBar(true);
Was aber meiner Meinung nach kein Problem darstellen sollte, oder ?
Es funktionert nur, wenn ich die ProgressBar in der Entwicklungsumgebung auf Visible = true setzte !
Dann muss ich es aber im im Form-Aufruf nach InitializeComponent() wieder auf
toolStripProgressBar.Visible = false;
setzen, was ich aber eigentlich nicht will (--> mögliches "flackern"...)
Es geht hier ja "nur" um eine Anzeige für den User (also nichts wichtiges) - wenn es, warum auch immer, hier zu einem Fehler kommen sollte, dann soll dadurch nicht das Programm behindert werden ...
das ist es nicht, denn wie ich schrieb "Wenn ich durch steppe, so sehe ich das die Eigenschaft zwar auf Visible = true gesetzt wurde, aber es passiert nichts ..." - er geht nicht in eine Exception...
"weil das try/catch so einfach sinnlos und quatsch ist" - meinst Du das generell, oder für diesen Fall ?
Wenn generell, bitte erklären ...
(wenn in diesem Fall, hast Du wohl recht, das ist noch übrig geblieben vom Start-Code - aber schaden tuts ja auch nicht, oder?)