Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Wie kann ich beim Abrufen von Exchange-Properties einen Status oder Ladebalken anzeigen?
SKB
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

Wie kann ich beim Abrufen von Exchange-Properties einen Status oder Ladebalken anzeigen?

beantworten | zitieren | melden

Hallo,
ich lade per EWS einen ganzen Schwung an Mails (>3000) und lasse diese dann in einer e-Mail Liste ablegen, damit ich alle Mails nacheinander bearbeiten kann. Soweit so gut.

Da ich ja dann zu jeder Mail die Eigenschaften brauche, lade ich mit


exchange.LoadPropertiesForItems(emails, GetItemsPropertySet);

die Details vom Server. Leider dauert dies bei dem Haufen an Mails immer eine Weile. Hier würde ich gerne eine Statusmeldung einrichten, die zeigt, wie weit der Abruf schon ist. Ist sowas möglich?

Abholen der Mails sieht so aus:


private List<EmailMessage> CollectMailsAsync()
        {
            FolderId SharedMailbox = new FolderId(WellKnownFolderName.Inbox, g_id);
            SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, true));

            PropertySet FindItemPropertySet = new PropertySet(BasePropertySet.IdOnly);

            bool more = true;
            ItemView view = new ItemView(int.MaxValue, 0, OffsetBasePoint.Beginning);
            view.PropertySet = FindItemPropertySet;
            view.OrderBy.Add(EmailMessageSchema.DateTimeReceived, SortDirection.Ascending);
            
            FindItemsResults<Item> findResults;
            List<EmailMessage> emails = new List<EmailMessage>();
            
            while (more)
            {
                findResults = exchange.FindItems(SharedMailbox, searchFilter, view);

                foreach (var item in findResults.Items)
                {
                    emails.Add((EmailMessage)item);
                    
                }
                more = findResults.MoreAvailable;
                if (more)
                {
                    view.Offset += 1000;
                }
            }
            return emails;
        }

Funktion, um die Eigenschaften der Mails abzuholen:


        private async Task<List<EmailMessage>> PrepareMailsAsync(List<EmailMessage> emails)
        {
            PropertySet GetItemsPropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
            GetItemsPropertySet.RequestedBodyType = BodyType.Text;
            GetItemsPropertySet.BlockExternalImages = true;
            exchange.TraceEnabled = false;
            exchange.LoadPropertiesForItems(emails, GetItemsPropertySet);
            return emails;
        }


Funktion, um die Mails zu bearbeiten:


        public async void FetchNewMail(object sender, EventArgs e)
        {
            if (exchange != null)
            {
                try
                {
                    List<EmailMessage> emailMessages = null;
                    emailMessages = await System.Threading.Tasks.Task.Run(() => CollectMailsAsync());
                    emailMessages = await System.Threading.Tasks.Task.Run(() => PrepareMailsAsync(emailMessages));
                }
            }
        }

Vielen Dank für Eure Zeit!
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1766
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@SKB
Wozu machst du ein await und gleichzeitig Task.Run(), wenn deine Methode doch *Async heißen?
Eigentlich sollten diese einen Task zurückgeben, den du dann per await abarbeiten lässt.
So hast du Methoden, die synchron arbeiten, Async heißen und damit eigentlich andeuten, dass diese asynchron laufen.
Ebenfalls sollten Async Methoden, die Tasks liefern auch async markiert sein.

Da du die Menge an Emails anfangs nicht kennen kannst, wirst du erst eine generische Ladeanzeige anzeigen müssen z.B. mit der Informations, dass die Emails ermittelt werden.
Erst wenn du alle Emails hast, kennst du die Anzahl davon.
Jetzt würde ich jeweils gestaffelt für X Emails die Eigenschaften nachladen.
Damit kannst du dann auch eine entsprechende Anzeige umsetzen.

Müsste dann aber asynchron laufen, damit die UI nicht wieder blockiert.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
SKB
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Hallo Virus,
ich habe das await davor stehen, weil ich sonst einen Compiler Fehler erhalte.

Hast du einen Tipp, wie man dies besser abarbeiten könnte?
private Nachricht | Beiträge des Benutzers
Papst
myCSharp.de - Experte



Dabei seit:
Beiträge: 344
Herkunft: Kassel

beantworten | zitieren | melden

Wie lautet denn dein Compiler Fehler?

Deine Methode "PrepareMailsAsync" heißt zwar Async und ist als Async markiert, ist aber nicht async und gibt vor allem keinen Task zurück. Sollte also in jedem Fall einen Compiler Fehler geben, weil der Rückgabetyp nicht stimmt.
private Nachricht | Beiträge des Benutzers
SKB
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Angepasst habe ich die Tasks nun wie folgt:


private async Task<List<EmailMessage>> CollectMailsAsync()
        {
            FolderId SharedMailbox = new FolderId(WellKnownFolderName.Inbox, g_id);
            SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, true));

            PropertySet FindItemPropertySet = new PropertySet(BasePropertySet.IdOnly);

            bool more = true;
            ItemView view = new ItemView(int.MaxValue, 0, OffsetBasePoint.Beginning);
            view.PropertySet = FindItemPropertySet;
            view.OrderBy.Add(EmailMessageSchema.DateTimeReceived, SortDirection.Ascending);
            
            FindItemsResults<Item> findResults;
            List<EmailMessage> emails = new List<EmailMessage>();
            
            while (more)
            {
                findResults = exchange.FindItems(SharedMailbox, searchFilter, view);

                foreach (var item in findResults.Items)
                {
                    emails.Add((EmailMessage)item);
                    
                }
                more = findResults.MoreAvailable;
                if (more)
                {
                    view.Offset += 1000;
                }
            }
            return emails;
        }

        private async Task<List<EmailMessage>> PrepareMailsAsync(List<EmailMessage> emails)
        {
            PropertySet GetItemsPropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
            GetItemsPropertySet.RequestedBodyType = BodyType.Text;
            GetItemsPropertySet.BlockExternalImages = true;
            exchange.TraceEnabled = false;
            exchange.LoadPropertiesForItems(emails, GetItemsPropertySet);
            return emails;
        }


                    List<EmailMessage> emailMessages = null;
                    emailMessages = await System.Threading.Tasks.Task.Run(() => CollectMailsAsync());

                    // String for High Mail Load
                    string mail_message = emailMessages.Count() + " Emails wurden vom Server eingelesen ";

                    if (emailMessages.Count() > 1000)
                    {
                        mail_message += "und werden nun aufbereitet.\nDies kann einen Moment dauern ...";
                    } else
                    {
                        mail_message += "und werden nun aufbereitet ...";
                    }
                    lblStatus.Text = mail_message;
                    lblStatus.Refresh();
                    emailMessages = await System.Threading.Tasks.Task.Run(() => PrepareMailsAsync(emailMessages));

Meine GUI blockiert nicht und alle Mails werden sauber abgearbeitet. Jedoch fehlt mir noch die Idee, wie ich dort einen Status einbauen kann.
private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 210

beantworten | zitieren | melden

Du hast eine Liste mit Mails, da weißt du die Anzahl.
Anstatt die zusammen in die Methode zu geben, kannst du sie ja einzeln abarbeiten und den Status aktualisieren.

Funktionieren deine Methoden wirklich?! Du gibst ja nicht mal einen Task zurück. Da macht der Aufruf dann halt auch keinen Sinn.


await System.Threading.Tasks.Task.Run(() => PrepareMailsAsync(emailMessages));
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von JimStark am .
private Nachricht | Beiträge des Benutzers
SKB
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Zitat von JimStark
Du hast eine Liste mit Mails, da weißt du die Anzahl.
Anstatt die zusammen in die Methode zu geben, kannst du sie ja einzeln abarbeiten und den Status aktualisieren.

Funktionieren deine Methoden wirklich?! Du gibst ja nicht mal einen Task zurück. Da macht der Aufruf dann halt auch keinen Sinn.


await System.Threading.Tasks.Task.Run(() => PrepareMailsAsync(emailMessages));

Ja, sie funktionieren. Wenn ich die Mails einzeln abarbeite, muss ich ja alle 3000 Mails wieder einzeln an den Server schicken. So habe ich gedacht, das eine komplette Abfrage ok ist.

Kannst Du mir noch beantworten: Wieso muss ich denn einen Task zurückgeben?

Danke :-)
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1766
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@SKB
Weil Async Methoden immer einen Task/Value Task zurückgeben müssen.
Sonst deuten diese eine asynchrone Verarbeitung an, die sich nicht leisten.
Ist aber Teil der Programmierung mit Tasks über async/await.
Solltest du dir ggf. nochmal anschauen, wie es richtig gemacht wird.
Spätestens jetzt wo du in der UI arbeitest, solltest du die Tasks auch richtig anwenden.

Nachtrag:
Ich hatte oben auch schon den Hinweis gegeben, dass du deine Emails gestaffelt an den Server senden sollst.
Dadurch sparst du dir viele Roundtrips zwischen dir und dem Server und der Server muss nicht jede Email einzeln abfragen bzw. deren Eigenschaften.
Teste hier am besten aus, ab welcher Menge die Dauer zum abfragen der Eigenschaften noch kurz genug ist und dann hast du schon einen guten Ansatz.

T-Virus
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von T-Virus am .
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers