AJAX MVCを介してExcelファイルをダウンロードする


92

私はMVCで大きな(ish)フォームを持っています。

そのフォームのサブセットからのデータを含むExcelファイルを生成できるようにする必要があります。

トリッキーなのは、これがフォームの残りの部分に影響を与えてはならないということです。そのため、AJAXを介してそれを実行します。私は関連しているように見えるSOに関するいくつかの質問に出くわしましたが、私は答えが何を意味するのか完全には理解できません。

これは私が求めているものに最も近いようです:asp-net-mvc-downloading-excel-しかし、私が応答を理解しているかどうかはわかりません。iframeを使用してファイルのダウンロードを処理することに関する別の記事(もう見つからない)にも出会いましたが、これをMVCで動作させる方法がわかりません。

完全なポストバックを実行している場合、Excelファイルは正常に返されますが、MVCでAJAXを使用して動作させることができません。

回答:


215

AJAX呼び出しを介してダウンロード用のファイルを直接返すことはできないため、別のアプローチは、AJAX呼び出しを使用して関連データをサーバーに投稿することです。その後、サーバー側のコードを使用してExcelファイルを作成できます(これにはEPPlusまたはNPOIを使用することをお勧めしますが、この部分が機能しているように見えます)。

2016年9月更新

私の元の答え(下記)は3年以上前のものだったので、AJAX経由でファイルをダウンロードするときにサーバー上にファイルを作成しなくなったので更新するつもりでしたが、特定の要件。

私のMVCアプリケーションの一般的なシナリオは、ユーザーが構成したレポートパラメーター(日付範囲、フィルターなど)があるWebページを介したレポートです。ユーザーがサーバーに投稿するパラメーターを指定すると、レポートが生成され(たとえば、出力としてのExcelファイル)、結果のファイルTempDataが一意の参照を持つバケットにバイト配列として保存されます。この参照は、Jsonの結果としてAJAX関数に返され、その後、別のコントローラーアクションにリダイレクトされTempDataて、エンドユーザーのブラウザーからデータを抽出し、ブラウザーにダウンロードします。

これを詳しく説明するために、Modelクラスにバインドされたフォームを持つMVCビューがあると想定して、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" }
   };

}

MVCフォームを上記のコントローラーに送信して応答を受信する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(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();
   }
}

必要に応じて簡単に対応できるもう1つの変更は、1つのコントローラーアクションがさまざまな出力ファイル形式を正しく処理できるように、ファイルのMIMEタイプを3番目のパラメーターとして渡すことです。

これにより、物理ファイルを作成してサーバーに保存する必要がなくなり、ハウスキーピングルーチンは不要になり、エンドユーザーにとってシームレスになります。

注、使用しての利点TempDataはなくはSession一度ということでTempData読み込まれますが、ファイル要求の高いボリュームを持っている場合、それはメモリ使用量の面でより効率的になるようにデータがクリアされます。TempDataのベストプラクティスを参照してください。

元の回答

AJAX呼び出しを介してダウンロード用のファイルを直接返すことはできないため、別のアプローチは、AJAX呼び出しを使用して関連データをサーバーに投稿することです。その後、サーバー側のコードを使用してExcelファイルを作成できます(これにはEPPlusまたはNPOIを使用することをお勧めしますが、この部分が機能しているように見えます)。

サーバーでファイルが作成されたら、ファイルへのパス(またはファイル名のみ)をAJAX呼び出しの戻り値として返し、JavaScript window.locationをこのURLに設定して、ブラウザーにファイルのダウンロードを促します。

エンドユーザーの観点から見ると、リクエストの発生元のページから離れることがないため、ファイルのダウンロード操作はシームレスです。

以下は、これを達成するための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パラメーターは、コードがExcelファイルを作成するコントローラー/アクションメソッドです。
  • dataパラメータには、フォームから抽出されるjsonデータが含まれています。
  • returnValueは、新しく作成したExcelファイルのファイル名になります。
  • window.locationのを実際にダウンロードするファイルを返すコントローラ/アクションメソッドへのコマンドリダイレクト。

ダウンロードアクションのサンプルコントローラメソッドは次のようになります。

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

3
これは良い潜在的なオプションのように見えますが、先に進む前に、最初にサーバーでファイルを作成することを必要としない他の選択肢はありませんか?
Valuk 2013年

4
私が知っていることではありません-このアプローチは何度も成功裏に使用しています。ユーザーの観点からはシームレスですが、注意が必要なことは、作成されたファイルが時間の経過とともにマウントされるときに整理されるハウスキーピングルーチンが必要になることです。
connectedsoftware

7
エンドポイント '/ Download?file = ...'を作成すると、大量のセキュリティリスクが発生します-私はセキュリティの専門家ではありませんが、ユーザー認証、入力サニテーション、MVCの[ValidateAntiForgeryToken]を追加し、他のセキュリティについて最もよく言及したいと思います-この答えの実践。
ジミー

2
@CSL常にエラー0x800a03f6-JavaScriptランタイムエラーが発生します:var response = JSON.parse(data);に無効な文字があります。
スタンダージ2017年

2
すばらしい、古い答えを一番下に置いてみませんか?そして、一番上に新しい答え、人々は時間を無駄にしないように
goamn

19

私の2セント-エクセルを物理ファイルとしてサーバーに保存する必要はありません。代わりに、(セッション)キャッシュに保存します。(そのExcelファイルを格納する)キャッシュ変数に一意に生成された名前を使用します-これが(初期)ajax呼び出しの戻りになります。このようにして、ファイルアクセスの問題に対処したり、必要のないときにファイルを管理(削除)したりする必要がなくなります。また、ファイルをキャッシュに置くと、ファイルをすばやく取得できます。


1
あなたはそれをどのように正確に行いますか?面白そう。
ナタリア2014

2
例はいいでしょう(つまり、Excelファイルを生成するのではなく、キャッシュに保存する方法を意味します)。
Tadej 2017年

これはどれほどスケーラブルですか?ユーザーがいくつかの大きなレポートをダウンロードしている場合は?
Zapnologica

Azureを使用している場合、ARRAffinityをオフにするまでセッションは機能します。
JeeShen Lee 2018

14

私は最近、物理ファイルを作成せずにMVCでこれを達成することができました(ただしAJAXを使用する必要はありませんでした)。コードを共有すると思いました。

超シンプルなJavaScript関数(datatables.netボタンのクリックがこれをトリガーします):

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

C#コントローラーコード:

    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では、ブラウザがファイルのダウンロードを要求し、実際のナビゲーションは行われません。


8

まず、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 = "" });
}

次に、ダウンロードアクションを作成します

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

最後に、MVC Razorビューからのajax呼び出し

//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;
    }
});

7

私はCSLによって投稿されたソリューションを使用しましたが、セッション全体を通じてセッションにファイルデータを保存しないことをお勧めします。TempDataを使用することにより、次の要求(ファイルのGET要求)の後でファイルデータが自動的に削除されます。ダウンロードアクションのセッションでファイルデータの削除を管理することもできます。

SessionStateストレージと、セッション中にエクスポートされるファイルの数、およびユーザー数が多い場合、セッションは多くのメモリ/スペースを消費する可能性があります。

代わりにTempDataを使用するようにCSLのsererサイドコードを更新しました。

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();
   }
}

@Nichlas私もTempDataを使い始めましたが、あなたの答えは私にこれを反映するように私のものを更新するように促しました!
connectedsoftware

5

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


AJAX CALL成功ブロックでは、成功: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(); }、
GVKRAO 2018年

上記のリンクにExcelファイルのダウンロードを実装した人がいます。それは@ html.Beginform()でのみ機能し、小さな変更がそのコードを必要とした後、AJAX呼び出し成功ブロックのために、それを確認してください、それはAJAX CALLで
正常に機能

3
$ .ajax({
                タイプ:「GET」、
                url: "/ Home / Downloadexcel /"、
                contentType: "application / json; charset = utf-8"、
                データ:null、
                成功:関数(Rdata){
                    デバッガ;
                    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();
                }、
                エラー:関数(err){

                }

            });

1

すべてがコントローラーから正常に返されているように見えたにもかかわらず、ajax呼び出しから502 Bad Gatewayの結果が返されたため、受け入れられた回答は私にとってはうまくいきませんでした。

たぶん、TempDataで限界に達していたのかもしれません-確かではありませんが、TempDataの代わりにIMemoryCacheを使用した場合、問題なく動作することがわかりました。

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
  }
 }

また、Startup.csのConfigureServicesに以下が含まれていることを確認してください。

services.AddDistributedMemoryCache();

0

このスレッドは、私がここで共有する独自のソリューションを作成するのに役立ちました。最初は問題なくGET ajaxリクエストを使用していましたが、リクエストのURLの長さを超えてしまうため、POSTに切り替えなければなりませんでした。

JavaScriptはJQueryファイルダウンロードプラグインを使用し、2つの後続の呼び出しで構成されます。1つのPOST(パラメーターを送信する)と1つの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");
    }

0

CSLの答えは私が取り組んでいるプロジェクトに実装されましたが、Azureでのスケールアウトで発生した問題は、ファイルのダウンロードを壊しました。代わりに、1つのAJAX呼び出しでこれを行うことができました。

サーバ

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

CLIENTajaxポストからハンドルファイルダウンロードの変更バージョン)

$("#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));
});

0
  $.ajax({
    global: false,
    url: SitePath + "/User/ExportTeamMembersInExcel",
    "data": { 'UserName': UserName, 'RoleId': RoleId, UserIds: AppraseeId },
    "type": "POST",
    "dataType": "JSON",
   "success": function (result) {
        debugger
        var bytes = new Uint8Array(result.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 () {
        alert("error");
    }
})


[HttpPost]
    public JsonResult ExportTeamMembersInExcel(string UserName, long? RoleId, string[] UserIds)
    {
        MemoryStream stream = new MemoryStream();
        FileContentResult robj;
        DataTable data = objuserservice.ExportTeamToExcel(UserName, RoleId, UserIds);
        using (XLWorkbook wb = new XLWorkbook())
        {
            wb.Worksheets.Add(data, "TeamMembers");
            using (stream)
            {
                wb.SaveAs(stream);
            }
        }
        robj = File(stream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "TeamMembers.xlsx");
        return Json(robj, JsonRequestBehavior.AllowGet);
    }

ファイルを開くことができず、Excelがちょうど開いて、それ自体が閉じないだけです。robjの直前にstream.close()を追加しましたが、機能していません。
夜明けコード

0

私は非常に素朴に聞こえるかもしれませんし、かなりの批判を引き付けるかもしれませんが、ここに私がそれをした方法があります
それは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's the trick, I'm setting my filter in TempData["filterKeys"] 
     in an action,(GetFilteredPartial() illustrated below) when 'searching' for the data,
     so do not really need ajax here..to pass my filters.. */

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

      //  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);
    } */     
} 

そして、これがビューです。

/*Commenting out the View code, in order to focus on the imp. code     
 @model Models.MainViewModel
 @{Layout...}     

      Some code for, say, a partial View  
      <div id="tblSampleBody">
        @Html.Partial("_SomePartialView", Model.PartialViewModel)
      </div>
  */                                                       
//The actual part.. Just **posting** this bit of data from the complete View...
//Here, you are not posting the full Form..or the complete View
   @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ビューの一部)を投稿している ことを示してAction methodいます。フォームを投稿するFileResultと、FileResultが返されますthe Excel File。これにより、が返されます 。
そして、フィルター値を投稿するために、前述のように(必要に応じて)、説明しようとした別のアクションへの投稿リクエストを作成しています。


-1

Asp.Net WebFormを使用していますが、サーバー側からファイルをダウンロードしたいだけです。記事はたくさんありますが、基本的な答えだけはわかりません。今、私は基本的な方法を試して、それを得ました。

それが私の問題です。

実行時に多くの入力ボタンを動的に作成する必要があります。また、各ボタンをダウンロードボタンに追加して、一意のfileNumberを指定します。

私はこのように各ボタンを作成します:

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

各ボタンはこのajaxメソッドを呼び出します。

$.ajax({
    type: 'POST',
    url: 'index.aspx/CreateExcelFile',
    data: jsonData,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (returnValue) {
      window.location = '/Reports/Downloads/' + returnValue.d;
    }
});

次に、基本的な簡単な方法を書きました。

[WebMethod]
public static string CreateExcelFile2(string fileNumber)
{
    string filePath = string.Format(@"Form_{0}.xlsx", fileNumber);
    return filePath;
}

このForm_1、Form_2、Form_3を生成しています。そして、この古いファイルを別のプログラムで削除します。しかし、Responseを使用するようにバイト配列をダウンロードファイルに送信する方法がある場合。使いたい。

これが誰にとっても役に立つことを願っています。


-1

提出フォーム

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();
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.