2013-12-19 3 views
2

У меня есть контроллер (ViewResult), который получает строковый параметр, создает файл PDF и отправляет PDF-файл обратно в браузер. Я тестировал сам контроллер, и он отлично работает. К сожалению, когда я пытаюсь отправить этот контроллер из функции $ .ajax jQuery (передавая простую строку), контроллер всегда принимает строковый параметр как null. Я пробовал сотни различных конфигураций функции $ .ajax. Вот контроллер, который возвращает PDF в браузере (он работает ... до тех пор, пока я создаю HTML внутри метода):Загрузка файла ASP.NET MVC и параметр jQuery

[HttpPost] 
public ActionResult HtmlToPdf(String htmlData) 
{ } 

Вот JQuery я использую, на мой взгляд (показываемых по нажатие кнопки):

function getPdf() { 
    var htmlData = “blah, blah, etc.”; 
    $.ajax({ 
     url: '/Home/HtmlToPdf', 
     type: 'post', 
     data: JSON.stringify(htmlData), 
     contentType: 'application/json; charset=utf-8', 
     success: handleSuccess, 
     error: handleError 
    }); 
} 

Я пытался «пост», «получить», JSON, текст, HTML, stringify, различные типы контента и т.д. кто-нибудь знает, как правильно отправить строку (УАК " htmlData 'выше) к контроллеру? После? Получить? Что-то другое? Благодарю.

+1

Постарайся не stringifying вашего объекта, отправить его в качестве 'данных:! HtmlData' – Jose

+0

Попробованных это именно так. Все еще null. – TheDudeDude

+0

Хммм, у меня были такие проблемы раньше ... Я бы удалил часть contentType, я обнаружил, что даже при кодировании, как вы это сделали (даже с правильным типом), удалив его, MVC будет расшифруйте его правильно. Просто мои 2 цента;) – Jose

ответ

5

Вы должны отправить его в качестве JSon объекта:

function getPdf() { 
    var htmlData = “blah, blah, etc.”; 
    var dataToPost = { htmlData: htmlData }; 
    $.ajax({ 
     url: '/Home/HtmlToPdf', 
     type: 'POST', 
     data: JSON.stringify(dataToPost), 
     dataType: 'json', 
     contentType: 'application/json; charset=utf-8', 
     success: handleSuccess, 
     error: handleError 
    }); 
} 

Вы тогда доступ в HomeController, просто объявив это аргументом, как вы это сделали. Дело в том, что вам нужно передать имя аргумента как часть объекта JSON. Тот факт, что вы являетесь именем переменной, также является «htmlData», не имеет значения. Выше, может также быть легко ...

var stuff = "blah, etc..."; 
var dataToPost = { htmlData: stuff }; 

Очевидно, что для нескольких аргументов вы просто иметь больше деталей в вашем объекте ...

var dataToPost = { arg1: someData, arg2: 2, arg3: true } 

... с ...

public ActionResult DoStuff(string arg1, int? arg2, bool? arg3) {} 

Если вы хотите передать массив, добавьте traditional:true в объект аргумента $.ajax.

Я также отмечаю, что я всегда ставил «POST» в верхнем регистре, поскольку, если вы посмотрите на документацию here, аргументы datatype: (например, «json») указаны в нижнем регистре, но «GET» и «POST» 'для type: находятся в верхнем регистре.

---------------------------- Обновление ----------------- --------

Как указано в комментариях, для простой загрузки файлов, вероятно, проще использовать GET.

Основной контроллер что-то вроде (я уравновешивать вниз код, чтобы не проверял это)

public FileResult DownloadFile(string filename) 
{ 
    byte[] fileContent = new byte[0]; 
    using(FileStream fs = File.OpenRead(filename)) { 
     fileContent = new byte[fs.Length]; 
     fs.Read(fileContent, 0, Convert.ToInt32(fs.Length)); 
    } 
    UTF8Encoding encoder = new UTF8Encoding(); 
    return File(encoder.GetBytes(fileContent), "applicaton/text", filename); 
} 

Тогда в JavaScript сделать:

$.get('/Home/DownloadFile', 
    function(data, textStatus, jqXHR) { /* don't think anything needs to be done */ } 
).error(alert('Download failed')); 

Это, очевидно, загружает текстовый файл так что вам нужно будет играть с кодировкой (возможно, возможно, она не нужна?) и stringType для PDF (я думаю, что это просто «приложение/PDF»).Кроме того, чтобы повторить, я не тестировал этот точный код, просто отредактировал логику существующего приложения. Удачи.

+0

Очень странно; все еще не работает. Я должен использовать GET, потому что контроллер возвращает FileStreamResult. Если я использую Html.ActionLink вместо простой кнопки, действие контроллера называется правильно ... Я просто не могу передать длинную строку, как хотелось бы. Использование кнопки (и функции $ .ajax) вызовет действие контроллера, но при успехе браузер не отображает полученный PDF-файл. Есть ли конкретное действие/команда, которую мне нужно использовать в «успехе», чтобы просто отобразить ответ сервера? – TheDudeDude

+0

(в ответ на ваше обновление выше): Это выглядит слишком просто! Я попробую в понедельник. FWIW, я единственный .NET dev на работе, который _ever_ вступает в jQuery (!). Еще раз спасибо. – TheDudeDude

+0

«Методы обратного вызова jqXHR.success(), jqXHR.error() и jqXHR.complete(), введенные в jQuery 1.5, устарели от jQuery 1.8». – Misi

2

Попробуйте отправить ваш data как объект JSON и установив dataType в 'json':

function getPdf() { 
    var htmlData = “blah, blah, etc.”; 
    $.ajax({ 
     url: '/Home/HtmlToPdf', 
     type: 'post', 
     data: { htmlData: htmlData }, 
     dataType: 'json', 
     contentType: 'application/json; charset=utf-8', 
     success: handleSuccess, 
     error: handleError 
    }); 
} 
+0

Я тоже пробовал это, без успеха. Действительно, я использовал буквально десятки разных «конфигураций» функции $ .ajax. Я начинаю задаваться вопросом, связано ли это с POST или GET, или что-то другое. – TheDudeDude

+0

О, еще одна вещь: если я использую ваш синтаксис выше (данные: {htmlData: htmlData}), функция выдает функцию ошибки. Я не знаю почему. Если я просто использую [data: htmlData], контроллер будет успешно вызван. :-p – TheDudeDude

+0

@TheDudeDude - вы добавили 'dataType: 'json'', когда вы отправили его как json? – Alconja

0

Спасибо за ответы. Я думаю, все они были правильными и хорошими. Однако я отказался от этого, потому что, я думаю, я пытался сделать что-то, что на самом деле невозможно: отправить вызов ajax на сервер и заставить сервер «закончить работу», вернув двоичный файл в браузер (как PDF). Функция ajax выполняла, получая сообщение об успешном завершении и выполняла свою функцию успеха. Потерянный во всем этом факт заключался в том, что браузер должен был получать ответ файла, а не ответ ajax. Извините, если я не объясню это очень хорошо. Во всяком случае, я отступил и проигнорировал: я создаю свой файл, представляя отчет .NET (.rdlc) в виде PDF и отправляя его в браузер. Сырой, но эффективный. Оглядываясь назад, я не думаю, что аякс был даже способом пойти на это. :-п. Спасибо еще раз за помощь.

+1

Это можно сделать в AJAX, поскольку мы делаем это все время. Я недавно не смотрел код, но помню, что один из методов заключался в том, чтобы сделать начальный POST для создания файла и вернуть данные для обновления экрана, а затем в функции успеха выпустить второй POST, который возвращает файл. Я посмотрю код. – StarNamer

+0

@starnamer О, хороший ответ! Я не думал о двух отдельных POST. Я думаю, что буду возвращаться, спасибо! – TheDudeDude

0

Используя метод двойной POST и свободное расширение Jquery «FileDownload» от here

/* 
* jQuery File Download Plugin v1.4.1 
* 
* http://www.johnculviner.com 
* 
* Copyright (c) 2013 - John Culviner 
* 
* Licensed under the MIT license: 
* http://www.opensource.org/licenses/mit-license.php 
*/ 

Которые в основном оборачивает POST в какой-то код, который помогает обработке некоторые сложности ...

У нас есть (с большими кусками удалены (!) ...

 $.ajax({ 
      url: emr.baseURL + '/Control/SaveData', 
      type: 'POST', 
      data: JSON.stringify(dataToPost), 
      dataType: 'json', 
      contentType: 'application/json; charset=utf-8', 
      success: function (json) { 
// stuff deleted which updates page 
         $.fileDownload(
          '/Control/Export', 
          { 
           data: { 
// data list deleted... 
            )) 
           }, 
           httpMethod: 'POST' 
          }); 
        } 
      }, 
      error: function() { 
// deleted 
      } 
     }); 

с методами контроллера (сократить)

public JsonResult SaveData(/* ... */) 
{ 
    /* 
    ... do stuff ... 
    */ 
    return /* JsonResult... */; 
} 

[HttpPost] 
public void Export(/* ... */) 
{ 
    /* 
    ... 
    */ 
    HttpContext context = System.Web.HttpContext.Current; 
    /* 
    ... 
    */ 
    byte[] XLSXdata; 
    /* 
    ...Fill XLXSdata... 
    */ 
    context.Response.Clear(); 
    context.Response.ClearHeaders(); 
    context.Response.ClearContent(); 
    context.Response.Buffer = false; 
    context.Response.ContentType = "application/vnd.ms-excel"; 
    context.Response.AddHeader("content-disposition", "attachment;filename="+filename); 
    context.Response.Charset = ""; 
    context.Response.BinaryWrite(XLSXdata); 
    context.Response.Flush(); 
    context.Response.End(); 
} 

Очевидно, что это явно контролирует то, что входит в ответ.

Надеется, что это помогает/

Смежные вопросы