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

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von Chronos
Thema: Werte in einer ObservableCollection berechnen
Am im Forum: Grundlagen von C#

Also um Ehrlich zu sein mir erschließt es sich auch nicht so recht.
Zumal sich die Aufgabenstellung im Vergleich zum Initialpost geändert hat.
Wenn ichs richtig sehe sind wir jetzt bei der Parallelschaltung wo wir vorher nur bei der Reihenschaltung waren?

Wenn dein User diese Werte eingibt ist es klar das die dann auch in der Liste "gespeichert" sind.
Aber das Beispiel liefert z.B. kein Ergebnis der Kalkulation damit man mal sehen kann ob das Ergebnis am Ende erwartungsgemäß wäre.

Thema: Wie kann ich eine Http API mit Auth Testbar machen?
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo,

zunächst einmal, gegoogelt habe ich nach meine Fragestellung aber konkret finden konnte ich dazu bisher nix.


Ich versuche gerade mittels Http(Client|MessageHandler) eine API umzusetzen.
Sinn ist es mittels Digest Auth auf einem Server per SSL Daten abzufragen.
Das funktioniert auch schon.

Ich mache mir nun Gedanken darüber wie man die implementierten Clients UnitTestbar machen kann.
Erster Gedanke war das per HttpMessageHandler zu realisieren der im Konstruktor eines jeden Clients mitgegeben wird (evtl. auch mit Credentials).
Würde soweit auch funktionieren.
In Tests habe ich aber festgestellt das im funktionalen Einsatz unter Realbedingungen es so ist das für jede Abfrage auch automatisch eine neue Anmeldung am Server gemacht wird.
Ich wäre davon ausgegangen das dies nur beim ersten Request passieren würde und für jeden weiteren Request dann nicht mehr, da der Händler für jeden Request der selbe ist.


Jetzt bin ich beim Lesen auf den Hinweis gestoßen das man einen HttpClient am besten static haben sollte.
Drum dachte ich mir das der Client evtl. irgendwelche Sessions oder ähnliches zwischenspeichert von denen er ausgehen könnte nach der ersten Anmeldung wäre keine weiter mehr notwendig.
Aber auch bei der Implementierung mit einem static HttpClient zeichnet sich das selbe Bild ab.

Jetzt ist für mich die Frage:

#1: Ist das in diesem Fall evtl. die Implementierung/Handling am Server die/das die Auth nicht über Requests hinweg funktioniert lässt.
#2: Wenn das so ist kann ich in diesem Fall nichts daran ändern, aber um spätere größere Änderungen zu vermeiden wäre meine Frage was besser wäre?

Für jede Aktion auf der C# API einen Client oder einen Handler mitzugeben auf dem die Requests gemacht werden?
Bauchgefühl sagt Handler wegen der Testbarkeit.
Nur kann ich aufgrund mangelnder Erfahrung mit HTTP nicht abschätzen ob es equivalent wäre einen Handler oder Client mitzugeben, gerade im Bezug auf das Führen von möglichen Sessions.
Was meint ihr?

Thema: Kann man Standard-Events vom UserControl entfernen
Am im Forum: GUI: Windows-Forms

Moinsen,

kurze Antwort: Nö, bei Events schonmal garnicht. Das einzige was "funktionieren" würde wären Methoden und Properties wenn diese überschreibbar sind zu versiegeln und mit EditorBrowsableAttribute zu attributieren.

Aber davon würde ich absolut abraten.
Mir würde wirklich kein Szenario einfallen in dem man sowas machen sollte/würde.

Ich meine warum sollten die Events mit vererbt werden wenn sie nicht an irgendeiner Stelle gebraucht werden (z.B. Resizing, Loading etc.).

Thema: Fenster skalieren nur für die Höhe erlauben
Am im Forum: GUI: WPF und XAML

Wieso so kompliziert?

Dem Window SizeToContent=WidthAndHeight mitgeben und dann im Loaded Event zunächst die MinWidth, MaxWidth und MinHeight auf die aktuellen Werte setzen sowie zum Abschluss den SizeToContent wieder auf Manual.

Es muss ja nur erstmal die Anpassung an den Content erfolgen um die Werte zu setzen.

Thema: PS Fritz!Box API - TR-064 Schnittstelle
Am im Forum: .NET-Komponenten und C#-Snippets

Hauptsächlich geht's dabei ums ExceptionHandling und ums "Timing" sprich das auf den Abschluss des Tasks gewartet wird was in deinem o.g. Beispiel nicht der Fall war und zu dem Fehler führte.

Wenn du Fiddler nebenher laufen lässt siehst du auch das der Request unvollständig ist.

Siehe: https://msdn.microsoft.com/magazine/jj991977

Thema: [gelöst] ListBox dynamisch an Fenstergröße Anpassen
Am im Forum: GUI: WPF und XAML

Luxusproblem...Na klasse, das auch noch...wie immer... :tongue:

Dann versuch doch mal deiner Listbox ein VerticalAlignment=Top mitzugeben.

Wenn ich das richtig verstanden habe sollte dies das Luxusproblem lösen.

Thema: [gelöst] ListBox dynamisch an Fenstergröße Anpassen
Am im Forum: GUI: WPF und XAML

Wachsen?

Da wächst nichts mehr außerhalb des verbliebenden Platzes.

Mit dem Entfernen der Height setzt du die Höhe auf ihren Default (* |Nutze den verfügbaren Platz) während Auto bedeutet das die Höhe vom Control bestimmt wird.
Bei einem ItemsControl wie der ListBox wäre das die max. Anzahl an Elementen.

Thema: Wie kann ich dynamisch Controls zu einem StackPanel hinzufügen?
Am im Forum: GUI: WPF und XAML

Du versuchst das ControlTemplate zu ändern. Was du hier brauchst ist das ItemTemplate. Nur damit kannst du das Aussehen der Items ändern.

Thema: [gelöst] ListBox dynamisch an Fenstergröße Anpassen
Am im Forum: GUI: WPF und XAML

Naja,
Bei so vielen Angaben für Hight und MinHeight ein dynamisches Layout (Ich gehe mal davon aus dass das am Ende das Ergebnis sein soll) herauszubekommen ist schon eine Herausforderung.
Da setzt man nur mal in einer Zeile die falsche Höhe, da ist man dann erstmal am Suchen.

Mit Container meine ich dein Grid.
Denkbar wäre statt dessen z.B. nen DockPanel bzw. je nach Komplexität des Layouts auch nen Mix.

Also wenn du zwingend die ganzen Zeilen so brauchst, dann entferne mal die Height der vorletzten RowDefinition.

Thema: [gelöst] ListBox dynamisch an Fenstergröße Anpassen
Am im Forum: GUI: WPF und XAML

Moin moin,

dein Problem dürften die ganzen Row und ColumnDefinitionen sein.
Die sind der beschränkende Faktor für die ListBox.

Brauchst du fürs Layout überhaupt so viele Zeilen und Spalten?
Ansonsten vielleicht mal mit nem anderen Container versuchen.

Thema: PS FritzBox NetzwerkMonitor
Am im Forum: Projekte

Ne fehlerhafte Konfiguration kann natürlich möglich sein, obgleich ich es bei mir nicht vermute, denn andere Tools die auch die TR064-Schnittstelle nutzen kommen an die Daten der selben FritzBox. Dabei ists egal ob LAN oder Remote.

Thema: PS FritzBox NetzwerkMonitor
Am im Forum: Projekte

Das ist korrekt.

Die einzige Möglichkeit für mich an die Daten der FritzBox zu kommen besteht das Tool auf

https://<InsertDynDNSOrIPHere>:<InsertHttpsPortHere>
zu konfigurieren. Damit beziehe ich mich auf die Verwendung der Debugversion.
Im LAN ist weder über den Port 49000 (Http) noch 49443 (Https) an Daten zu kommen.

Thema: PS FritzBox NetzwerkMonitor
Am im Forum: Projekte

Also der Internal Server Error per Http ist für mich reproduzierbar.
Es wird der Service auf der FritzBox nicht gefunden wenn man über LAN zugriff nimmt.
Remote über den TCP-Port für HTTPS funktionierts.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Dank für den Hinweis, werd ich berücksichtigen.


Soweit habe ich es jetzt auch zum funktionieren gebracht. Es funktioniert aber nur mit ClearAuthenticationCache

Was ich nur noch nicht ganz verstehe ist:

HttpBaseProtocolFilter.CacheControl.ReadBehavior/WriteBehavior kann man ja die Werte HttpCacheReadBehavior.NoCache/HttpCacheWriteBehavior.NoCache zuweisen. Also für mein Verständnis müsste man doch auch damit verhindern können den Cache zu nutzen. Oder verstehe ich das falsch?

Ich finde es schon ein wenig merkwürdig solch eine in meinen Augen Elementare Funktion nachzuliefern so dass man dafür die Targetversion anheben muss. Oder ist es so unüblich geworden sich auch mal abzumelden? Und ja, die Frage ist ernst gemeint ^^

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Ok, habs jetzt nochmal mit dem Windows.Web.HttpClient versucht.

Interessanter weise ploppt trotz setzen von AllowUI auf false ein AnmeldeDialog auf.

Was zu bemerken war ist, das sich dieser Client ähnlich wie die anderen Lösungen verhielt.
Sprich,
Alle <30 Sekunden ein Request, StatusCode: 200.
>30 Sekunden: StatusCode: 401 mit Dialog zur Anmeldung.

Auch habe ich zusätzlich noch die Capability Privat Networks (Client & Server) wie in dem verlinkten Beitrag erwähnt hinzugefügt.

Hier ist der Code:


private async Task TryItWithHttpClient2Async(string userName, string password)
        {
            for (int i = 0; i < 40; i++)
            {
                using (var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter())
                {
                    
                    filter.AllowUI = false;
                    filter.ServerCredential = new Windows.Security.Credentials.PasswordCredential()
                    {
                        UserName = userName,
                        Password = password,
                        Resource = "fritz.box"
                    };
                    using (Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient())
                    {
                        string url = null;
                        using (var message = new Windows.Web.Http.HttpRequestMessage())
                        {
                            message.Method = new Windows.Web.Http.HttpMethod("POST");
                            message.RequestUri = new Uri("http://fritz.box:49000/upnp/control/x_contact");
                            message.Content = new Windows.Web.Http.HttpStringContent(
                                "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap-env:Envelope encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap-env:Body><GetCallList xmlns=\"urn:dslforum-org:service:X_AVM-DE_OnTel:1\" /></soap-env:Body></soap-env:Envelope>",
                                Windows.Storage.Streams.UnicodeEncoding.Utf8,
                                "text/xml");
                            message.Headers.Add("SOAPAction", "urn:dslforum-org:service:X_AVM-DE_OnTel:1#GetCallList");
                            using (var responseMessage = await client.SendRequestAsync(message))
                            {
                                Debug.WriteLine($"{message.RequestUri}, StatusCode: {responseMessage.StatusCode}");
                                if (responseMessage.IsSuccessStatusCode)
                                {
                                    using (var responseInputStream = await responseMessage.Content.ReadAsInputStreamAsync().AsTask())
                                    {
                                        using (var responseStream = responseInputStream.AsStreamForRead())
                                        {
                                            using (var responseStreamReader = new StreamReader(responseStream))
                                            {
                                                var soapXml = await responseStreamReader.ReadToEndAsync();
                                                var xml = new XmlDocument();
                                                xml.LoadXml(soapXml);

                                                var newCallListURL = xml.SelectSingleNodeNS("//s:Envelope/s:Body/u:GetCallListResponse/NewCallListURL", "xmlns:s='http://schemas.xmlsoap.org/soap/envelope/' xmlns:u='urn:dslforum-org:service:X_AVM-DE_OnTel:1'");
                                                url = newCallListURL?.InnerText;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (url != null)
                        {
                            Uri uri = new Uri(url);
                            Debug.WriteLine($"URL: {uri}");
                            using (var responseMessage = await client.GetAsync(uri))
                            {
                                Debug.WriteLine($"URL: {uri}, StatusCode: {responseMessage.StatusCode}");
                                if (responseMessage.IsSuccessStatusCode)
                                {
                                    var callListSerializer = new XmlSerializer(typeof(AVMCallList));
                                    using (var responseInputStream = await responseMessage.Content.ReadAsInputStreamAsync())
                                    {
                                        using (var responseStream = responseInputStream.AsStreamForRead())
                                        {
                                            var callList = callListSerializer.Deserialize(responseStream) as AVMCallList;
                                            if (callList != null)
                                            {
                                                Debug.WriteLine($"Calls: { callList.Calls.Count }");
                                            }
                                        }
                                    }

                                }
                            }
                        }
                    }
                }
                int delay = i * 1000;
                Debug.WriteLine($"Wartezeit: { delay / 1000 } Sekunde(n).");
                await Task.Delay(delay);
            }
        }

Jetzt habe ich aber gesehen das es mit Build 12295 in diesem Szenario eine Möglichkeit gibt den Cache auch zu leeren. *Heureka*

Dies geschieht mittels:

filter.ClearAuthenticationCache();

Jetzt verhält sich der Client ansatzweise wie erwartet. Unabhängig von der ersten Anmeldung werde ich jetzt jedesmal nach Credentials gefragt.
Trotz wie gesagt AllowUI=false. Fast so als könne er mit den mitgegebenen Credentials noch nix anfangen. Ich habe für den Resourcennamen verschiedene Werte ausprobiert, jedoch ohne Erfolg.

Ausprobiert habe ich die Werte:

fritz.box
fritz.box:49000
fritz.box:49000/[UPnP-Path]
http://fritz.box
http://fritz.box:49000
http://fritz.box:49000/[UPnP-Path]

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Sorry das nicht gleich eingangs erwähnt zu haben.


Was den Code angeht so sind die Klassen zwar alle vorhanden. Aber beim ausführen des Requests kommt es wieder zu einer PlatformNotSupportedException mit der Message:

The value 'System.Net.CredentialCache' is not supported for property 'Credentials'.

Aber da es sich hier auch wieder um eine PlatformNotSupportedException handelt und der Vollständigkeitshalber, kann es evtl. mit der Targetplatform zutun haben?

Target: Universal Windows
Target Version: Windows 10 (10.0; Build 10240)
Min Version: Windows 10 (10.0; Build 10240)

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Interessanterweise ist die Exception die ich beim setzten von HttpClientHandler.PreAuthenticate auf false bekomme vom Typ:

System.PlatformNotSupportedException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

Message:
The value 'False' is not supported for property 'PreAuthenticate'.

Aber wie kann sein das diese Funktion nicht unterstützt wird?

Die App ist eine Windows 10 UWP App. Windows ist Fully updated.

Capabilities der App:
- Internet (Client)
- Microphone
- Private Networks (Client & Server)

Beim Googlen nach den Schlagwörtern PlatformNotSupportedException und PreAuthenticate bin ich dabei auf folgenden Link gestoßen:
Link

Dort ist folgender Code zu finden der zumindest ansatzweise erklären würde warum ich diesen Fehler bekomme:


        public bool PreAuthenticate
        {
            get { return true; }
            set
            {
                if (value != PreAuthenticate)
                {
                    throw new PlatformNotSupportedException(String.Format(CultureInfo.InvariantCulture,
                        SR.net_http_value_not_supported, value, nameof(PreAuthenticate)));
                }
                CheckDisposedOrStarted();
            }
        }

Ob der Code allerdings 1:1 dem von MS entspricht weis ich leider nicht da ich den Code ja nicht Debuggen kann.

Es wirft für mich aber die Frage auf warum die Möglichkeit zwar gegeben ist es abzuschalten man aber nicht gelassen wird.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Aber dann müsste ich doch aber auch mit Reflection dazu in der Lage sein mir die PropertyInfo geben zu lassen?

var preAuthenticateProperty = request.GetType().GetProperty("PreAuthenticate");
gibt mir null zurück.

Auch mit

var properties= request.GetType().GetProperties();
bekomme ich PreAuthenticate auch nicht angezeigt.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Ja nur das lustige daran ist ja das der HttpClientHandler besagtes Property hat, und ich ihm den Wert False zuweisen kann. Laut der Exception die ich dann aber bekomme ist nur true erlaubt.

Und HttpWebRequest hat dieses Property bei mir garnicht erst obwohl es laut MSDN da sein sollte.

Ich verstehe das nicht.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Da bekomme ich folgende Exception geworfen:

The value 'System.Net.CredentialCache' is not supported for property 'Credentials'.

Ich habe nochmal die Doku der Api durchforstet

In dem Dokument AVM TR-064 first steps gibt es folgende Passage:
The default authentication mechanism is HTTP authentication using digest (MD5 hashes). Alternatively an authentication on content level is supported.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Was ja auch der Fall ist.
Eine InnerException gibt's jedoch nicht.
Die Message der Exception:

The remote server returned an error: (401) Unauthorized.


Wie sieht das denn mit PreAuthenticate=false aus? Lässt sich das irgendwie setzen. Laut Doku soll HttpWebRequest genauso wie HttpClientHandler auch besagtes Property haben. IntelliSense sagt mir jedoch das die Eigenschaft nicht vorhanden ist.

Das setzen der Eigenschaft im HttpClientHandler führt bei mir zumindest zu einer Exception (siehe oben).

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Interessanterweise verhält sich der HttpWebRequest genau so wie der HttpClient.

Bei der Ersten Anfrage werden keine Credentials geschickt und ich bekomme den StatusCode 401. Dann wiederholt sich der Request aber diesmal mit Credentials. Ab da bekomme ich dann nurnoch den StatusCode 200. setze ich die Requests für 30 Sekunden + aus, bekomme ich nurnoch 401.

Dies ist der Code zum reproduzieren.

private async Task TryItWithHttpWebRequestAsync(string userName, string password)
        {
            try
            {
                for (int i = 0; i < 40; i++)
                {
                    string url = null;
                    Uri soapUri = new Uri("http://fritz.box:49000/upnp/control/x_contact");
                    var soapRequest = (HttpWebRequest)WebRequest.Create(soapUri);
                    soapRequest.Credentials = new NetworkCredential(userName, password);
                    soapRequest.Headers["SOAPAction"] = "urn:dslforum-org:service:X_AVM-DE_OnTel:1#GetCallList";
                    soapRequest.ContentType = "text/xml;charset=\"utf-8\"";
                    soapRequest.Method = HttpMethod.Post.Method;
                    using (var soapRequestStream = await soapRequest.GetRequestStreamAsync())
                    {
                        var bytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap-env:Envelope encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap-env:Body><GetCallList xmlns=\"urn:dslforum-org:service:X_AVM-DE_OnTel:1\" /></soap-env:Body></soap-env:Envelope>");
                        await soapRequestStream.WriteAsync(bytes, 0, bytes.Count());
                    }

                    using (var soapResponse = (HttpWebResponse)await soapRequest.GetResponseAsync())
                    {
                        Debug.WriteLine($"URL: {soapUri}, StatusCode: {soapResponse.StatusCode}");
                        if (soapResponse.StatusCode == HttpStatusCode.OK)
                        {
                            using (var responseStream = soapResponse.GetResponseStream())
                            {
                                using (var responseStreamReader = new StreamReader(responseStream, Encoding.UTF8))
                                {
                                    var soapXml = await responseStreamReader.ReadToEndAsync();
                                    var xml = new XmlDocument();
                                    xml.LoadXml(soapXml);

                                    var newCallListURL = xml.SelectSingleNodeNS("//s:Envelope/s:Body/u:GetCallListResponse/NewCallListURL", "xmlns:s='http://schemas.xmlsoap.org/soap/envelope/' xmlns:u='urn:dslforum-org:service:X_AVM-DE_OnTel:1'");
                                    url = newCallListURL?.InnerText;
                                }
                            }
                        }
                    }

                    if (url != null)
                    {
                        Uri getUri = new Uri(url);
                        var getRequest = (HttpWebRequest)WebRequest.Create(getUri);
                        getRequest.Method = HttpMethod.Get.Method;
                        using (var getResponse = (HttpWebResponse)await getRequest.GetResponseAsync())
                        {
                            Debug.WriteLine($"URL: {getUri}, StatusCode: {getResponse.StatusCode}");
                            if (getResponse.StatusCode == HttpStatusCode.OK)
                            {
                                var serializer = new XmlSerializer(typeof(AVMCallList));
                                using (var getResponseStream = getResponse.GetResponseStream())
                                {
                                    var callList = serializer.Deserialize(getResponseStream) as AVMCallList;
                                    if (callList != null)
                                    {
                                        Debug.WriteLine($"Calls: {callList.Calls.Count}");
                                    }
                                }
                            }
                        }
                    }

                    int delay = i * 1000;
                    Debug.WriteLine($"Wartezeit: { delay / 1000 } Sekunde(n).");
                    await Task.Delay(delay);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Was ich ja noch gerne ausprobiert hätte:
Der HttpClientHandler hat eine Eigenschaft namens PreAuthenticate vom Typ Boolean.

Der Standartwert ist true.

Wenn ich diesen Wert auf False ändere sollte laut diesen Blogs wohl gewünschtes Verhalten möglich sein.

Nur wenn ich den Wert False setzte bekomme ich folgende Exception:

The value 'False' is not supported for property 'PreAuthenticate'.

Ich werde jetzt mal versuchen das ganze per WebRequest zu bewerkstelligen um dann nochmal zu schauen obs sich da ähnlich verhält.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Die Frage ist ja überhaupt warum der Client nur beim ersten mal eine Anfrage ohne Credentials macht, danach die selbe Anfrage automatisch nochmal mit Credentials macht. Um dann mit einer Wartezeit von 30 Sekunden direkt mit dem StatusCode 401 zurück kommt.

Für mein Verständnis müsste es doch eigentlich so sein.

Vorgang #1:
Anfrage ohne Credentials -> 401
Automatiches neuanfragen mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Vorgang #2:
Anfrage ohne Credentials -> 401
Automatiches neuanfragen mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Vorgang #3:
Anfrage ohne Credentials -> 401
Automatiches neuanfragen mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Wartezeit: 30 Sekunden

Vorgang #n:
Anfrage ohne Credentials -> 401
Automatiches neuanfragen mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

usw....
Unter der Prämisse das jeder Vorgang vom vorangegangenen Vorgang den StatusCode nicht kennt.
Also so als ob jedes mal ein frischer und unbenutzter Client genutzt wird was ja doch eigentlich der Fall sein sollte wenn ich den Client nach jedem Vorgang Dispose. Zumindest nach meinem Verständnis.


Stattdessen:

Anfrage #1:
Anfrage ohne Credentials -> 401
Automatiches neuanfragen mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Anfrage #2:
Anfrage mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Anfrage #3:
Anfrage mit Credentials -> 200
Get ohne Credentials dafür aber mit SID -> 200

Wartezeit: 30 Sekunden

Anfrage #n:
Anfrage mit Credentials -> 401
Get wird nicht mehr ausgeführt.


Für mich sieht das so aus das er nicht jedesmal neue Credentials mitschickt sondern diese aus dem Cache nutzt. Und diese haben eine Verfallszeit von 30 Sekunden wenn sie nicht in diesem Zeitfenster verlängert werden.

Ich könnte mir vorstellen das eine Lösung des Problems sein könnte bei jedem Request gleich die frischen Credentials mitzuschicken.

Nur wie?

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Der erste Request geht ohne Auth-Header an: http://fritz.box:49000/upnp/control/x_contact
StatusCode: 401

Dann schickt der Client von sich aus erneut jedoch mit Auth-Header (siehe oben) an:http://fritz.box:49000/upnp/control/x_contact
StatusCode: 200

Danach findet der Get-Request ohne Auth-Header statt:http://fritz.box:49000/calllist.lua?sid=******************
StatusCode: 200

Das ist ein Durchlauf.

Mehr mache ich da nicht. Die SID wird nicht angetastet außer beim Get-Request ausgelesen/übernomen.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Ja das schon, nur halte ich die sid nicht für das Problem. Die wird ja nur für die Get-Anfrage benötigt. Wenn ich den StatusCode 401 bekomme komme ich ja garnicht erst zum Get.

Die Exception bekomme ich immer beim Soap-Call. Aber nur dann wenn mehr als 25 Sekunden zum vorherigen Request vergangen ist. Und das kann ich nicht recht zuordnen.

In dem Soap-Request habe ich auch nirgends was von der Sid, an stelle dessen bekomme ich den Authentication-Header

Authorization: Digest username="UserName",realm="HTTPS Access",nonce="****************",uri="/upnp/control/x_contact",cnonce="*********************",nc=00000019,algorithm=MD5,response="*********************",qop="auth"

Danach bekomme ich erst den Link mit der Sid die laut AVM-Doku 60 Minuten gültig ist.


Eine andere Möglichkeit wäre evtl. noch dem Envelope einen Auth-Header mitzugeben. Aber dann übernehme ich ja eigentlich die Arbeit die meiner Meinung nach der Client machen sollte/würde wenn ich ihm schon die Credentials mitgebe.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Die SID wird ja bei dem Vorgang on the Fly erstellt und ist dann 20Min gültig. Von dem Aspekt her sollte das kein Problem mit der vergangenen Zeit sein.

Das selbe Problem habe ich auch. Seit dem neuen Seitenlayout kann man noch nichtmal mehr den html-code zerlegen da das alles auf Ajax beruht.

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Ah auch schonmal was für die Fritte gemacht ? ;D


Dass das supobtimal ausschaut weis ich. Ist ja auch nur zum provozieren des Fehlers ohne das Beispiel unnötig kompliziert zu machen. Solch eine Session-Klasse nutze ich auch. Diese aber hauptsächlich zum validieren der Credentials.

Ich weis das ich mit der erstellten SID auch den Link direkt abrufen oder die csv herunterladen könnte. Jedoch was wenn sich der Pfad dorthin ändert? Und die CSV enthält nicht die Infos die meine App benötigt.Außerdem wollte ich dokumentierte APIs nutzen. Sprich TR-064. Und da läuft das dann ein wenig anders. Es funktioniert ja eigentlich auch wenn das Problem mit dem 401 nicht wäre.Und das liegt ja wohl an dem caching der Credentials im Client.

Lade mir den Pfad zur Liste, lade die Liste und jage sie dann einmal durch den XmlSerializer. Fertig, eigentlich.... ^^

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Reproduzieren kann ich das Verhalten mit folgendem Code:


private async Task TryItAsync(string userName, string password)
        {
            try
            {
                string soap = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap-env:Envelope encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap-env:Body><GetCallList xmlns=\"urn:dslforum-org:service:X_AVM-DE_OnTel:1\" /></soap-env:Body></soap-env:Envelope>";
                string action = "urn:dslforum-org:service:X_AVM-DE_OnTel:1#GetCallList";
                Uri uri = new Uri("https://fritz.box:49443/upnp/control/x_contact");

                for (int i = 0; i < 4; i++)
                {
                    
                    using (var handler = new HttpClientHandler())
                    {
                        handler.Credentials = new NetworkCredential(userName, password);
                        using (var client = new HttpClient(handler))
                        {
                            string url = null;
                            using (HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, uri))
                            {
                                message.Version = new Version("1.0");
                                message.Content = new StringContent(soap, Encoding.UTF8, "text/xml");
                                message.Headers.Add("SOAPAction", action);
                                using (var responseMessage = await client.SendAsync(message))
                                {
                                    Debug.WriteLine($"#1 Request StatusCode: {responseMessage.StatusCode}");
                                    if (responseMessage.IsSuccessStatusCode)
                                    {
                                        using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
                                        {
                                            using (var responseStreamReader = new StreamReader(responseStream))
                                            {
                                                var responseXml = await responseStreamReader.ReadToEndAsync();
                                                XmlDocument xml = new XmlDocument();
                                                xml.LoadXml(responseXml);

                                                var envelopeNode = xml.ChildNodes.OfType<XmlElement>().FirstOrDefault(node => (string)node.LocalName == "Envelope");
                                                var bodyNode = envelopeNode.ChildNodes.OfType<XmlElement>().FirstOrDefault(node => (string)node.LocalName == "Body");
                                                var getCallListResponseNode = bodyNode.ChildNodes.OfType<XmlElement>().FirstOrDefault(node => (string)node.LocalName == "GetCallListResponse");
                                                var newCallListURLNode = getCallListResponseNode.ChildNodes.OfType<XmlElement>().FirstOrDefault(node => (string)node.LocalName == "NewCallListURL");
                                                url = newCallListURLNode.InnerText;
                                            }
                                        }
                                    }
                                }
                            }

                            if (url != null)
                            {
                                using (var responseMessage = await client.GetAsync(url))
                                {

                                    Debug.WriteLine($"#2 Request StatusCode: {responseMessage.StatusCode}");
                                }
                            }

                        }

                    }

                    await Task.Delay(26000);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

Authentifiziert wird mittels Digest.

Wie kann man denn dem Client denn dieses Verhalten abgewöhnen?

Thema: HttpClient produziert bei weiterem Request StatusCode 401. Werden Credentials gecached?
Am im Forum: Web-Technologien

Hallo,

ich habe ein Problem mit dem HttpClient aus System.Net.Http.

ich bekomme reproduzierbar den Statuscode 401 wo er eigentlich nicht auftreten dürfte, die Credentials die ich dem Client mitgebe passen.

Folgendes Szenario:

Ein Vorgang wird gestartet. Für jeden dieser Vorgänge instanziiere ich einen eigenen HttpClient samt HttpClientHandler dem ich die Credentials mitgebe.
Der Client macht einen SoapRequest um sich benötigte Daten zu holen. In diesen Daten ist eine URL enthalten mit der ich nach dem ersten Request ein Get mache.

Für den ersten Durchlauf, kein Problem. Credentials sind Valide -> StatusCode 200
Für den zweiten und folgenden Durchlauf auch kein Problem solange der Vorgang in einem Zeitfenster von 25 Sekunden (Reproduzierbar) zum vorhergegangenen Vorgang stattfindet.

Dann nähmlich bekomme ich plötzlich den StatusCode 401.


Folgendes habe ich mittels Fiddler herausfinden können:

Der erste Request des Vorgangs wird ohne CredentialHeader gemacht. StatusCode: 401
Der zweite Request erfolgt dann mit Credentials im Header. StatusCode: 200
Der Get-Request erfolgt dann auch wieder mit Credentials. StatusCode: 200

Und jetzt fängt es an merkwürdig zu werden.

Ein zweiter Vorgang wird 25 Sekunden später angestoßen:

Der erste Request des Vorgangs wird mit (???) CredentialHeader gemacht. StatusCode: 401
An dieser stelle bekomme ich das Fehlen des StatusCodes 200 als Exception präsetiert.

Ich hätte jetzt erwartet das der Client zunächst eine Anfrage ohne Credentials macht um dann bei den folgenden diese wieder mitzuschicken.


Für mich sieht das ein wenig so aus als ob die Credentials in irgendeiner Art gecached werden und diese nach besagten 25 Sekunden nicht mehr gültig sind.
Aber wie kann das sein, immerhin ist es bei jedem Vorgang ein neuer Client der nach Abschluss auch wieder Disposed wird.

Weis jemand rat?


Falls jemand Beispielscode sehen mag bitte einfach bescheid geben. Den reiche ich dann nach.