MVC3 HttpPostedFileBase Первая загрузка не дает никаких данных, но последующая загрузка

Предыстория вопроса.

РЕДАКТИРОВАТЬ 3 Я могу убедиться, что это снова работает в Chrome 20. Спасибо!

Обновление TLDR

РЕДАКТИРОВАТЬ 2 После еще большего взлома об этом, похоже, ошибка в Chrome 19. Пожалуйста, смотрите здесь:

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

Ничего похожего на мелкую ошибку!:-)

Firefox-самая последняя и IE8/9 работают как положено. Журналы Fiddler показывают то же самое поведение с тем основным отличием, что 2-я проверка авторизации 401 не посылает искаженную полезную нагрузку формы и работает как ожидалось.

Звучит как тестовый пример, и исправление находится в разработке! Так что, надеюсь, для любого из вас, кто мог столкнуться с этим, это помогает!

КОНЕЦ TLDR

У меня есть действие контроллера, которое принимает только загруженный файл, который представляет собой CSV-файл "событий". За кулисами этот CSV анализируется, превращается в объекты событий, и данные синхронизируются в базе данных. В результате вывода пользователю предлагается загрузить электронную таблицу Excel, которая содержит все ошибки в каждой возникшей строке.

Все это прекрасно работает локально на моей машине для разработки. Однако после развертывания в среде DEV я получаю разные результаты. Первая попытка загрузить файл приводит к тому, что поток, который я ищу здесь, не читается? Он правильно сообщает о своей длине, но попытки извлечь информацию ничего не дает. Последующие чтения имеют данные, и все работает как ожидалось.

Я дам вам соответствующие кодовые страницы. Во-первых, упрощенная форма HTML:

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

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

</form>

Довольно прямо:

Действие контроллера (простите за беспорядок, я взломал это в течение пары часов):

[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);

Цель состоит в том, чтобы передать текстовый или строковый читатель методу службы, поскольку за кадром это использует реализацию обработки CSV, которая хочет эти типы.

Любые идеи, почему первый запрос не удается, но последующая работа? Я чувствую, что мне нужен свежий взгляд, потому что я иссякаю от идей.

Последний пункт, IIS 7.5 является целью как локально через IIS Express, так и на конечном сервере.

Спасибо

РЕДАКТИРОВАТЬ за вознаграждение:

Я копирую свое сообщение о вознаграждении здесь и вывод Fiddler для каждого запроса

Я добавил несколько комментариев к этому вопросу. Похоже, проблема связана с NTLM. То, что я вижу в Fiddler, - это 401 неавторизованный по запросу 1 с действительными данными формы (точнее, я понимаю, что эти первые два 401 неавторизованных запроса являются "нормальными" в сценариях, где включена только аутентификация Windows; проверьте, пожалуйста?). Перечисленный запрос 2 снова представляет собой 401 с теми же данными формы, за исключением того, что данные загруженного файла теперь представляют собой просто набор блоков данных, точно такого же размера, но не точных загруженных данных. Запрос 3 - это 200 OK, который содержит искаженные данные, и это то, что получает мое действие контроллера. Как заставить NTLM хорошо играть с загрузкой файлов?

Вот вывод Fiddler для каждого запроса:

Запрос 1)

Запрос 2)

И, наконец, запрос 3, который обработан HTTP 200 OK

РЕДАКТИРОВАТЬ 2 После еще большего взлома об этом, похоже, ошибка в Chrome 19. Пожалуйста, смотрите здесь:

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

Ничего похожего на мелкую ошибку!:-)

Firefox-самая последняя и IE8/9 работают как положено. Журналы Fiddler показывают то же самое поведение с тем основным отличием, что 2-я проверка авторизации 401 не посылает искаженную полезную нагрузку формы и работает как ожидалось.

Звучит как тестовый пример, и исправление находится в разработке! Так что, надеюсь, для любого из вас, кто мог столкнуться с этим, это помогает!

Спасибо

3 ответа

Хороший вопрос. Аутентификация была первым, что пришло мне в голову. Это нормально, чтобы получить два не авторизованных и 3-й авторизованный. Так работает NTLM.

Если нужно, чтобы он также работал на Chrome и не мог дождаться исправления, я бы предложил включить проверку подлинности с помощью форм, которая перенаправляет на тот же домен, но на другой порт, где находится приложение LOGIN с проверкой подлинности Windows. Это приложение устанавливает форму cookie или нет и отправляет вас обратно в основное приложение. Процесс хорошо описан здесь: http://msdn.microsoft.com/en-us/library/ms972958.aspx

Таким образом, ваш NTLM выполняется один раз, а затем у вас есть файл cookie, поэтому NTLM не используется с вашим запросом POST, и все должно работать как положено.

Просто думал, что поделюсь этим:)

Я думаю, что вам нужно проверить права доступа к папке IIS / виртуальному веб-сайту, в который загружаются файлы, и каталогу самого себя, если они находятся в разных местах.

Это просто идея, чтобы попробовать. Обратите внимание, что StreamReader имеет много конструкторов:

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

В некоторых конструкторах он пытается автоматически определить кодировку (если она указана), и если он не может обнаружить ее, он возвращается к указанной. Используемый конструктор использует кодировку UTF-8. Вы можете изменить конструктор так, чтобы он автоматически определял кодировку, а если нет, используйте UTF-8.

Другие вопросы по тегам