Autor Beitrag
Viperos
Hält's aus hier
Beiträge: 2



BeitragVerfasst: So 26.02.17 13:50 
Hallo,

zuerst einmal möchte ich mich entschuldigen das mein erster Post direkt so groß ist, aber ich sitze an diesem Problem schon eine ganze Weile und komme damit absolut nicht weiter und bräuchte deswegen etwas Unterstützung.
Falls dieser Beitrag in den falschen Themenbereich gerutscht ist wegen der "Komplexität" (UWP/Xaml/System.Net), sorry.

Ich habe eine Webseite von der ich den Content lesen möchte. Zu diesem Zweck muss ich, da es HTTPS ist, mich mit Benutzername und Password anmelden.

Die Software ist in erster Linie ein Windows 10/UWP App, soll aber später um weitere Plattformen erweitert werden.
Aufgrund des Crossplattformsupports war der Plan das Vorhaben mittels System.Net.Http.HttpClient zu lösen.

Dabei ist aber aufgefallen das sich der Client nicht wie für mich erwartet verhält.
Folgender Versuchsaufbau:

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:
var url = new UriBuilder("https://localhost:443/history");
                var userName = "UserName";
                var password = "Password";
                var delay = TimeSpan.FromSeconds(30);
                var delaySecondRequest = true;

                using (var handler = new HttpClientHandler())
                {
                    handler.Credentials = new NetworkCredential()
                    {
                        UserName = userName,
                        Password = password
                    };

;                    using (var client = new HttpClient(handler))
                    {
                        using (var request = new HttpRequestMessage(HttpMethod.Post, url.Uri))
                        using (var response = await client.SendAsync(request).ConfigureAwait(false))
                        {

                        }

                        if(delaySecondRequest)
                            await Task.Delay(delay).ConfigureAwait(false);

                        using (var request = new HttpRequestMessage(HttpMethod.Post, url.Uri))
                        using (var response = await client.SendAsync(request).ConfigureAwait(false))
                        {

                        }
                    }
                }


Das Problem was ich habe ist folgendes.
Der erste Request wird mir mit einem OK quitiert, also sind die Credentials auch OK.

Das Problem macht der zweite Request, dort bekomme ich ein 401 zurück geliefert obwohl die Credentials identisch sind.
Warte ich nun zwischen den zwei Requests nicht so ist der zweite Request auch OK. (Vermutlich gecached?!)

Über Fiddler kann man sehen dass der erste Request ankommt und mit einem 401 quitiert wird. Als Antwort darauf schickt der Client die selbe Anfrage. Aber diesmal mit Authentication-Header. An dieser stelle hat der Request den StatusCode 200 und ich kann den Content abgreifen. Soweit denke ich ist das ok.

Jetzt ist es jedoch so das jeder weitere Request, ob mit warten oder nicht, nicht bis zum Server weitergereicht wird obwohl ich im Code die Response sehe. Ich würde daraufhin von einem Cache ausgehen aus dem die erste Anfrage gezogen wird.

Daraufhin habe ich den selben Code in einem .Net Projekt untergebracht wo er mit warten oder nicht auch anstanzlos und wie erwartet funktioniert.


Nach weiteren Recherchen bin ich dann auf Windows.Web.Http.HttpClient gestoßen welcher wohl die native Win10 API bedient.
In Analogie dazu folgender Code:

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:
var url = new UriBuilder("https://localhost:443/history");
                var userName = "UserName";
                var password = "Password";
                var delay = TimeSpan.FromSeconds(30);
                var delaySecondRequest = true;

using (var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter())
                {
                    filter.ServerCredential = new Windows.Security.Credentials.PasswordCredential() {
                        Password = password,
                        UserName = userName
                    };

                    using (var client = new Windows.Web.Http.HttpClient(filter))
                    {
                        using (var request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, url.Uri))
                        using (var response = await client.SendRequestAsync(request).AsTask().ConfigureAwait(false))
                        {

                        }

                        if (delaySecondRequest)
                            await Task.Delay(delay).ConfigureAwait(false);

                        using (var request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, url.Uri))
                        using (var response = await client.SendRequestAsync(request).AsTask().ConfigureAwait(false))
                        {

                        }
                    }
                }


Hier ist es so das sowohl der erste Request als auch der zweite den StatusCode OK haben. der erste wurde jedoch übers Network geschoben während der zweite ganz klar aus dem Cache kommt.

Die CacheControl habe ich schon veränder was zu keiner Änderung geführt hat. Auch habe ich versucht der URL einen Dummywert mitzugeben damit sich die Url bei jedem Aufruf unterscheided. Auch dies brachte keine Veränderung.

Nur ist mein Problem das im Unterschied zu System.Net.Http, Windows.Web.Http nicht Crossplatform ist und mir, wenn ich Windows.Web.Http verwenden muss, wohl die ganzen Klassen neu, oder Adapter schreiben muss. (Neuerfindung des Rades.)

Jetzt meine Frage:
Warum ist das verhalten bei beiden Clients so unterschiedlich obwohl sie in der selben App laufen?
Und ganz wichtig ist es irgendwie möglich das Caching der Credentials unter System.Net.Http abzuschalten damit man neue Credentials verwenden kann?
Oder ist die Verwendung von Windows.Web.Http in einer UWP App zwingend?


So, das wars nun erstmal. Ich hoffe das ihr mir weiter helfen könnt.


Moderiert von user profile iconTh69: Topic aus WPF / Silverlight verschoben am So 26.02.2017 um 13:40
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18727
Erhaltene Danke: 1628

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 26.02.17 21:32 
Die einfachste Variante solch ein Caching zu vermeiden ist einfach an die URL bei jedem Aufruf einen zusätzlichen zufälligen Parameter anzuhängen. Also zum Beispiel:
localhost:443/history?random=33665
Viperos Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: So 26.02.17 21:37 
@jaenicke

Das hatte ich mir auch so gedacht. Dem ist zumindest hier in der UWP App nicht so. Ich denke eine neue Guid sollte die URL hinreichend verändern damit der Cache umgangen wird.



Der vollständigkeithalber hier noch die Header:

ausblenden volle Höhe 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:
41:
42:
43:
44:
45:
################################################################################################

POST https://localhost:443/history/ HTTP/1.1
Host: localhost:443
Content-Length: 0
Connection: Keep-Alive

HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 170
Content-Type: text/html; charset=utf-8
Pragma: no-cache
Server: Webserver
WWW-Authenticate: Digest realm="HTTPS Access",nonce="E25BD15C0C71BA3E",algorithm=MD5,qop="auth"


POST https://localhost:443/history/ HTTP/1.1
Host: localhost:443
Content-Length: 0
Connection: Keep-Alive
Authorization: Digest username="UserName",realm="HTTPS Access",nonce="E25BD15C0C71BA3E",uri="/history/",cnonce="596d0e682be9788b40a445a4a7ac6ae1",nc=00000001,algorithm=MD5,response="2e74cc20ecdb886549448535f54933d0",qop="auth"

HTTP/1.1 200 OK
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-type: text/html; charset=iso-8859-1
Keep-Alive: timeout=60, max=300

################################################################################################

POST https://localhost:443/history/ HTTP/1.1
Host: localhost:443
Content-Length: 0
Connection: Keep-Alive
Authorization: Digest username="UserName",realm="HTTPS Access",nonce="E25BD15C0C71BA3E",uri="/history/",cnonce="596d0e682be9788b40a445a4a7ac6ae1",nc=00000002,algorithm=MD5,response="e9207f7930d304fa8f98a43fd73efac2",qop="auth"

HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 170
Content-Type: text/html; charset=utf-8
Pragma: no-cache
Server: Webserver
WWW-Authenticate: Digest realm="HTTPS Access",nonce="50227B3F0B60C51F",algorithm=MD5,qop="auth"

################################################################################################