FileResult का उपयोग करके Asp.Net MVC में किसी भी प्रकार की फ़ाइल डाउनलोड करें?


228

मैंने यह सुझाव दिया था कि मैं अपने Asp.Net MVC एप्लिकेशन से फ़ाइलों को डाउनलोड करने की अनुमति देने के लिए FileResult का उपयोग करूं। लेकिन इसका एकमात्र उदाहरण मुझे हमेशा छवि फ़ाइलों (सामग्री प्रकार छवि / जेपीईजी निर्दिष्ट करना) के साथ करना पड़ता है।

लेकिन क्या होगा अगर मैं फ़ाइल प्रकार नहीं जान सकता हूँ? मैं चाहता हूं कि उपयोगकर्ता मेरी साइट के फ़िलिया से किसी भी फ़ाइल को डाउनलोड करने में सक्षम हों।

मैंने ऐसा करने का एक तरीका पढ़ा था ( कोड के लिए एक पिछला पोस्ट देखें ), जो वास्तव में ठीक काम करता है, सिवाय एक बात के: सेव अस डायलॉग में आने वाली फाइल का नाम अंडरस्कोर के साथ फाइल पथ से समाप्‍त होता है ( folder_folder_file.ext)। इसके अलावा, ऐसा लगता है कि लोगों को लगता है कि मुझे इस कस्टम वर्ग का उपयोग करने के बजाय FileResult को वापस करना चाहिए जो मैंने BinaryContentResult पाया था।

किसी को भी एमवीसी में ऐसा डाउनलोड करने का "सही" तरीका पता है?

संपादित करें: मुझे उत्तर मिला (नीचे), लेकिन मैंने सोचा कि अगर कोई और दिलचस्पी रखता है तो मुझे पूर्ण कार्य कोड पोस्ट करना चाहिए:

public ActionResult Download(string filePath, string fileName)
{
    string fullName = Path.Combine(GetBaseDir(), filePath, fileName);

    byte[] fileBytes = GetFile(fullName);
    return File(
        fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

byte[] GetFile(string s)
{
    System.IO.FileStream fs = System.IO.File.OpenRead(s);
    byte[] data = new byte[fs.Length];
    int br = fs.Read(data, 0, data.Length);
    if (br != fs.Length)
        throw new System.IO.IOException(s);
    return data;
}

12
आप जो कर रहे हैं वह खतरनाक है। आप अपने सर्वर से किसी भी फ़ाइल को डाउनलोड करने के लिए उपयोगकर्ताओं को बहुत अधिक अनुमति दे रहे हैं जिसे निष्पादित उपयोगकर्ता एक्सेस कर सकता है।
पॉल फ्लेमिंग

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

2
क्या कोई उपकरण हैं जो आपको संभावित खतरनाक खामियों को खोजने की अनुमति देता है जैसे कि यह एक?
डेविड

मुझे लगता है कि यह stackoverflow.com/a/22231074/4573839Response.ContentType = MimeMapping.GetMimeMapping(filePath); से सामग्री प्रकार सेट करने के लिए सुविधाजनक है ,
यू यांग जियान

आप क्लाइंट की तरफ से क्या उपयोग कर रहे हैं?
FrenkyB

जवाबों:


425

आप सामान्य जेनेटिक-स्ट्रीम MIME प्रकार निर्दिष्ट कर सकते हैं:

public FileResult Download()
{
    byte[] fileBytes = System.IO.File.ReadAllBytes(@"c:\folder\myfile.ext");
    string fileName = "myfile.ext";
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

4
ठीक है, मैं कोशिश कर सकता है, लेकिन बाइट [] सरणी में क्या जाता है?
एंडर्स

3
कोई बात नहीं, मुझे लगता है कि मैंने इसे समझ लिया है। मैंने एक फाइलस्ट्रीम में फाइलनेम (पूर्ण पथ) पढ़ा और फिर एक बाइट सरणी में, और फिर इसने एक आकर्षण की तरह काम किया! धन्यवाद!
एंडर्स

5
यह पूरी फाइल को मेमोरी में लोड करता है बस इसे स्ट्रीम करने के लिए; बड़ी फ़ाइलों के लिए, यह एक हॉग है। एक बेहतर समाधान नीचे एक है जो फ़ाइल को पहले मेमोरी में लोड नहीं करना है।
HBlackorby

13
जैसा कि यह उत्तर लगभग पाँच साल पुराना है, हाँ। यदि आप बहुत बड़ी फ़ाइलों की सेवा करने के लिए ऐसा कर रहे हैं, तो न करें। यदि संभव हो, तो एक अलग स्टेटिक फाइल सर्वर का उपयोग करें, ताकि आप अपने एप्लिकेशन थ्रेड्स को टाई न करें, या 2010 से MVC में जोड़ी गई फ़ाइलों की सेवा के लिए कई नई तकनीकों में से एक है। यह सिर्फ MIME प्रकार अज्ञात होने पर उपयोग करने के लिए सही MIME प्रकार दिखाता है । ReadAllBytesएक एडिट में वर्षों बाद जोड़ा गया था। यह मेरा दूसरा सबसे उत्कट उत्तर क्यों है? ओह अच्छा।
इयान हेनरी

10
यह त्रुटि प्राप्त करना:non-invocable member "File" cannot be used like a method.
A-Sharabiani

105

MVC फ्रेमवर्क मूल रूप से इसका समर्थन करता है। System.Web.MVC.Controller.File नियंत्रक द्वारा एक फ़ाइल वापस जाने के लिए तरीके प्रदान नाम / धारा / सरणी

उदाहरण के लिए फ़ाइल के लिए वर्चुअल पथ का उपयोग करके आप निम्न कार्य कर सकते हैं।

return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet,  Path.GetFileName(virtualFilePath));

36

यदि आप .NET फ्रेमवर्क 4.5 का उपयोग कर रहे हैं, तो आप अपनी फ़ाइल के लिए माइम-टाइप प्राप्त करने के लिए MimeMapping.GetMimeMapping (स्ट्रिंग FileName) का उपयोग करते हैं। इस तरह मैंने इसे अपने एक्शन में इस्तेमाल किया है।

return File(Path.Combine(@"c:\path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName);

यह है कि माइम मैपिंग अच्छा है, लेकिन क्या यह पता लगाने की प्रक्रिया नहीं है कि रन टाइम में फाइल का प्रकार क्या है?
मोहम्मद नौरेलिन

@MohammedNoureldin यह "समझ" नहीं रहा है, फ़ाइल एक्सटेंशन या उसके बाद कुछ के आधार पर एक साधारण मानचित्रण तालिका है। सर्वर सभी स्थिर फ़ाइलों के लिए करता है, यह धीमा नहीं है।
अल कीप

13

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

मैंने इसे एक बार और यहाँ अपने कोड का उपयोग किया है।

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Download(int fileID)
        {
            Data.LinqToSql.File file = _fileService.GetByID(fileID);

            return new DownloadResult { VirtualPath = GetVirtualPath(file.Path),
                                        FileDownloadName = file.Name };
        }

मेरे उदाहरण में मैं फ़ाइलों का भौतिक पथ संग्रहीत कर रहा था, इसलिए मैंने इस सहायक विधि का उपयोग किया था-मुझे कहीं ऐसा मिला जिसे मैं याद नहीं कर सकता- इसे आभासी पथ में परिवर्तित करना

        private string GetVirtualPath(string physicalPath)
        {
            string rootpath = Server.MapPath("~/");

            physicalPath = physicalPath.Replace(rootpath, "");
            physicalPath = physicalPath.Replace("\\", "/");

            return "~/" + physicalPath;
        }

यहाँ पूरी कक्षा है, जैसा कि फिल हैक के लेख से लिया गया है

public class DownloadResult : ActionResult {

    public DownloadResult() {}

    public DownloadResult(string virtualPath) {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath {
        get;
        set;
    }

    public string FileDownloadName {
        get;
        set;
    }

    public override void ExecuteResult(ControllerContext context) {
        if (!String.IsNullOrEmpty(FileDownloadName)) {
            context.HttpContext.Response.AddHeader("content-disposition", 
            "attachment; filename=" + this.FileDownloadName)
        }

        string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
        context.HttpContext.Response.TransmitFile(filePath);
    }
}

1
ठीक है, हाँ, मैंने उस लेख को भी देखा, लेकिन यह उसी तरह का काम करता है जैसा कि मैंने जिस लेख का उपयोग किया था (मेरी पिछली पोस्ट का संदर्भ देखें), और वह खुद को पृष्ठ के शीर्ष पर कहता है कि वर्कअरेन चाहिए ' t की अब और आवश्यकता नहीं है क्योंकि: "NEW UPDATE: इस कस्टम एक्शनResult की अब कोई आवश्यकता नहीं है क्योंकि ASP.NET MVC अब बॉक्स में एक शामिल करता है।" लेकिन दुर्भाग्य से, वह इस बारे में कुछ और नहीं कहता कि इसका उपयोग कैसे किया जाए।
एंडर्स

@ManafAbuRous, यदि आप कोड को बारीकी से पढ़ते हैं तो आप देखेंगे कि यह वास्तव में आभासी पथ को भौतिक पथ में परिवर्तित करता है ( Server.MapPath(this.VirtualPath)) इसलिए बिना परिवर्तन के सीधे इसका सेवन करना एक बुरा अनुभव है। आपको एक वैकल्पिक उत्पादन करना चाहिए जो यह स्वीकार करता PhysicalPathहै कि आखिरकार क्या आवश्यक है और आप जो स्टोर कर रहे हैं वह है। यह बहुत अधिक सुरक्षित होगा क्योंकि आपने एक धारणा बनाई है कि भौतिक पथ और सापेक्ष पथ एक ही होगा (जड़ को छोड़कर)। डेटा फ़ाइलों को अक्सर संग्रहीत किया जाता है App_Data। यह एक सापेक्ष पथ के रूप में सुलभ नहीं है।
पॉल फ्लेमिंग

GetVirtualPath महान है .... बहुत उपयोगी है। धन्यवाद!
ज़वी रेडर

6

इयान हेनरी को धन्यवाद !

यदि आपको MS SQL सर्वर से फ़ाइल प्राप्त करने की आवश्यकता होती है तो इसका समाधान है।

public FileResult DownloadDocument(string id)
        {
            if (!string.IsNullOrEmpty(id))
            {
                try
                {
                    var fileId = Guid.Parse(id);

                    var myFile = AppModel.MyFiles.SingleOrDefault(x => x.Id == fileId);

                    if (myFile != null)
                    {
                        byte[] fileBytes = myFile.FileData;
                        return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, myFile.FileName);
                    }
                }
                catch
                {
                }
            }

            return null;
        }

कहाँ AppModel है EntityFrameworkमॉडल और MyFiles प्रस्तुत तालिका अपने डेटाबेस में। FileData है varbinary(MAX)में MyFiles तालिका।


2

इसकी सरल बस फ़ाइल नाम के साथ DirectoryPath में अपना भौतिक पथ दें

public FilePathResult GetFileFromDisk(string fileName)
{
    return File(directoryPath, "multipart/form-data", fileName);
}

ग्राहक पक्ष के बारे में क्या, इस विधि को बुला रहा है? यदि आप डायलॉग के रूप में सेव दिखाना चाहते हैं तो बताएं
FrenkyB

0
   public ActionResult Download()
        {
            var document = //Obtain document from database context
    var cd = new System.Net.Mime.ContentDisposition
    {
        FileName = document.FileName,
        Inline = false,
    };
            Response.AppendHeader("Content-Disposition", cd.ToString());
            return File(document.Data, document.ContentType);
        }

-1

अगर (string.IsNullOrWhiteSpace (fileName)) वापसी सामग्री ("फ़ाइल नाम मौजूद नहीं है");

        var path = Path.Combine(your path, your filename);

        var stream = new FileStream(path, FileMode.Open);

        return File(stream, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);

-4

GetFile फ़ाइल को बंद करना चाहिए (या इसका उपयोग करके इसे खोलना चाहिए)। तब आप बाइट्स में रूपांतरण के बाद फ़ाइल को हटा सकते हैं - डाउनलोड उस बाइट बफर पर किया जाएगा।

    byte[] GetFile(string s)
    {
        byte[] data;
        using (System.IO.FileStream fs = System.IO.File.OpenRead(s))
        {
            data = new byte[fs.Length];
            int br = fs.Read(data, 0, data.Length);
            if (br != fs.Length)
                throw new System.IO.IOException(s);
        }
        return data;
    }

तो अपने डाउनलोड विधि में ...

        byte[] fileBytes = GetFile(file);
        // delete the file after conversion to bytes
        System.IO.File.Delete(file);
        // have the file download dialog only display the base name of the file            return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(file));

2
कृपया कभी भी, पूरी फाइलों को मेमोरी में इस तरह लोड न करें
makhdumi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.