Autor Beitrag
Cäptin Pommes
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Mo 10.09.12 16:03 
Hi leutz,

erstma code :)

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
public string TryToLogin(System.Collections.Generic.Dictionary<string,object> data)
        {
            string result = "";
            network.Login(data);
            network.LoggedIn += new Network.EventHandler(delegate(object sender, LoginEventArgs e)
                                                         {
                                                             if (e.isSuccessful)
                                                                 result = "success";
                                                             else
                                                                 result = e.errorMsg;
                                                         });
            return result;
        }


das dieser code nicht sinnvoll ist weiss ich, er soll auch nur verdeutlichen was ich machen will.
Das Problem is nur das ich nicht weiss wie ich mein vorhaben elegant umsetzten kann.
es würde ja returnt werden bevor result gesetzt wird. Kann man den return aufschieben bis result in der anonymen methode gesetzt wurde? oder gibs vieleicht nen anderen ansatz den ich nehmen sollte?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 10.09.12 16:44 
Du könntest irgendeinen WaitHandle erzeugen der erst im delegaten freigeschaltet wird und natürlich vor dem return abgefragt wird. Als WaitHandle würde sich z.B. AutoResetEvent eignen.

Was ist hier überhaupt der Sinn eines erst mal asynchronen Logins?
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Mo 10.09.12 16:55 
der request von meiner app zum php script(das sich um den eigentlichen login kümmert) ist asynchron
für den request benutz ich eine lib und die macht das nunma asynchron :)
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Mo 10.09.12 18:59 
user profile iconCäptin Pommes hat folgendes geschrieben Zum zitierten Posting springen:
für den request benutz ich eine lib und die macht das nunma asynchron :)

Die macht das aus gutem Grund: So wird nämlich verhindert, dass sich das Programm aufhängt, bis die Seite aufgerufen wurde. Solche Freezes sollte man möglichst vermeiden, da es nach einem Programmfehler aussieht und auch dementsprechend behandelt wird (Windows 7 bietet dann die Möglichkeit an, den Prozess zu beenden).

Wenn du es richtig machen willst, solltest du dich mit ereignisorientierter Programmierung beschäftigen. Dafür musst du in etwa folgendes tun:

  • einen Hinweis, der dem Benutzer zeigt, dass der Anmeldevorgang läuft
  • die Komponenten, die ohne Log-in nicht verfügbar sind, sollten während der Anmeldung deaktiviert sein
  • In das Ereignis, das du im Beispielcode mit einem delegate behandelst, schreibst du den ganzen Code, den du sonst nach Beenden der Methode TryToLogin ausführen würdest, inkl. Ladevorgangs-Hinweis entfernen

Ich denke, das kannst du schaffen. Wenn's irgendwo hakt, einfach weiter fragen :)

Grüße,
Yogu
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 10:23 
@Yogu danke für den hinweis, ich werds versuchen so um zu setzen :)

was die AutoResetEvents angeht ... bin ich mir nich sicher wie ich die anwenden soll.

folgende situation:

Der user betätigt den Login button, der befindet sich in der Login.xaml.cs. Dort wird der vorgang für den Login gestarten in dem über meine Controller klasse die TryToLogin methode aufgerufen wird.

Login.xaml.cs
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
private void loginBtn_Click(object sender, RoutedEventArgs e)
        {
            if (userBox.Text.Length == 0 || pswBox.Password.Length == 0)
                MessageBox.Show(LoginStringRes.emptyLoginMsgBoxMessage, LoginStringRes.emptyLoginMsgBoxTitle, MessageBoxButton.OK);
            else
            {
                Controller.GetController().TryToLogin(userBox.Text, MD5Core.GetHashString(pswBox.Password).ToLower());
            }
        }


der Controller ruft über mein Network objekt nun die eigentliche Login Methode auf und aboniert das event.

Controller.cs
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public void TryToLogin(string username, string psw)
        {
            network.Login(username, psw);
            network.LoggedIn += new Network.EventHandler(network_LoggedIn);
        }

        void network_LoggedIn(object sender, LoginEventArgs e)
        {
            
        }


wie müsste ich jetzt die AutoResetEvents einsetzten damit mein vorhaben funktioniert?


ps: ich hab die Lib wieder rausgeschmissen und selbst den request zum php script geschrieben, die lib hatte aus irgent einem grund nicht über den umweg über meinen controller funktioniert.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 10:49 
Erstmal würde ich die Reihenfolge von Methodenaufruf und EventHandler verdrahten drehen. Wenn das wirklich asynchron ist könnte dein Login sonst fertig sein bevor du den EventHandler verdrahtet hast.
Also erst verdrahten dann Login aufrufen.

Denn AutoresetEvent einbauen hieße

a.) vor dem Login den AutoResetEvent auf blockieren setzen (z.B.über neuerzeugen AutoResetEvent event = new AutoResetEvent(true);
b.) nach dem Login auf das Signalisieren des Events warten event.WaitOne();
c.) Im LoggedIn EventHandler dem Event das Signal senden lassen das man fertig ist event.Set(); (und es damit im anderen Thread an der WaitOne-stelle weitergehen kann).
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 11:52 
ok, ich habs jetzt so versucht:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public string TryToLogin(string username, string psw)
        {
            string result = "";
            AutoResetEvent are = new AutoResetEvent(true);
            network.LoggedIn += new Network.EventHandler(delegate(object sender, LoginEventArgs e)
                                                         {
                                                             if (e.isSuccessful)
                                                                 result = "success";
                                                             else
                                                                 result = e.errorMsg;

                                                             are.Set();  
                                                         });
            network.Login(username, psw);
            are.WaitOne();
            return result;
        }


jedocht return er immer den Leerstring der initalisiert wurde. Wenn ich AutoResetEvent auf false setzte (damit blockiert man doch oder?) bleibt er die ganze zeit blockiert trotz .Set().
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 14:06 
AutoResetEvent(false) wäre richtiger.

Für mich sähe das dann richtig aus. Aber vielleicht habe ich deinen Code drumherum noch nicht verstanden. Der LoggedIn EventHandler wird doch in einem anderen Thread ausgeführt oder?
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 14:12 
naja so siehts aus:

Network.cs
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
public delegate void LoginEventHandler(object sender, LoginEventArgs e);
public event LoginEventHandler LoggedIn;
protected virtual void OnLoggedIn(LoginEventArgs e)
        {
            LoginEventHandler eventCopy = LoggedIn;
            if (eventCopy != null)
            { eventCopy(this, e); }
        }

public void Login(string username, string psw)
        {
            string data = "";
            string extension = String.Format("?user_name={0}&user_psw={1}", username, psw);
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(new Uri(UrlStringRes.api + extension));
            req.BeginGetResponse(delegate(IAsyncResult ar)
                                 {
                                     data = IAsyncResultToString(ar);
                                     if (data != "err")
                                     {
                                         XDocument doc = XDocument.Parse(data);
                                         if (doc.Element("user").Element("error") == null)
                                         {
                                             string userId = (string)doc.Element("user").Element("id");
                                             string userName = (string)doc.Element("user").Element("username");
                                             string userEmail = (string)doc.Element("user").Element("mail");
                                             string portal = (string)doc.Element("user").Element("portal");
                                             string userStatus = (string)doc.Element("user").Element("status");
                                             string active = (string)doc.Element("user").Element("isActive");
                                             Controller.GetController().SetUser(userId, userName, userEmail, userStatus, portal, active);
                                             string temp = Controller.GetController().GetUserData("username");

                                             OnLoggedIn(new LoginEventArgs(truenull));
                                         }
                                         else
                                             OnLoggedIn(new LoginEventArgs(false, ErrorStringRes.userPswNotMatched));
                                     }
                                     else
                                         OnLoggedIn(new LoginEventArgs(false, ErrorStringRes.noConnection));
                                 }, req);
        }


req.BeginGetResponse wird doch glaube ich in einem eigenen thread ausgeführt oder?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 15:48 
Zitat:
req.BeginGetResponse wird doch glaube ich in einem eigenen thread ausgeführt oder?


Ja. Interessanter findest du in der Hilfe zu BeginGetResponse auch gleich ein passendes Beispiel. Dort zwar mit ManualResetEvent anstatt dem AutoResetEvent macht aber eigentlich keinen Unterschied.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 16:10 
o.O
ich habs mir angeguckt aber ich weiss ehrlich gesagt nich was ich nun tun soll ... ich fühl mich regelrecht erschlagen von dem ganzen code ... das was ich hab is ja nur ein bruchteil davon.

heisst das ich soll network.Login(username, psw); in den ThreadPool packen? o.O
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 16:24 
Nein. Der ThreadPool ist nur Statist.

Nein soweit ich deinen Code verstehe müsste das bereits funktionieren. Zumindest sehe ich keinen Fehler. Das Beispiel in der Doku was nur als Hinweis gedacht damit du dir den ansiehst ob du vielleicht etwas siehst was du anderes gemacht hast was sich diesseits des Internets aus den Codefragmenten nicht erschließen lässt.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 17:09 
also hast du keine idee mehr? sämtlichen quellcode der damit zu tun hat hab ich gepostet :/
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 17:33 
Nicht wirklich.

Hast du das den durchdebuggt? Also du hast gesehen das du im WaitOne ankommst und hängenbleibst und dann irgendwann der delegate aufgerufen wird du beim set() vorbeikommst und trotzdem der andere Thread nicht weiter läuft?

Ich kann mir nur Vorstellen das du irgendwas in deinem Code veranstaltest das auch eine Synchronisierung zwischen den beiden Threads benötigt da der Hauptthread aber angehalten ist durch den WaitOne() klappt das nicht. Das müsstest du aber beim debuggen sehen das du nicht bis zum Aufruf von Set() kommst sondern das System vorher hängen bleibt.


Edit: Was passiert in IAsyncResultToString? Greifst du da nochmal auf den WebRequest zu? Könnte mir vorstellen das das problematisch ist.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 17:42 
also es ist so:

er ruft die public void Login(string username, string psw) aber geht nicht in den dortigen delegaten rein bei der BeginGetResponse methode.
deswegen wird auch nie das event geworfen und somit wird dann auch Set() nie aufgerufen. Ich versteh allerdings nich warum er dort nich reigeht wenn er in der methode die zeilen davor schon gemacht hat :/
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 18:12 
Der wird erst aufgerufen wenn die Response zurückkommt. Bekommst du denn überhaupt eine Response auf deine Anfrage? Also wenn du es mal synchron machst anstatt asynchron?
Wenn es da schon keinen return gibt ist das ganze rätseln was danach passiert überflüssig.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 18:27 
ohne den AutoResetEvent oder auch wenn ich den AutoResetEvent auf true setzte geht er ganz normal über all durch. Der AutoResetEvent muss den Response irgentwie blockieren oder so :/
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 11.09.12 18:35 
Wenn du auf  data = IAsyncResultToString(ar); im delegaten einen Breakpoint setzt kommst du da noch hin? Ich habe IAsyncResultToString im Verdacht wen es das nicht ist hab ich dann wirklich keine Idee mehr.
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Di 11.09.12 18:41 
nee leider nicht :(

edit: fals das aus meinen vorherigen Post nicht hervor ging ... es handelt sich dabei um eine WP7.5 app
Cäptin Pommes Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 142
Erhaltene Danke: 2



BeitragVerfasst: Mi 12.09.12 11:56 
ich habe etwas anderes versucht, leider ohne erfolg :/ aber vieleicht hilft es jemanden dabei das problem zu endecken!

Controller.cs
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public string TryToLogin(string username, string psw)
        {
            string result = "";
            network.LoggedIn += new Network.LoginEventHandler(delegate(object sender, LoginEventArgs e)
                                                             {
                                                                 if (e.isSuccessful)
                                                                     result = "success";
                                                                 else
                                                                     result = e.errorMsg;
                                                             });
            Thread t = new Thread(network.Login);
            object userData = username + "/" + psw;
            t.Start(userData);
            t.Join();

            return result;
        }


gleiches resultat ... er führt so den delegate bei der BeginGetResponse methode ... aber wie kann das sein? das läuft doch jetzt in nem komplett anderen Thread o.O