Загрузите файл Excel через AJAX MVC

У меня есть большая (ish) форма в MVC.

Мне нужно иметь возможность генерировать файл excel, содержащий данные из подмножества этой формы.

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

Этот кажется самым близким к тому, что мне нужно: asp-net-mvc-downloading-excel - но я не уверен, что понимаю ответ, и это пара лет старый сейчас. Я также столкнулся с другой статьей (больше не могу ее найти) об использовании iframe для обработки загрузки файла, но я не уверен, как заставить это работать с MVC.

Мой файл excel возвращает штраф, если я делаю полный пост, но я не могу заставить его работать с AJAX в mvc.

Ответ 1

Вы не можете напрямую вернуть файл для загрузки через вызов AJAX, поэтому альтернативный подход заключается в использовании вызова AJAX для отправки связанных данных на ваш сервер. Затем вы можете использовать код на стороне сервера для создания файла Excel (я бы рекомендовал использовать EPPlus или NPOI для этого, хотя кажется, что у вас есть эта часть работы).

ОБНОВЛЕНИЕ Сентябрь 2016

Моему первоначальному ответу (ниже) было более 3 лет, поэтому я решил обновить, поскольку больше не создаю файлы на сервере при загрузке файлов через AJAX, однако я оставил исходный ответ, поскольку это может быть полезно все еще зависит от ваших конкретных требований.

Обычный сценарий в моих приложениях MVC сообщает через веб-страницу с некоторыми настроенными параметрами отчета пользователя (Date Ranges, Filters и т.д.). Когда пользователь указал параметры, которые они отправляют на сервер, создается отчет (например, файл Excel в качестве вывода), а затем я сохраняю полученный файл в виде байтового массива в ведре TempData с уникальной ссылкой. Эта ссылка передается как результат Json для моей функции AJAX, которая затем перенаправляет на отдельное действие контроллера для извлечения данных из TempData и загрузки в браузер конечных пользователей.

Чтобы дать это более подробно, если у вас есть MVC View, который имеет форму, связанную с классом Model, позвоните в Model ReportVM.

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

public ActionResult PostReportPartial(ReportVM model){

   // Validate the Model is correct and contains valid data
   // Generate your report output based on the model parameters
   // This can be an Excel, PDF, Word file - whatever you need.

   // As an example lets assume we've generated an EPPlus ExcelPackage

   ExcelPackage workbook = new ExcelPackage();
   // Do something to populate your workbook

   // Generate a new unique identifier against which the file can be stored
   string handle = Guid.NewGuid().ToString();

   using(MemoryStream memoryStream = new MemoryStream()){
        workbook.SaveAs(memoryStream);
        memoryStream.Position = 0;
        TempData[handle] = memoryStream.ToArray();
   }      

   // Note we are returning a filename as well as the handle
   return new JsonResult() { 
         Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
   };

}

Вызов AJAX, который отправляет мою форму MVC указанному выше контроллеру и получает ответ, выглядит следующим образом:

$ajax({
    cache: false,
    url: '/Report/PostReportPartial',
    data: _form.serialize(), 
    success: function (data){
         var response = JSON.parse(data);
         window.location = '/Report/Download?fileGuid=' + response.FileGuid 
                           + '&filename=' + response.FileName;
    }
})

Действие контроллера для обработки загрузки файла:

[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{   
   if(TempData[fileGuid] != null){
        byte[] data = TempData[fileGuid] as byte[];
        return File(data, "application/vnd.ms-excel", fileName);
   }   
   else{
        // Problem - Log the error, generate a blank file,
        //           redirect to another controller action - whatever fits with your application
        return new EmptyResult();
   }
}

Еще одно изменение, которое может быть легко выполнено при необходимости, - передать MIME-тип файла в качестве третьего параметра, чтобы одно действие контроллера могло корректно обслуживать различные форматы выходных файлов.

Это устраняет необходимость в любых физических файлах, которые были созданы и сохранены на сервере, поэтому не требуется никаких подпрограмм ведения домашнего хозяйства, и еще раз это становится понятным для конечного пользователя.

Примечание. Преимущество использования TempData, а не Session заключается в том, что после чтения TempData данные очищаются, поэтому они будут более эффективными с точки зрения использования памяти, если у вас большой объем запросов файла. См. Лучшая практика TempData.

ОРИГИНАЛЬНЫЙ ОТВЕТ

Вы не можете напрямую вернуть файл для загрузки через вызов AJAX, поэтому альтернативный подход заключается в использовании вызова AJAX для отправки связанных данных на ваш сервер. Затем вы можете использовать код на стороне сервера для создания файла Excel (я бы рекомендовал использовать EPPlus или NPOI для этого, хотя это звучит так, как будто у вас есть эта часть работы).

Как только файл был создан на сервере, верните путь к файлу (или просто имя файла) в качестве возвращаемого значения для вашего вызова AJAX, а затем установите для этого URL JavaScript window.location, который заставит браузер загрузите файл.

С точки зрения конечных пользователей операция загрузки файлов является бесшовной, поскольку они никогда не покидают страницу, на которой возникает запрос.

Ниже приведен простой надуманный пример вызова ajax для достижения этого:

$.ajax({
    type: 'POST',
    url: '/Reports/ExportMyData', 
    data: '{ "dataprop1": "test", "dataprop2" : "test2" }',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (returnValue) {
        window.location = '/Reports/Download?file=' + returnValue;
    }
});
  • url - это метод Controller/Action, в котором ваш код создаст файл Excel.
  • data​​strong > содержит данные json, которые будут извлечены из формы.
  • returnValue будет именем файла вашего вновь созданного файла Excel.
  • Команда window.location перенаправляет на метод Controller/Action, который фактически возвращает ваш файл для загрузки.

Пример метода контроллера для действия Download:

[HttpGet]
public virtual ActionResult Download(string file)
{   
  string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
  return File(fullPath, "application/vnd.ms-excel", file);
}

Ответ 2

Мои 2 цента - вам не нужно хранить Excel как физический файл на сервере - вместо этого, сохраните его в (Session) Cache. Используйте уникально сгенерированное имя для вашей переменной Cache (которая хранит этот файл Excel) - это будет возвращением вашего (начального) вызова ajax. Таким образом, вам не придется сталкиваться с проблемами доступа к файлам, управлять (удалять) файлы, когда они не нужны, и т.д. И, имея файл в кэше, быстрее его извлекать.

Ответ 3

Недавно я смог выполнить это в MVC (хотя не нужно было использовать AJAX) без создания физического файла и думал, что я поделюсь своим кодом:

Супер простая функция JavaScript (кнопка кнопки datatables.net вызывает это):

function getWinnersExcel(drawingId) {
    window.location = "/drawing/drawingwinnersexcel?drawingid=" + drawingId;
}

Код контроллера С#:

    public FileResult DrawingWinnersExcel(int drawingId)
    {
        MemoryStream stream = new MemoryStream(); // cleaned up automatically by MVC
        List<DrawingWinner> winnerList = DrawingDataAccess.GetWinners(drawingId); // simple entity framework-based data retrieval
        ExportHelper.GetWinnersAsExcelMemoryStream(stream, winnerList, drawingId);

        string suggestedFilename = string.Format("Drawing_{0}_Winners.xlsx", drawingId);
        return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", suggestedFilename);
    }

В классе ExportHelper я использую сторонний инструмент (GemBox.Spreadsheet), чтобы сгенерировать файл Excel, и он имеет значение "Сохранить в поток" вариант. При этом существует несколько способов создания файлов Excel, которые могут быть легко записаны в поток памяти.

public static class ExportHelper
{
    internal static void GetWinnersAsExcelMemoryStream(MemoryStream stream, List<DrawingWinner> winnerList, int drawingId)
    {

        ExcelFile ef = new ExcelFile();

        // lots of excel worksheet building/formatting code here ...

        ef.SaveXlsx(stream);
        stream.Position = 0; // reset for future read

     }
}

В IE, Chrome и Firefox браузер запрашивает загрузку файла, и фактическая навигация не происходит.

Ответ 4

Я использовал решение, отправленное CSL, но я бы рекомендовал вам не хранить данные файла в сеансе в течение всего сеанса. Используя TempData, данные файла автоматически удаляются после следующего запроса (который является запросом GET для файла). Вы также можете управлять удалением файлов в сеансе в процессе загрузки.

Сессия может потреблять много памяти/пространства в зависимости от хранилища SessionState и количества файлов, экспортируемых во время сеанса, и если у вас много пользователей.

Я обновил код Serer от CSL, чтобы вместо этого использовать TempData.

public ActionResult PostReportPartial(ReportVM model){

   // Validate the Model is correct and contains valid data
   // Generate your report output based on the model parameters
   // This can be an Excel, PDF, Word file - whatever you need.

   // As an example lets assume we've generated an EPPlus ExcelPackage

   ExcelPackage workbook = new ExcelPackage();
   // Do something to populate your workbook

   // Generate a new unique identifier against which the file can be stored
   string handle = Guid.NewGuid().ToString()

   using(MemoryStream memoryStream = new MemoryStream()){
        workbook.SaveAs(memoryStream);
        memoryStream.Position = 0;
        TempData[handle] = memoryStream.ToArray();
   }      

   // Note we are returning a filename as well as the handle
   return new JsonResult() { 
         Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
   };

}

[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{   
   if(TempData[fileGuid] != null){
        byte[] data = TempData[fileGuid] as byte[];
        return File(data, "application/vnd.ms-excel", fileName);
   }   
   else{
        // Problem - Log the error, generate a blank file,
        //           redirect to another controller action - whatever fits with your application
        return new EmptyResult();
   }
}

Ответ 5

Сначала создайте действие контроллера, которое создаст файл Excel

[HttpPost]
public JsonResult ExportExcel()
{
    DataTable dt = DataService.GetData();
    var fileName = "Excel_" + DateTime.Now.ToString("yyyyMMddHHmm") + ".xls";

    //save the file to server temp folder
    string fullPath = Path.Combine(Server.MapPath("~/temp"), fileName);

    using (var exportData = new MemoryStream())
    {
        //I don't show the detail how to create the Excel, this is not the point of this article,
        //I just use the NPOI for Excel handler
        Utility.WriteDataTableToExcel(dt, ".xls", exportData);

        FileStream file = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
        exportData.WriteTo(file);
        file.Close();
    }

    var errorMessage = "you can return the errors in here!";

    //return the Excel file name
    return Json(new { fileName = fileName, errorMessage = "" });
}

затем создайте действие Download

[HttpGet]
[DeleteFileAttribute] //Action Filter, it will auto delete the file after download, 
                      //I will explain it later
public ActionResult Download(string file)
{
    //get the temp folder and file path in server
    string fullPath = Path.Combine(Server.MapPath("~/temp"), file);

    //return the file for download, this is an Excel 
    //so I set the file content type to "application/vnd.ms-excel"
    return File(fullPath, "application/vnd.ms-excel", file);
}

если вы хотите удалить файл после загрузки, создайте этот

public class DeleteFileAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.Flush();

        //convert the current filter context to file and get the file path
        string filePath = (filterContext.Result as FilePathResult).FileName;

        //delete the file after download
        System.IO.File.Delete(filePath);
    }
}

и, наконец, вызов ajax от вас Просмотр MVC Razor

//I use blockUI for loading...
$.blockUI({ message: '<h3>Please wait a moment...</h3>' });    
$.ajax({
    type: "POST",
    url: '@Url.Action("ExportExcel","YourController")', //call your controller and action
    contentType: "application/json; charset=utf-8",
    dataType: "json",
}).done(function (data) {
    //console.log(data.result);
    $.unblockUI();

    //get the file name for download
    if (data.fileName != "") {
        //use window.location.href for redirect to download action for download the file
        window.location.href = "@Url.RouteUrl(new 
            { Controller = "YourController", Action = "Download"})/?file=" + data.fileName;
    }
});

Ответ 6

используя ClosedXML.Excel;

   public ActionResult Downloadexcel()
    {   
        var Emplist = JsonConvert.SerializeObject(dbcontext.Employees.ToList());
        DataTable dt11 = (DataTable)JsonConvert.DeserializeObject(Emplist, (typeof(DataTable)));
        dt11.TableName = "Emptbl";
        FileContentResult robj;
        using (XLWorkbook wb = new XLWorkbook())
        {
            wb.Worksheets.Add(dt11);
            using (MemoryStream stream = new MemoryStream())
            {
                wb.SaveAs(stream);
                var bytesdata = File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "myFileName.xlsx");
                robj = bytesdata;
            }
        }


        return Json(robj, JsonRequestBehavior.AllowGet);
    }

Ответ 7

$.ajax({
                type: "GET",
                url: "/Home/Downloadexcel/",
                contentType: "application/json; charset=utf-8",
                data: null,
                success: function (Rdata) {
                    debugger;
                    var bytes = new Uint8Array(Rdata.FileContents); 
                    var blob = new Blob([bytes], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
                    var link = document.createElement('a');
                    link.href = window.URL.createObjectURL(blob);
                    link.download = "myFileName.xlsx";
                    link.click();
                },
                error: function (err) {

                }

            });

Ответ 8

Этот поток помог мне создать мое собственное решение, которое я поделюсь здесь. Сначала я использовал запрос GET ajax без проблем, но он дошел до точки, где длина URL-адреса запроса была превышена, поэтому мне пришлось перебирать POST.

javascript использует плагин загрузки файлов JQuery и состоит из 2 последующих вызовов. Один POST (для отправки параметров) и один GET для восстановления файла.

 function download(result) {
        $.fileDownload(uri + "?guid=" + result,
        {
            successCallback: onSuccess.bind(this),
            failCallback: onFail.bind(this)
        });
    }

    var uri = BASE_EXPORT_METADATA_URL;
    var data = createExportationData.call(this);

    $.ajax({
        url: uri,
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify(data),
        success: download.bind(this),
        fail: onFail.bind(this)
    });

Серверная сторона

    [HttpPost]
    public string MassExportDocuments(MassExportDocumentsInput input)
    {
        // Save query for file download use
        var guid = Guid.NewGuid();
        HttpContext.Current.Cache.Insert(guid.ToString(), input, null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration);
        return guid.ToString();
    }

   [HttpGet]
    public async Task<HttpResponseMessage> MassExportDocuments([FromUri] Guid guid)
    {
        //Get params from cache, generate and return
        var model = (MassExportDocumentsInput)HttpContext.Current.Cache[guid.ToString()];
          ..... // Document generation

        // to determine when file is downloaded
        HttpContext.Current
                   .Response
                   .SetCookie(new HttpCookie("fileDownload", "true") { Path = "/" });

        return FileResult(memoryStream, "documents.zip", "application/zip");
    }

Ответ 9

Ответ CSL был реализован в проекте, над которым я работаю, но проблема, с которой я столкнулся, заключалась в том, что масштабирование на Azure прервало загрузку наших файлов. Вместо этого я смог сделать это с помощью одного вызова AJAX:

SERVER

[HttpPost]
public FileResult DownloadInvoice(int id1, int id2)
{
    //necessary to get the filename in the success of the ajax callback
    HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

    byte[] fileBytes = _service.GetInvoice(id1, id2);
    string fileName = "Invoice.xlsx";
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

КЛИЕНТ (модифицированная версия загрузки файла Handle с поста ajax)

$("#downloadInvoice").on("click", function() {
    $("#loaderInvoice").removeClass("d-none");

    var xhr = new XMLHttpRequest();
    var params = [];
    xhr.open('POST', "@Html.Raw(Url.Action("DownloadInvoice", "Controller", new { id1 = Model.Id1, id2 = Model.Id2 }))", true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function () {
        if (this.status === 200) {
            var filename = "";
            var disposition = xhr.getResponseHeader('Content-Disposition');
            if (disposition && disposition.indexOf('attachment') !== -1) {
                var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                var matches = filenameRegex.exec(disposition);
                if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
            }
            var type = xhr.getResponseHeader('Content-Type');

            var blob = typeof File === 'function'
                ? new File([this.response], filename, { type: type })
                : new Blob([this.response], { type: type });
            if (typeof window.navigator.msSaveBlob !== 'undefined') {
                // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
                window.navigator.msSaveBlob(blob, filename);
            } else {
                var URL = window.URL || window.webkitURL;
                var downloadUrl = URL.createObjectURL(blob);

                if (filename) {
                    // use HTML5 a[download] attribute to specify filename
                    var a = document.createElement("a");
                    // safari doesn't support this yet
                    if (typeof a.download === 'undefined') {
                        window.location = downloadUrl;
                    } else {
                        a.href = downloadUrl;
                        a.download = filename;
                        document.body.appendChild(a);
                        a.click();
                    }
                } else {
                    window.location = downloadUrl;

                }

                setTimeout(function() {
                        URL.revokeObjectURL(downloadUrl);
                    $("#loaderInvoice").addClass("d-none");
                }, 100); // cleanup
            }
        }
    };
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send($.param(params));
});

Ответ 10

Принятый ответ не сработал для меня, так как я получил результат 502 Bad Gateway от вызова ajax, хотя казалось, что все возвращается нормально с контроллера.

Возможно, я достиг предела с TempData - не уверен, но я обнаружил, что если я использовал IMemoryCache вместо TempData, он работал нормально, так что вот моя адаптированная версия кода в принятом ответе:

public ActionResult PostReportPartial(ReportVM model){

   // Validate the Model is correct and contains valid data
   // Generate your report output based on the model parameters
   // This can be an Excel, PDF, Word file - whatever you need.

   // As an example lets assume we've generated an EPPlus ExcelPackage

   ExcelPackage workbook = new ExcelPackage();
   // Do something to populate your workbook

   // Generate a new unique identifier against which the file can be stored
   string handle = Guid.NewGuid().ToString();

   using(MemoryStream memoryStream = new MemoryStream()){
        workbook.SaveAs(memoryStream);
        memoryStream.Position = 0;
        //TempData[handle] = memoryStream.ToArray();

        //This is an equivalent to tempdata, but requires manual cleanup
        _cache.Set(handle, memoryStream.ToArray(), 
                    new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(10))); 
                    //(I'd recommend you revise the expiration specifics to suit your application)

   }      

   // Note we are returning a filename as well as the handle
   return new JsonResult() { 
         Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
   };

}

Вызов AJAX остается как с принятым ответом (я не внес изменений):

$ajax({
    cache: false,
    url: '/Report/PostReportPartial',
    data: _form.serialize(), 
    success: function (data){
         var response = JSON.parse(data);
         window.location = '/Report/Download?fileGuid=' + response.FileGuid 
                           + '&filename=' + response.FileName;
    }
})

Действие контроллера для обработки загрузки файла:

[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{   
    if (_cache.Get<byte[]>(fileGuid) != null)
    {
        byte[] data = _cache.Get<byte[]>(fileGuid);
        _cache.Remove(fileGuid); //cleanup here as we don't need it in cache anymore
        return File(data, "application/vnd.ms-excel", fileName);
    }
    else
    {
        // Something has gone wrong...
        return View("Error"); // or whatever/wherever you want to return the user
    }
}

...

Теперь есть дополнительный код для настройки MemoryCache...

Чтобы использовать "_cache", я вставил в конструктор контроллера вот так:

using Microsoft.Extensions.Caching.Memory;
namespace MySolution.Project.Controllers
{
 public class MyController : Controller
 {
     private readonly IMemoryCache _cache;

     public LogController(IMemoryCache cache)
     {
        _cache = cache;
     }

     //rest of controller code here
  }
 }

И убедитесь, что у вас есть следующее в ConfigureServices в Startup.cs:

services.AddDistributedMemoryCache();

Ответ 11

Возможно, я звучу довольно наивно и может вызвать серьезную критику, но вот как я это сделал,

(Он не включает ajax для экспорта, но он также не выполняет полную обратную передачу)

Спасибо за этот пост и этот ответ.

Создать простой контроллер

public class HomeController : Controller
{               
   /* A demo action
    public ActionResult Index()
    {           
        return View(model);
    }
   */
    [HttpPost]
    public FileResult ExportData()
    {
        /* An example filter
        var filter = TempData["filterKeys"] as MyFilter;
        TempData.Keep();            */
        var someList = db.GetDataFromDb(/*filter*/) // filter as an example

    /*May be here the trick, I'm setting my filter in TempData["filterKeys"] 
     in another action,(GetFilteredPartial() illustrated below )
     when searching for the data,
     so do not really need ajax here..to pass my filters.. */

 var dt = Utility.ConvertToDataTable(someList); //Some utility to convert list to Datatable

        //  I am using EPPlus nuget package 
        using (ExcelPackage pck = new ExcelPackage())
        {
            ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1");
            ws.Cells["A1"].LoadFromDataTable(dt, true);

            using (var memoryStream = new MemoryStream())
            {                   
              pck.SaveAs(memoryStream);
              return File(memoryStream.ToArray(),
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
              "ExportFileName.xlsx");                    
            }                
        }   
    }

    //This is just a supporting example to illustrate setting up filters ..        
   /* [HttpPost]
    public PartialViewResult GetFilteredPartial(MyFilter filter)
    {            
        TempData["filterKeys"] = filter;
        var filteredData = db.GetConcernedData(filter);
        var model = new MainViewModel();
        model.PartialViewModel = filteredData;

        return PartialView("_SomePartialView", model);
    } */     
} 

А вот взгляды.. или вид

/* @model Models.MainViewModel
 @{
   ViewBag.Title = "Home Page";
   Layout = "~/Views/Shared/_Layout.cshtml";
  }

   <div class="main-container">... 
          Some code for, say, a partial View  
              <div id="tblSampleBody">
                @Html.Partial("_SomePartialView", Model.PartialViewModel)
              </div>
  */                                                       
//The actual part.. Just post this bit of data... Here, you are not posting the Main form.. 
        @using (Html.BeginForm("ExportData", "Home", FormMethod.Post))
        {
             <input type="submit" value="Export Data" />
        }
...
</div>

/*And you may require to pass search/filter values.. as said in the accepted answer..
That can be done while searching the data.. and not while we need an export..for instance:-             

<script>             
  var filterData = {
      SkipCount: someValue,
      TakeCount: 20,
      UserName: $("#UserName").val(),
      DepartmentId: $("#DepartmentId").val(),     
   }

  function GetFilteredData() {
       $("#loader").show();
       filterData.SkipCount = 0;
       $.ajax({
          url: '@Url.Action("GetFilteredPartial","Home")',
          type: 'POST',
          dataType: "html",
          data: filterData,
          success: function (dataHTML) {
          if ((dataHTML === null) || (dataHTML == "")) {
              $("#tblSampleBody").html('<tr><td>No Data Returned</td></tr>');
                $("#loader").hide();
            } else {
                $("#tblSampleBody").html(dataHTML);                    
                $("#loader").hide();
            }
        }
     });
   }    
</script>*/

Здесь вся суть в том, что мы публикуем форму в середине Razor View, вызываем метод Action, который возвращает FileResult, а в возвращаемом файле мы возвращаем файл...
А для публикации значений фильтра, как было сказано (и, если требуется), я публикую их в другом действии, которое пытались описать.

Ответ 12

Я использую Asp.Net WebForm, и просто хочу загрузить файл со стороны сервера. Существует много статей, но я не могу найти простой ответ. Теперь я попробовал простой способ и получил его.

Это моя проблема.

Мне нужно создать много кнопки ввода динамически во время выполнения. И я хочу добавить каждую кнопку для загрузки кнопки с указанием уникального fileNumber.

Я создаю каждую кнопку следующим образом:

fragment += "<div><input type=\"button\" value=\"Create Excel\" onclick=\"CreateExcelFile(" + fileNumber + ");\" /></div>";

Ответ 13

Вставить форму

public ActionResult ExportXls()
{   
 var filePath="";
  CommonHelper.WriteXls(filePath, "Text.xls");
}

 public static void WriteXls(string filePath, string targetFileName)
    {
        if (!String.IsNullOrEmpty(filePath))
        {
            HttpResponse response = HttpContext.Current.Response;
            response.Clear();
            response.Charset = "utf-8";
            response.ContentType = "text/xls";
            response.AddHeader("content-disposition", string.Format("attachment; filename={0}", targetFileName));
            response.BinaryWrite(File.ReadAllBytes(filePath));
            response.End();
        }
    }