WebRequest: Comment trouver un code postal à l'aide d'un WebRequest contre ce contenuType = “Application / xhtml + xml, text / xml, text / html; charse = utf-8 ”?

StackOverflow https://stackoverflow.com/questions/1455567

Question

J'ai d'abord posté ceci: HTTPWeBRequest: Comment trouver un code postal au Canada Post via un WebRequest avec X-WWW-FORM-FLOSED?.

Suite aux suggestions d'Anthonywjones, j'ai changé mon code à la suite de ses suggestions.

Sur la poursuite de mon enquête, j'ai remarqué avec le temps que le poste de contenu du Canada est plus susceptible d'être "Application / xhtml + xml, texte / xml, texte / html; charset = utf-8".

Mes questions sont:

  1. Comment webrequest contre un tel site Web de type contenu?
  2. Devons-nous continuer à aller avec l'objet NameValueCollection?
  3. Selon Scott Lance qui m'a généreusement fourni des informations précieuses dans ma question précédente, le WebRequest renverra le type d'informations quel que soit le type de contenu, est-ce que je manque quelque chose ici?
  4. Dois-je modifier mon code en raison du changement de type de contenu?

Voici mon code pour qu'il soit plus facile de comprendre mes progrès.

internal class PostalServicesFactory {
/// <summary>
/// Initializes an instance of GI.BusinessSolutions.Services.PostalServices.Types.PostalServicesFactory class.
/// </summary>
internal PostalServicesFactory() {
}
/// <summary>
/// Finds a Canadian postal code for the provided Canadian address.
/// </summary>
/// <param name="address">The instance of GI.BusinessSolutions.Services.PostalServices.ICanadianCityAddress for which to find the postal code.</param>
/// <returns>The postal code found, otherwise null.</returns>
internal string FindPostalCode(ICanadianCityAddress address) {
    if (address == null)
        throw new InvalidOperationException("No valid address specified.");

    using (ServicesWebClient swc = new ServicesWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        byte[] resultData = swc.UploadValues(@"http://www.canadapost.ca/cpotools/apps/fpc/personal/findByCity", "POST", values);

        return Encoding.UTF8.GetString(resultData);
    }
}

private class ServicesWebClient : WebClient {
    public ServicesWebClient()
        : base() {
    }
    protected override WebRequest GetWebRequest(Uri address) {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        request.CookieContainer = new CookieContainer();
        return request;
    }
}
}

Ce code renvoie en fait le code source HTML du formulaire à remplir avec les informations requises afin de traiter avec la recherche de code postal. Ce que je souhaite, c'est obtenir le code source HTML ou quoi que ce soit avec le code postal trouvé.

ÉDITER: Voici la conception Web que j'obtiens maintenant: "Impossible d'envoyer un corps de contenu avec ce type de verbe." (Ceci est une traduction de l'exception française "Impossible d'Envoyer Un Corps de Contenu avec ce type de verbe.")

Voici mon code:

    internal string FindPostalCode(string url, ICanadianAddress address) {
    string htmlResult = null;

    using (var swc = new ServiceWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        swc.UploadValues(url, @"POST", values);
        string redirectUrl = swc.ResponseHeaders.GetValues(@"Location")[0];
        => swc.UploadValues(redirectUrl, @"GET", values);
    }

    return htmlResult;
}

La ligne qui provoque l'exception est pointée avec "=>". Il semble que je ne peux pas utiliser Get comme méthode, mais c'est ce qui m'a été dit de faire ...

Une idée de ce qui me manque ici? J'essaie de faire ce que Justin (voir la réponse) m'a recommandé de faire.

Merci d'avance pour votre aide! :-)

Était-ce utile?

La solution

Pour introduction au monde du crampons d'écran, vous avez choisi un étui très difficile! La page de recherche du Canada Post fonctionne comme ceci:

  1. La première page est un formulaire qui accepte les valeurs d'adresse
  2. Cette page publie sur une deuxième URL.
  3. Cette deuxième URL redirige à son tour (en utilisant une redirection HTTP 302) vers une troisième URL qui vous montre en fait la réponse HTML contenant le code postal.

Pour aggraver les choses, la page de l'étape # 3 doit connaître l'ensemble des cookies à l'étape # 1. Vous devez donc utiliser le même CookieContainer pour les trois demandes (bien qu'il puisse être suffisant pour envoyer la même chose CookieContainer à # 2 et # 3 uniquement).

De plus, vous devrez peut-être également envoyer des en-têtes HTTP supplémentaires dans ces demandes, comme accepter. Je soupçonne que vous rencontrez des problèmes que HttpWeBRequest par défaut, les poignées redirigent de manière transparente pour vous - mais lorsqu'elle redirige de manière transparente, cela peut ne pas ajouter les bons en-têtes HTTP nécessaires pour usurper l'identité d'un navigateur.

La solution consiste à définir le HttpWebRequest's AllowAutoRedirect propriété à FAUX et gérez le redirection vous-même. En d'autres termes, une fois que la première demande renvoie une redirection, vous devrez retirer l'URL dans le HttpWebResponse's Location: entête. Alors vous devrez créer un nouveau HttpWebRequest (Cette fois, une demande de GET régulière, pas un message) pour cette URL. Rappelez-vous d'envoyer le même cookie! (la CookieContainer La classe rend cela très facile)

Vous devrez peut-être également faire une demande supplémentaire (n ° 1 dans ma liste ci-dessus) afin de configurer le cookie de session. Si j'étais vous, je suppose que cela est nécessaire, simplement pour l'éliminer comme un problème, et essayer de supprimer cette étape plus tard et de voir si votre solution fonctionne toujours.

Vous voudrez télécharger et utiliser Fiddler (www.fiddlertool.com) pour vous aider avec tout cela. Fiddler vous permet de regarder les demandes HTTP passant par-dessus le fil et vous permet (via la fonction de création de demande) vous permet de créer des demandes HTTP afin que vous puissiez voir quels en-têtes sont réellement requis.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top