#c# #asp.net-mvc #stream
#c# #asp.net-mvc #поток
Вопрос:
Небольшая проблема с приложением MVC, которую я не уверен, как найти способ обойти.
По сути, я добавляю дополнительные функциональные возможности в систему, которая изначально была создана кем-то другим (c #). Для системы отчетности результаты всегда отображались только на экране. Теперь я создаю функциональность, позволяющую пользователю загружать свой отчет в виде документа Excel.
Итак, в принципе, у меня есть представление, которое отображает диапазоны дат и некоторые другие параметры уточнения поиска для пользователя. Я ввел переключатель, который, если он выбран, будет загружать отчет, а не отображать его на экране.
Вот мои три действия в ReportController:
public ActionResult Index()
{
return View();
}
public ActionResult ProductReport(AdminReportRequest reportRequest, FormCollection formVariables)
{
AdminEngine re = new AdminEngine();
if (!reportRequest.Download)
{
AdminReport report = re.GetCompleteAdminReport(reportRequest);
return View(report);
}
Stream ExcelReport = re.GetExcelAdminReport(reportRequest);
TempData["excelReport"] = ExcelReport;
return RedirectToAction("ExcelProductReport");
}
public FileResult ExcelReport()
{
var ExcelReport = TempData["excelReport"] as Stream;
return new FileStreamResult(ExcelReport, "application/ms-excel")
{
FileDownloadName = "Report" DateTime.Now.ToString("MMMM d, yyy") ".xls"
};
}
Я отладил через AdminEngine, и все выглядит нормально. Однако в действии ExcelReport, когда дело доходит до возврата файла — этого не происходит. То, что я вижу, — это множество символов на экране (в div ‘panelReport’ — см. Ниже), смешанных с тем, что могло бы быть данными в файле Excel.
Я думаю, я установил, что причина, по которой он отображается на экране, является результатом некоторого кода
это было написано в индексном представлении:
<% using (Ajax.BeginForm("ProductReport", "Report", null,
new AjaxOptions
{
UpdateTargetId = "panelReport",
InsertionMode = InsertionMode.Replace,
OnSuccess = "pageLoaded",
OnBegin = "pageLoading",
OnFailure = "pageFailed",
LoadingElementId = ""
},
new { id = "SearchForm" })) %>
Как вы можете видеть, в инструкции Ajax.BeginForm указано, что он должен обновиться до div panelReport, что он и делает (через частичный просмотр отчета о продукте). Хотя это идеально подходит для случаев, когда отчеты должны отображаться на экране, очевидно, что это не сработает с файлом Excel.
Есть ли способ обойти эту проблему, не слишком сильно изменяя существующий код?
Вот класс, в котором я выполняю обработку файла Excel на случай, если это потребуется, чтобы пролить свет на ситуацию:
Класс отчета:
public Stream GetExcelAdminReport(AdminReportRequest reportRequest)
{
AdminReport report = new AdminReport();
string dateRange = null;
List<ProductSale> productSales = GetSortedListOfProducts(reportRequest, out dateRange);
report.DateRange = dateRange;
if (productSales.Count > 0)
{
report.HasData = true;
CustomisedSalesReport CustSalesRep = new CustomisedSalesReport();
Stream SalesReport = CustSalesRep.GenerateCustomisedSalesFile(productSales);
return SalesReport;
}
}
Рабочий класс:
public class CustomisedSalesReport
{
public Stream GenerateCustomisedSalesFile(List<ProductSale> productSales)
{
MemoryStream ms = new MemoryStream();
HSSFWorkbook templateWorkbook = new HSSFWorkbook();
HSSFSheet sheet = templateWorkbook.CreateSheet("Sales Report");
//Workings
templateWorkbook.Write(ms);
ms.Position = 0;
return ms;
}
}
Ответ №1:
Проблема довольно очевидна в том, что вы используете Ajax-форму для загрузки файла. Кроме того, вы используете встроенные библиотеки Microsoft Ajax, которые кажутся недостаточно интеллектуальными.
Я могу предоставить 2 решения:
-
Самое простое решение (которое я использовал в прошлом) заключается в том, что вместо потоковой передачи файла самостоятельно создайте файл Excel и сохраните его на сервере, а затем отправьте ссылку на скачивание пользователю. Это не потребует больших изменений в коде.
-
Вы могли бы обработать событие onSubmit ajaxForm, посмотреть, нужно ли загружать этот файл. Если да, то сделайте полный запрос обратной передачи (используя
$.post()
). Таким образом, браузер автоматически выведет диалоговое окно с запросом, где загрузить.
Надеюсь, это имеет смысл.