Laden...

WebClient unterschied Windows und Windows Phone (Encoding)

Erstellt von MysticEmpires vor 10 Jahren Letzter Beitrag vor 10 Jahren 5.231 Views
M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren
WebClient unterschied Windows und Windows Phone (Encoding)

Hallo,

ich habe da ein Problem. Und zwar möchte ich mit "DownloadStringAsync" wie der Name schon sagt den String einer Webseite (naja eher die Rückgabe einer API) auslesen.

Ich benutze folgenden Code:

var wbClient = new WebClient();
wbClient.DownloadStringCompleted += (s, e) => Console.WriteLine(e.Result);
wbClient.DownloadStringAsync(new Uri("http://192.168.137.205/control/epg?04530001445c"));

Führe ich das ganze unter Windows aus bekommen ich wunderschön einen Rückgabe mit Sonderzeichen und allem. Führe ich das unter Windows Phone aus bekomme ich statt Umlauten sowas hier: "ý".

Es bringt auch nichts das Encoding vom wbClient auf UTF-8 zu stellen. Keine Änderung 😦

Jemand eine Idee?

*EDIT*

selber Link im Windows Phone Browser gibt aber sehr wohl die Umlaut korrekt aus.

*EDIT2*

Hier mal der Header der zurück kommt:

HTTP/1.0 200 OK
Content-Type: text/plain
Cache-Control: no-cache
Server: nhttpd/3.1.8 (yhttpd_core/1.2.0)
Date: Sun, 21 Jul 2013 09:38:12 GMT
Connection: close
Last-Modified: Sun, 21 Jul 2013 09:38:12 GMT
Content-Length: 4947

Gruß
Alex

D
615 Beiträge seit 2009
vor 10 Jahren

Hallo MysticEmpires

Für micht klingt es dennoch nach einem Encoding/Decoding Problem.

Du hast also schon folgendes versucht ?

Webclient.Encoding = System.Text.Encoding.UTF8

Ist die Antwort wirklich UTF8 ?

Du kannst sonst auch

WebClient.DownloadData verwenden, dann bekommst das byte[] mit etwas debuggen, solltest du so zum Resultat kommen.

Beste Grüsse

Diräkt

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Es bringt auch nichts das Encoding vom wbClient auf UTF-8 zu stellen. Keine Änderung 😦

Jop auch versucht. Verwunder mich wie gesagt nur das es im Windows mit ner simplen Consolen-Anwendung funktioniert. Aber 1:1 der gleiche Code im Windows Phone nicht funktioniert.

D
615 Beiträge seit 2009
vor 10 Jahren

Hallo MysticEmpires

Beide haben die selbe Version Nummer des .Net Frameworks als Target ? (z.B. 4.5 ?)

Ich weiss das für die DownloadString Methode kein StreamReader etc. benötigt wird (was ja das Umsetzen so einfach / schön macht 😃)

Dennoch versuch mal sowas :


    string result=string.Empty;
     
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://www.google.de");
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    [B]Encoding responseEncoding = Encoding.GetEncoding(response.CharacterSet);[/B]
     
    using (StreamReader sr = new StreamReader(response.GetResponseStream(), responseEncoding))
    {
    result = sr.ReadToEnd();
    }

Beste Grüsse

Diräkt

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Geht so unter Windows Phone leider nicht 😦

D
615 Beiträge seit 2009
vor 10 Jahren

Hallo MysticEmpires

Ja stimmt, bei Dir müsste das etwa so aussehen :



string url= "http://www.google.ch";
HttpWebRequest request =    (HttpWebRequest)HttpWebRequest.Create(url);
request.BeginGetResponse(GetRequestCallback, request);

void GetRequestCallback(IAsyncResult result)
{
    HttpWebRequest request = result.AsyncState as HttpWebRequest;
    if (request != null)
    {
        try
        {
            WebResponse response = request.EndGetResponse(result);
            Encoding responseEncoding = Encoding.GetEncoding(response.CharacterSet);
            
          using (StreamReader sr = new StreamReader(response.GetResponseStream(), responseEncoding))
    {
    result = sr.ReadToEnd();
    }

        }
        catch (WebException e)
        {
           throw;   ......
        }
    }
}


Beste Grüsse

Diräkt

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Geht leider auch nicht ganz da es kein "response.CharacterSet" gibt. Ich habe das mal so versucht:

        private void GetRequestCallback(IAsyncResult result)
        {
            var request = result.AsyncState as HttpWebRequest;

            if (request == null) 
                return;

            var response = request.EndGetResponse(result);

            using (var sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                System.Diagnostics.Debug.WriteLine(sr.ReadToEnd());
        }

Leider ohne Erfolg wieder komische Zeichen 😕

3.170 Beiträge seit 2006
vor 10 Jahren

Hallo,

leider ist ja in Deinem HTTP-Response-Header kein Content-Encoding angegeben. Daher kann der WebClient auch nicht bestimmen, um welches Encoding es sich handelt.

Ich vermute, dass dann das Default-Encoding herangezogen wird. Dies kann sich zwischen Phone und PC schon unterscheiden.
Wenn es am PC funktioniert, schau doch mal, was dort für ein Default-Encoding benutzt wird und versuche dann, dieses Encoding auch auf dem Phone zu benutzen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

So weiter getestet. Es kommen ja auch XML-Dokumente zurück. Beide enthalten ja ne Deklaration.

Kommt folgende XML:

<?xml version="1.0" encoding="UTF-8">

funktioniert alles ohne etwas einzustellen. Kommt folgende XML:

<?xml version="1.0" encoding="ISO-8859-1">

Gibt es Probleme mit Sonderzeichen. Lege ich jetzt das Encoding auf "ISO-8859-1" fest und zwar so:

wbClient.Encoding = Encoding.GetEncoding("iso-8859-1")

Geht zwar die zweite XML aber die erste nicht mehr. Wie soll ich denn beide Handeln ohne einen außen vor zu lassen?

D
615 Beiträge seit 2009
vor 10 Jahren

Hallo MysticEmpires

Schau Dir mal das an:

How to detect encoding of xml file

Beste Grüsse

Diräkt

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Das ja weniger das Problem. Ich lese die XML später mit:

XDocument.Parse(e.Result);

Ein dort wird die Deklaration ja auch korrekt erkannt nur der String der Runtergeladen wird ist dann halt schon versaut.

16.841 Beiträge seit 2008
vor 10 Jahren

Ich seh nicht, dass Du den Ratschlägen von MarsStein befolgt hast.

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Das habe ich hat nur nicht zum Erfolg geführt:

Windows Phone => "utf-8"
Windows => "Windows-1252"

Und "Windows-1252" gibt es im Windows Phone nicht:

'Windows-1252' is not a supported encoding name.

Ich habe ja nur zwei verschiedene Datein

text/plain; charset=UTF-8

(Diese wird korrekt erkannt. Aber auch wenn wäre es egal da das Default-Encoding eh UTF8 ist)

text/plain;

(Diese wird nicht richtig erkannt (wie auch). Jetzt wird aber UTF8 benutzt aber die Datei selbst wie man am Inhalt der XML sieht ist ISO-8859-1)

Und genau da liegt das Problem.

16.841 Beiträge seit 2008
vor 10 Jahren

Wenn Du nach "Windows-1252", also Big5 Encoding suchst, dann wirst Du sehen, dass dies als veraltet markiert ist.
Die Alternative ist jedoch ISO-8859-1, wobei sich hier die Chars 129-159 etwas unterscheiden.

In meinen Augen ist der Wurm an anderer stelle, wenn ISO-8859-1 bei Dir nicht funktioniert.
UTF-8 scheint der Dokumentation zufolge jedenfalls nicht das richtige zu sein (wichtig ist hier der Request, nicht das Parsen).

Du solltest den Default also auf ISO-8859-1 setzen, ansonsten dynamisch aus dem Request lesen. Das was der Server Dir als Encoding sendet hat zu 99,9% Priorität.

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Du solltest den Default also auf ISO-8859-1 setzen, ansonsten dynamisch aus dem Request lesen. Das was der Server Dir als Encoding sendet hat zu 99,9% Priorität.

Genau das ist das was ich gern machen möchte. Nur wie?

Ich bekommen wie oben erwähnt zwei Unterschiedliche Antworten (je nach dem welchen Server ich die Frage stelle).

Server1-Header:

text/plain;

Server1-XML:

<?xml version="1.0" encoding="ISO-8859-1"?>

Server2-Header:

text/plain; charset=UTF-8

Server2-XML:

<?xml version="1.0" encoding="UTF-8"?>
16.841 Beiträge seit 2008
vor 10 Jahren

Das Encoding des XMLs halt prinzipiell mal nicht viel mit dem Encoding der Verbindung zutun - besser gesagt gar nichts.

Das Encoding, das Du von der Verbindung mit bekommst, das verwendest Du um den mitgesendeten Inhalt zu lesen (meist über einen Streamreader, dem Du dieses Encoding (oder den Standard) übergeben musst). Das hast Du mit GetRequestCallback auch schon prinzipiell gemacht; Du musst hier nur das Encoding der Verbindung beachten und das XML Encoding bei diesem Schritt ignorieren.

Das gelesene Resultat, aus dem Streamreader, übergibst Du dann XDocument.Parse().
Dieser erkennt anhand des XML-Encodings eigenständig, was er mit dem Inhalt anstellen muss.

Dich muss nur das Verbindungsencoding für das Lesen des Request-Inhalts kümmern. Und wenn Du das Lesen falsch angehst, dann kracht auch der XDocument-Parser.

Und wenn WP8 wirklich kein direktes Ermitteln des Encodings anbietet (damits FW kleiner bleibt), dann musst Du das eben selbst auslesen, indem Du auf die Header-Keys zugreifst.

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

So ich hab es jetzt gelöst. Ich lese die Daten nicht mehr mit DownloadStringAsync sondern mit OpenReadAsync. Dann lese ich die Daten normal mit einen StreamReader das Encoding gebe ich aber zusätzlich an. Den Wert für das Encoding lese ich aus dem Header aus. Hier mal ein Beispielcode falls jemand ein ähnliches Problem hat:

private static Encoding GetEncodingFromResponseHeader(WebHeaderCollection whc)
{
    //# Default-Encoding auf iso-8859-1 setzen
    var enc = Encoding.GetEncoding("iso-8859-1");

    //# Liegt ein Header vor?
    if (whc != null)
    {
        //# ContentTyp ermittlen
        var contentType = whc[HttpRequestHeader.ContentType];

        //# Sind die Daten korrekt?
        if (!String.IsNullOrEmpty(contentType) && Regex.IsMatch(contentType,@"charset=([^""']+)"))
        {
            //# Encoding String ermitteln
            var encstr = Regex.Match(contentType, @"charset=([^""']+)").Groups[1].Value;

            try
            {
                //# Versuchen Encoding auf Charset festzulegen
                enc = Encoding.GetEncoding(encstr);
            }
            catch (ArgumentException)
            {
                //# Name konnte nicht ermittelt werden oder wird nicht unterstützt
            }              
        }
    }

    //# Rückgabe
    return enc;
}

Ich habe als Fallback Encoding "iso-8859-1" da in meinen Fall der Server kein Encoding angibt der die Daten auch in "iso-8859-1" schickt. Aber das kann man ja sonst gern auf Default stellen.

Gruß
Alex

16.841 Beiträge seit 2008
vor 10 Jahren

Danke, dass Du Deine Lösung gepostet hast.

Ein Hinweis noch bzgl der Architektur: hinterleg doch in den konsumierenden Servereinstellungen pro Server ein Default-Encoding.
Dann kannst Du Dich entweder entscheiden, dass Du ein Fallback-Encoding beim Methodenaufruf übergibst, oder, dass Du einfach null zurück lieferst, wenn nichts gefunden wurde und dann auf die Fallback-Variante in den Servereinstellungen zurück greifst.

So fliegst nämlich relativ schnell auf die Nase bzw. hast erhöhten Wartungsaufwand / Code-Änderungsaufwand, falls mal ein anderer Server hinzukommt, der wieder ein anderen Default liefert.

M
MysticEmpires Themenstarter:in
302 Beiträge seit 2004
vor 10 Jahren

Danke für die Tip. Ist bei mir nur nicht nötig. Die Adressen werden vom User eingegeben und sind mir daher auch nicht bekannt. Aber bei den "Servern" handelt es sich nur um zwei Verschiedene Hardwaretypen die sich auf Grund des Unterschieds in der Software die dort läuft einfach nur anders verhalten. Daher deckt das mein Szenario ab 😃