28 votes

MVC3 HttpPostedFileBase Le premier téléchargement ne donne aucune donnée mais les suivants le font

Contexte de la question.

EDIT 3 Je peux vérifier que cela semble fonctionner à nouveau dans Chrome 20. Merci !

Mise à jour du TLDR

EDIT 2 Après avoir continué à chercher, il semble que ce soit un bogue dans Chrome 19. Veuillez voir ici :

http://groups.google.com/a/chromium.org/group/chromium-bugs/browse_thread/thread/15bc4992bcd4be1d/b905e8de20ee58fa?lnk=raot

Rien de tel qu'un insecte de dernière minute ! :-)

Firefox - dernière version et IE8/9 fonctionnent comme prévu. Les journaux Fiddler montrent le même comportement, à la différence près que la deuxième vérification de l'autorisation 401 n'envoie pas les données utiles du formulaire sous forme tronquée et que tout fonctionne comme prévu.

On dirait qu'il s'agit d'un cas de test et qu'un correctif est en cours de réalisation ! J'espère que cela aidera ceux d'entre vous qui ont rencontré ce problème !

END TLDR

J'ai une action de contrôleur qui prend uniquement un fichier téléchargé qui est un fichier CSV d'"événements". En coulisses, ce CSV est analysé, transformé en objets d'événement et les données sont synchronisées dans la base de données. Comme résultat, l'utilisateur est invité à télécharger une feuille de calcul Excel qui contient toutes les erreurs sur chaque ligne qui se sont produites.

Tout cela fonctionne bien localement sur ma machine de développement. Cependant, une fois déployé dans l'environnement DEV, j'obtiens des résultats différents. Lors de la première tentative de téléchargement d'un fichier, le flux est, quel est le mot que je cherche ici, illisible ? Il indique correctement sa longueur mais les tentatives d'extraction des informations n'aboutissent à rien. Les lectures suivantes contiennent les données et tout fonctionne comme prévu.

Je vais vous donner les morceaux de code pertinents. D'abord, le formulaire HTML générique simplifié :

<form action="/Events/ImportLocal" enctype="multipart/form-data" method="post">

<input id="uploadFile" name="uploadFile" type="file" />
<input type="submit" value="Upload Events" />    

</form>

C'est assez simple :

Action du contrôleur (pardonnez le désordre, je suis en train de bricoler depuis quelques heures maintenant) :

[HttpPost]
public ActionResult ImportLocal(HttpPostedFileBase uploadFile)
{
    if (uploadFile == null || uploadFile.ContentLength <= 0)
    {
        BaseLogger.Info("uploadFile is null or content length is zero...");
        //Error content returned to user
    }

    BaseLogger.InfoFormat("Community Import File Information: Content Length: {0}, Content Type: {1}, File Name: {2}",
    uploadFile.ContentLength, uploadFile.ContentType, uploadFile.FileName);

//This logger line is always reporting as correct. Even on the attempts where I can't pull out the stream data, I'm seeing valid values here.
//EXAMPLE output on failed attempts:
//Import File Information: Content Length: 315293, Content Type: application/vnd.ms-excel, File Name: Export_4-30-2012.csv

    BaseLogger.InfoFormat("Upload File Input Stream Length: {0}", uploadFile.InputStream.Length);           
//This is reporting the correct length on failed attempts as well

//I know the below is overly complicated and convoluted but I'm at a loss for why the inputstream in HttpPostedFileBase is not pulling out as expected
//so I've been testing
        var target = new MemoryStream();
        uploadFile.InputStream.CopyTo(target);
        byte[] data = target.ToArray();
        BaseLogger.InfoFormat("File stream resulting length = {0}", data.Length);
//This reports correctly. So far so good.

        StringReader stringOut;
        var stream = new MemoryStream(data) {Position = 0};

        using (var reader = new StreamReader(stream))
        {
            string output = reader.ReadToEnd();
            BaseLogger.InfoFormat("Byte[] converted to string = {0}", output);
//No go...output is reported to be empty at this point so no data ever gets sent on to the service call below
            stringOut = new StringReader(output);
        }

        //Build up a collection of CommunityEvent objects from the CSV file
        ImportActionResult<Event> importActionResults = _eventImportServices.Import(stringOut);

L'objectif est de passer un textreader ou un stringreader à la méthode de service car, en coulisses, elle utilise une implémentation de traitement CSV qui veut ces types.

Avez-vous une idée de la raison pour laquelle la première demande échoue mais que les suivantes fonctionnent ? Je pense que j'ai besoin d'un regard neuf car je suis à court d'idées.

Dernier point, IIS 7.5 est la cible à la fois localement via IIS Express et sur le serveur de destination.

Gracias

EDIT pour la générosité :

Je copie ici mon message de prime et le résultat de Fiddler pour chaque demande.

J'ai ajouté quelques commentaires à cette question. Le problème semble lié à NTLM. Ce que je vois dans Fiddler est un 401 Unauthorized sur la requête 1 avec des données de formulaire valides (je crois comprendre que ces deux premières requêtes 401 Unauthorized sont "normales" dans les scénarios où seule l'authentification Windows est activée ; vérifiez s'il vous plaît). La demande 2 listée est à nouveau une 401 avec les mêmes données de formulaire, sauf que les données du fichier téléchargé ne sont plus qu'un tas de boîtes, la même taille de données, mais pas les données téléchargées exactes. La requête 3 est un 200 OK qui contient les données déformées et c'est ce que mon action de contrôleur reçoit. Comment faire pour que NTLM joue le jeu avec les téléchargements de fichiers ?

Voici le résultat de Fiddler pour chaque requête :

Demande 1) enter image description here

Demande 2) enter image description here

Et enfin la requête 3 qui est le HTTP 200 OK traité. enter image description here

EDIT 2 Après avoir continué à chercher, il semble que ce soit un bogue dans Chrome 19. Veuillez voir ici :

http://groups.google.com/a/chromium.org/group/chromium-bugs/browse_thread/thread/15bc4992bcd4be1d/b905e8de20ee58fa?lnk=raot

Rien de tel qu'un insecte de dernière minute ! :-)

La dernière version de Firefox et IE8/9 fonctionnent comme prévu. Les journaux Fiddler montrent le même comportement, à la différence près que la deuxième vérification de l'autorisation 401 n'envoie pas les données utiles du formulaire sous forme tronquée et que tout fonctionne comme prévu.

Il semble qu'un cas de test et un correctif soient en cours de réalisation ! J'espère que cela aidera ceux d'entre vous qui ont rencontré ce problème !

Gracias

1voto

j0aqu1n Points 859

C'est juste une idée à essayer. Notez que StreamReader possède de nombreux constructeurs :

http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx

Dans certains constructeurs, il tente d'autodétecter l'encodage (s'il est spécifié) et s'il ne peut pas le détecter, il revient à celui qui est spécifié. Le constructeur utilisé utilise l'encodage UTF-8. Vous pourriez modifier le constructeur pour qu'il détecte automatiquement l'encodage et, si ce n'est pas le cas, qu'il utilise UTF-8.

1voto

Alexandr Points 566

Je pense que vous devez vérifier les permissions sur le dossier IIS / Virtual Web Site dans lequel les fichiers sont téléchargés et le répertoire lui-même s'ils sont dans des endroits distincts.

1voto

Michal B. Points 3013

Bonne question. L'authentification est la première chose qui m'est venue à l'esprit. Il est normal d'avoir deux non autorisés et le 3ème autorisé. C'est simplement la façon dont NTLM fonctionne.

Si l'on a besoin de le faire fonctionner sur Chrome également et que l'on ne peut pas attendre le correctif, je suggère d'activer l'authentification par formulaire qui redirige vers le même domaine mais sur un port différent, où réside l'application LOGIN avec l'authentification Windows. Cette application définit ou non le cookie du formulaire et vous renvoie à votre application principale. Le processus est bien décrit ici : http://msdn.microsoft.com/en-us/library/ms972958.aspx

De cette façon, le NTLM est effectué une seule fois et vous disposez ensuite d'un cookie, de sorte que le NTLM n'est pas utilisé avec votre requête POST et que tout devrait fonctionner comme prévu.

J'ai juste pensé que je pourrais partager celle-ci :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X