AJAX MVC के माध्यम से एक्सेल फ़ाइल डाउनलोड करें


92

मेरे पास MVC में एक बड़ा (ईश) रूप है।

मुझे उस प्रपत्र के सबसेट से डेटा वाली एक एक्सेल फ़ाइल बनाने में सक्षम होने की आवश्यकता है।

मुश्किल सा यह है कि यह शेष रूप को प्रभावित नहीं करना चाहिए और इसलिए मैं इसे AJAX के माध्यम से करना चाहता हूं। मुझे एसओ पर कुछ सवाल आए हैं जो संबंधित प्रतीत होते हैं, लेकिन मैं काफी जवाब नहीं दे सकता कि उत्तर का क्या मतलब है।

यह वही है जो मैं के बाद सबसे करीब लगता हूं: एस्प-नेट-एमवीसी-डाउनलोडिंग-एक्सेल - लेकिन मुझे यकीन नहीं है कि मैं प्रतिक्रिया को समझता हूं, और यह अभी कुछ साल पुराना है। फ़ाइल डाउनलोड को संभालने के लिए एक iframe का उपयोग करने के बारे में मैं एक अन्य लेख (इसे अब और नहीं पा सकता) आया, लेकिन मुझे यकीन नहीं है कि यह MVC के साथ कैसे काम कर सकता है।

अगर मैं एक पूरी पोस्ट वापस कर रहा हूँ तो मेरी एक्सेल फ़ाइल ठीक है, लेकिन मैं इसे mvc में AJAX के साथ काम नहीं कर सकता।

जवाबों:


215

आप सीधे एक AJAX कॉल के माध्यम से डाउनलोड के लिए एक फ़ाइल वापस नहीं कर सकते हैं, एक वैकल्पिक दृष्टिकोण अपने सर्वर से संबंधित डेटा पोस्ट करने के लिए AJAX कॉल का उपयोग करना है। फिर आप एक्सेल फाइल बनाने के लिए सर्वर साइड कोड का उपयोग कर सकते हैं (मैं इसके लिए EPPlus या NPOI का उपयोग करने की सिफारिश करूंगा, हालांकि ऐसा लगता है जैसे आपके पास यह भाग काम कर रहा है)।

अद्यतन सितंबर 2016

मेरा मूल उत्तर (नीचे) 3 साल से अधिक पुराना था, इसलिए मैंने सोचा कि मैं अपडेट करूंगा क्योंकि मैं AJAX के माध्यम से फाइल डाउनलोड करते समय सर्वर पर फाइलें नहीं बनाता हूं, हालांकि, मैंने मूल उत्तर छोड़ दिया है क्योंकि यह अभी भी कुछ उपयोग पर निर्भर हो सकता है आपकी विशिष्ट आवश्यकताएं।

मेरे एमवीसी अनुप्रयोगों में एक सामान्य परिदृश्य एक वेब पेज के माध्यम से रिपोर्टिंग कर रहा है जिसमें कुछ उपयोगकर्ता कॉन्फ़िगर किए गए रिपोर्ट पैरामीटर (दिनांक रेंज, फ़िल्टर आदि) हैं। जब उपयोगकर्ता ने उन मापदंडों को निर्दिष्ट किया है जो वे सर्वर पर पोस्ट करते हैं, तो रिपोर्ट उत्पन्न होती है (उदाहरण के लिए एक्सेल फ़ाइल को आउटपुट के रूप में कहें) और फिर मैं परिणामस्वरूप फ़ाइल को बाइट में बाइट सरणी के रूप में TempDataएक अद्वितीय संदर्भ के साथ संग्रहीत करता हूं । यह संदर्भ मेरे AJAX फ़ंक्शन के लिए एक Json परिणाम के रूप में वापस पारित किया गया है जो बाद में डेटा को निकालने TempDataऔर अंतिम उपयोगकर्ता ब्राउज़र पर डाउनलोड करने के लिए अलग-अलग नियंत्रक कार्रवाई को पुनर्निर्देशित करता है।

इसे और अधिक विस्तार देने के लिए, मान लें कि आपके पास एक MVC दृश्य है जो एक मॉडल वर्ग के लिए बाध्य है, जो मॉडल को कॉल करने देता है 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डेटा को पढ़ने के बाद साफ़ किया जाता है, इसलिए यदि आपके पास फ़ाइल अनुरोधों की अधिक मात्रा है, तो यह मेमोरी उपयोग के मामले में अधिक कुशल होगा। टेंपडाटा बेस्ट प्रैक्टिस देखें ।

मूल जवाब

आप सीधे एक AJAX कॉल के माध्यम से डाउनलोड के लिए एक फ़ाइल वापस नहीं कर सकते हैं, एक वैकल्पिक दृष्टिकोण अपने सर्वर से संबंधित डेटा पोस्ट करने के लिए AJAX कॉल का उपयोग करना है। फिर आप एक्सेल फाइल बनाने के लिए सर्वर साइड कोड का उपयोग कर सकते हैं (मैं इसके लिए EPPlus या NPOI का उपयोग करने की सिफारिश करूंगा, हालांकि ऐसा लगता है जैसे आपके पास यह भाग काम कर रहा है)।

एक बार जब फ़ाइल सर्वर पर बन जाती है, तो आपके AJAX कॉल पर वापसी मान के रूप में फ़ाइल (या सिर्फ फ़ाइल नाम) के लिए पथ वापस करें और फिर window.locationइस URL पर जावास्क्रिप्ट सेट करें जो फ़ाइल को डाउनलोड करने के लिए ब्राउज़र को संकेत देगा।

अंतिम उपयोगकर्ता के दृष्टिकोण से, फ़ाइल डाउनलोड ऑपरेशन सहज है क्योंकि वे उस पृष्ठ को कभी नहीं छोड़ते हैं जिस पर अनुरोध उत्पन्न होता है।

नीचे इसे प्राप्त करने के लिए अजाक्स कॉल का एक सरल आकस्मिक उदाहरण है:

$.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 पैरामीटर कंट्रोलर / एक्शन विधि है जहाँ आपका कोड एक्सेल फाइल बनाएगा।
  • डेटा पैरामीटर में json डेटा होता है जिसे फ़ॉर्म से निकाला जाएगा।
  • returnValue आपकी नई बनाई गई एक्सेल फ़ाइल का फ़ाइल नाम होगा।
  • विंडो स्थान नियंत्रक / कार्रवाई विधि है कि वास्तव में डाउनलोड के लिए आपकी फ़ाइल रिटर्न के लिए आदेश रीडायरेक्ट हैं।

डाउनलोड क्रिया के लिए एक नमूना नियंत्रक विधि होगी:

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

3
यह एक अच्छे संभावित विकल्प की तरह दिखता है, लेकिन इससे पहले कि मैं इसके साथ आगे बढ़ूं, क्या कोई अन्य विकल्प नहीं हैं जो पहले सर्वर पर फ़ाइल बनाने में शामिल नहीं हैं?
वालुक

4
ऐसा नहीं है कि मैं इससे अवगत हूं - इस दृष्टिकोण का मैंने कई बार सफलतापूर्वक उपयोग किया है। उपयोगकर्ताओं के दृष्टिकोण से, यह सहज है, केवल एक ही बात ध्यान रखने योग्य है कि आपको उन फाइलों को व्यवस्थित करने के लिए एक हाउसकीपिंग रूटीन की आवश्यकता होगी जो कि समय के साथ माउंट हो जाएंगे।
जुड़े

7
एक समापन बिंदु बनाना / डाउनलोड करना? फ़ाइल = ... 'SCREAMS भारी सुरक्षा जोखिम - मैं कोई सुरक्षा विशेषज्ञ नहीं हूं, लेकिन मुझे लगता है कि आप उपयोगकर्ता प्रमाणीकरण, इनपुट स्वच्छता, MVC के [ValidateAntiForgeryToken] को जोड़ना चाहते हैं और अन्य सुरक्षा का सबसे अच्छा उल्लेख करते हैं। -इस उत्तर के लिए दोष।
जिम्मी

2
@CSL मुझे हमेशा त्रुटि 0x800a03f6 मिल रही है - जावास्क्रिप्ट रनटाइम त्रुटि: var response = JSON.parse (data) पर अमान्य वर्ण;
स्टैंडएज

2
महान, आप नीचे पुराने जवाब क्यों नहीं डालते? और शीर्ष पर नया उत्तर, इसलिए लोग समय बर्बाद नहीं करते हैं
goamn

19

मेरे 2 सेंट - आपको सर्वर पर एक भौतिक फ़ाइल के रूप में एक्सेल को संग्रहीत करने की आवश्यकता नहीं है - इसके बजाय, इसे (सत्र) कैश में संग्रहीत करें। अपने कैश वैरिएबल (जो कि एक्सेल फाइल को स्टोर करता है) के लिए विशिष्ट रूप से जेनरेट किए गए नाम का उपयोग करें - यह आपकी (आरंभिक) अजाक्स कॉल की वापसी होगी। इस तरह आपको फ़ाइल एक्सेस के मुद्दों से निपटना नहीं है, ज़रूरत न होने पर फ़ाइलों को प्रबंधित करना (हटाना), और, कैश में फ़ाइल रखने, इसे पुनः प्राप्त करने के लिए तेज़ है।


1
आप वास्तव में ऐसा कैसे करेंगे? दिलचस्प लगता है।
नतालिया

2
एक उदाहरण अच्छा होगा (मेरा मतलब है कि इसे कैश में कैसे स्टोर किया जाए, एक्सेल फाइल नहीं बनाई जा रही है)।
तडेज

हालांकि यह कितना मापनीय है? यदि कोई उपयोगकर्ता कई बड़ी रिपोर्ट डाउनलोड कर रहा है?
Zapnologica

यदि आप एज़्योर पर हैं, तो सत्र UNTIL का काम करेगा जिसे आप बंद कर देते हैं ARRAffinity।
जीशान ली सेप

14

मैं हाल ही में MVC में इसे पूरा करने में सक्षम था (हालांकि AJAX का उपयोग करने की कोई आवश्यकता नहीं थी) एक भौतिक फ़ाइल बनाए बिना और सोचा था कि मैं अपना डेटा ले लूंगा:

सुपर सरल जावास्क्रिप्ट समारोह (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 वर्ग में मैं एक्सेल फाइल बनाने के लिए 3rd पार्टी टूल ( GemBox.Spreadsheet ) का उपयोग करता हूं और इसमें सेव टू स्ट्रीम का ऑप्शन है। कहा जा रहा है कि, एक्सेल फाइल बनाने के कई तरीके हैं जो आसानी से मेमोरी स्ट्रीम में लिखे जा सकते हैं।

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, क्रोम, और फ़ायरफ़ॉक्स में, ब्राउज़र फ़ाइल डाउनलोड करने का संकेत देता है और कोई वास्तविक नेविगेशन नहीं होता है।


8

सबसे पहले कंट्रोलर एक्शन बनाएँ जो एक्सेल फाइल बनाएगा

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

और आखिरकार एमजेसी रेज़र व्यू से अजाक्स कॉल

//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 अनुरोध है)। आप डाउनलोड कार्रवाई में सत्र में फ़ाइल डेटा को हटाने का प्रबंधन भी कर सकते हैं।

सत्र सत्र भंडारण के आधार पर सत्र और मेमोरी का उपयोग कर सकते हैं और सत्र के दौरान कितनी फाइलें निर्यात की जाती हैं और यदि आपके पास कई उपयोगकर्ता हैं।

मैंने इसके बजाय TempData का उपयोग करने के लिए CSL से सीर साइड कोड अपडेट किया है।

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

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 कॉल सफलता ब्लॉक में, सफलता: समारोह (Rdata) {डिबगर; var बाइट्स = नया Uint8Array (Rdata.FileContents); var blob = new Blob ([बाइट्स), {प्रकार: "एप्लीकेशन / vnd.openxmlformats-officedocument.spreadsheetml.sheet"}); var लिंक = document.createElement ('a'); link.href = window.URL.createObjectURL (बूँद); link.download = "myFileName.xlsx"; link.click (); },
जीवीकेआरओ

कुछ ने उपरोक्त लिंक में एक्सेल फाइल डाउनलोड को लागू किया है, यह केवल @ html.Beginform () के लिए काम करता है, फिर छोटे बदलावों के लिए उस कोड की आवश्यकता होती है, AJAX कॉल सक्सेस ब्लॉक के लिए, कृपया इसे देखें, यह AJAX CALL में ठीक काम करता है
GVKINO

3
.ajax $ ({
                प्रकार: "प्राप्त करें",
                url: "/ होम / Downloadexcel /",
                contentType: "एप्लिकेशन / जसन; चारसेट = utf-8",
                डेटा: अशक्त,
                सफलता: समारोह (Rdata) {
                    डिबगर;
                    var बाइट्स = नया Uint8Array (Rdata.FileContents); 
                    var blob = new Blob ([बाइट्स), {प्रकार: "एप्लीकेशन / vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
                    var लिंक = document.createElement ('a');
                    link.href = window.URL.createObjectURL (बूँद);
                    link.download = "myFileName.xlsx";
                    link.click ();
                },
                त्रुटि: फ़ंक्शन (इरेट) {

                }

            });

1

स्वीकृत जवाब मेरे लिए काफी काम का नहीं था क्योंकि मुझे ajax कॉल से 502 बैड गेटवे का परिणाम मिला था, भले ही ऐसा लगता था कि सब कुछ कंट्रोलर से ठीक हो रहा था।

शायद मैं 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 को स्वाइप करना पड़ा।

जावास्क्रिप्ट JQuery फ़ाइल डाउनलोड प्लगइन का उपयोग करता है और 2 सफल कॉल होते हैं। एक POST (Params भेजने के लिए) और एक 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 पर आउट हो रही थी, जिसने हमारी फ़ाइल डाउनलोड को तोड़ दिया। इसके बजाय, मैं एक 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);
}

CLIENT ( अजाक्स पोस्ट से हैंडल फ़ाइल डाउनलोड का संशोधित संस्करण )

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

फ़ाइल नहीं खोल सकते हैं, एक्सेल सिर्फ खुला है और फिर बस खुद को बंद नहीं करता है, मैंने यहां तक ​​कि रॉन्ज से पहले स्ट्रीम (क्लोज) भी जोड़ा है लेकिन काम नहीं कर रहा है।
डेवोडे

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>*/

के पूरे मुद्दे चाल है कि लगता है, हम एक फार्म (एक पोस्ट कर रहे हैं हिस्सा उस्तरा दृश्य की) जिस पर हम कर रहे हैं बुला एक Action methodहै, जो रिटर्न: एक FileResultहै, और यह FileResultरिटर्न the Excel File..
और फ़िल्टर मान पोस्ट करने के लिए, के रूप में कहा, ( और यदि आपको इसकी आवश्यकता है, तो मैं एक अन्य कार्रवाई के लिए एक पोस्ट अनुरोध कर रहा हूं, जैसा कि वर्णन करने का प्रयास किया गया है।


-1

मैं Asp.Net WebForm का उपयोग कर रहा हूं और बस मैं सर्वर साइड से एक फाइल डाउनलोड करना चाहता हूं। बहुत लेख है लेकिन मुझे सिर्फ मूल उत्तर नहीं मिल रहा है। अब, मैंने एक बुनियादी तरीका आजमाया और उसे हासिल कर लिया।

यही मेरी समस्या है।

मुझे रनटाइम पर गतिशील रूप से बहुत सारे इनपुट बटन बनाने हैं। और मैं एक अद्वितीय फ़ाइलनंबर देने के साथ बटन डाउनलोड करने के लिए प्रत्येक बटन जोड़ना चाहता हूं।

मैं इस तरह से प्रत्येक बटन बनाता हूं:

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

प्रत्येक बटन इस अजाक्स विधि को बुलाता है।

$.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;
}

I लेकिन अगर रिस्पांस का उपयोग करके फ़ाइल डाउनलोड करने के लिए केवल बाइट सरणी भेजने का एक तरीका है। मैं इसका इस्तेमाल करना चाहता हूं।

मुझे उम्मीद है कि यह किसी के लिए भी उपयोगी होगा।


-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();
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.