कैसे एक फ़ाइल पोस्ट स्वीकार करने के लिए


254

मैं एक आराम सेवा बनाने के लिए asp.net mvc 4 webapi बीटा का उपयोग कर रहा हूं। मुझे क्लाइंट एप्लिकेशन से पोस्ट की गई छवियों / फ़ाइलों को स्वीकार करने में सक्षम होने की आवश्यकता है। क्या वेबपी का उपयोग करना संभव है? नीचे बताया गया है कि मैं वर्तमान में कैसे क्रिया कर रहा हूं। क्या किसी को एक उदाहरण के बारे में पता है कि यह कैसे काम करना चाहिए?

[HttpPost]
public string ProfileImagePost(HttpPostedFile profileImage)
{
    string[] extensions = { ".jpg", ".jpeg", ".gif", ".bmp", ".png" };
    if (!extensions.Any(x => x.Equals(Path.GetExtension(profileImage.FileName.ToLower()), StringComparison.OrdinalIgnoreCase)))
    {
        throw new HttpResponseException("Invalid file type.", HttpStatusCode.BadRequest);
    }

    // Other code goes here

    return "/path/to/image.png";
}

3
यह केवल एमवीसी के साथ काम करता है न कि वेबएपीआई ढांचे का।
फिल

तुम बस से आइटम हड़पने के लिए सक्षम होना चाहिएRequest.Files
Tejs

7
ApiController में HttpRequestBase नहीं है जिसमें फ़ाइलें गुण हैं। यह अनुरोध वस्तु HttpRequestMessage वर्ग पर आधारित है।
फिल

जवाबों:


168

देखें http://www.asp.net/web-api/overview/formats-and-model-binding/html-forms-and-multipart-mime#multipartmime , हालांकि मुझे लगता है कि लेख से यह थोड़ा अधिक जटिल लगता है यह सचमुच में है।

मूल रूप से,

public Task<HttpResponseMessage> PostFile() 
{ 
    HttpRequestMessage request = this.Request; 
    if (!request.Content.IsMimeMultipartContent()) 
    { 
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); 
    } 

    string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads"); 
    var provider = new MultipartFormDataStreamProvider(root); 

    var task = request.Content.ReadAsMultipartAsync(provider). 
        ContinueWith<HttpResponseMessage>(o => 
    { 

        string file1 = provider.BodyPartFileNames.First().Value;
        // this is the file name on the server where the file was saved 

        return new HttpResponseMessage() 
        { 
            Content = new StringContent("File uploaded.") 
        }; 
    } 
    ); 
    return task; 
} 

5
सिर्फ एक फ़ाइल को पढ़ने के लिए टास्क का उपयोग करने से क्या लाभ है? असली सवाल, मैं सिर्फ टास्क का इस्तेमाल करने लगा हूं। मेरी वर्तमान समझ से, एक से अधिक फ़ाइल सही अपलोड करते समय यह कोड वास्तव में अनुकूल है?
क्रिस

48
MultipartFormDataStreamProvider के पास किसी भी अधिक (WebApi RTM में) BodyPartFileNames संपत्ति नहीं है। Asp.net/web-api/overview/working-with-http/…
Shrike

5
दोस्तों, क्या आप में से कुछ लोग इस बात पर कुछ प्रकाश डाल सकते हैं कि हम केवल HttpContext.Current.Request.Files का उपयोग करके फ़ाइलों तक क्यों नहीं पहुँच सकते हैं और इसके बजाय इस फैंसी मल्टीपार्टफ़ॉर्मटैडस्ट्रीमप्रोवाइडर का उपयोग करने की आवश्यकता है? पूर्ण प्रश्न: stackoverflow.com/questions/17967544
नियाहर

7
फ़ाइलें BodyPart_8b77040b-354b-464c-bc15-b3591f98f30f के रूप में सहेजी जा रही हैं । क्या उन्हें pic.jpg की तरह बचाया नहीं जाना चाहिए जैसा कि क्लाइंट पर था?
lbrahim

10
MultipartFormDataStreamProviderBodyPartFileNamesकिसी भी अधिक संपत्ति को उजागर नहीं करता है , मैं FileData.First().LocalFileNameइसके बजाय इस्तेमाल किया।
चिश्ती मालेक

374

मुझे आश्चर्य है कि आप में से बहुत से सर्वर पर फ़ाइलों को सहेजना चाहते हैं। स्मृति में सब कुछ रखने के लिए समाधान इस प्रकार है:

[HttpPost("api/upload")]
public async Task<IHttpActionResult> Upload()
{
    if (!Request.Content.IsMimeMultipartContent())
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); 

    var provider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(provider);
    foreach (var file in provider.Contents)
    {
        var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
        var buffer = await file.ReadAsByteArrayAsync();
        //Do whatever you want with filename and its binary data.
    }

    return Ok();
}

34
यदि आप डिस्कस्पेस खर्च नहीं करना चाहते हैं तो फाइलों को मेमोरी में रखना उपयोगी हो सकता है। हालाँकि, यदि आप बड़ी फ़ाइलों को अपलोड करने की अनुमति देते हैं, तो उन्हें स्मृति में रखने का अर्थ है कि आपका वेबसर्वर बहुत अधिक मेमोरी का उपयोग करेगा, जिसे अन्य अनुरोधों के लिए सामान रखने पर खर्च नहीं किया जा सकता है। यह उन सर्वरों पर समस्या पैदा करेगा जो उच्च भार के तहत काम करते हैं।
विलेम मीन्स

21
@ W.Meints मैं डेटा स्टोर करने के लिए इच्छुक कारणों को समझता हूं, लेकिन मुझे समझ में नहीं आता है कि कोई भी सर्वर डिस्क स्थान पर अपलोड किए गए डेटा को क्यों स्टोर करना चाहता है। आपको फ़ाइल भंडारण को हमेशा वेब-सर्वर से अलग रखना चाहिए - यहां तक ​​कि छोटी परियोजनाओं के लिए भी।
Gleno

1
सुनिश्चित करें कि आपकी पोस्ट की गई फ़ाइल का आकार कम है तो 64k, डिफ़ॉल्ट व्यवहार अनुरोधों को अनदेखा करना है अन्यथा, मैं इस पर लॉग समय के लिए अटक गया था।
गैरी डेविस

3
यदि आप प्रपत्र डेटा को पढ़ना चाहते हैं, तो दुर्भाग्य से, MultipartMemoryStreamProvider मदद नहीं करता है। एक MultipartFormDataMemoryStreamProvider की तरह कुछ बनाना चाहते थे, लेकिन बहुत सारे वर्ग और सहायक वर्ग एस्पेनेटवेस्टस्टैक में आंतरिक हैं :(
मार्टीनोस

9
File.WriteAllBytes(filename, buffer);इसे एक फाइल पर लिखने के लिए
pomber

118

नीचे दिए गए कोड को देखें, इस लेख से अनुकूलित , जो सबसे सरल उदाहरण कोड को प्रदर्शित करता है जो मुझे मिल सकता है। इसमें फ़ाइल और मेमोरी (तेज) अपलोड दोनों शामिल हैं ।

public HttpResponseMessage Post()
{
    var httpRequest = HttpContext.Current.Request;
    if (httpRequest.Files.Count < 1)
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }

    foreach(string file in httpRequest.Files)
    {
        var postedFile = httpRequest.Files[file];
        var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
        postedFile.SaveAs(filePath);
        // NOTE: To store in memory use postedFile.InputStream
    }

    return Request.CreateResponse(HttpStatusCode.Created);
}

26
HttpContext.Current शून्य है जब WebAPI को OWIN में होस्ट किया जाता है जो एक स्व होस्टिंग कंटेनर है।
Zach

1
इसे ऐसे ही तय करें: var httpRequest = System.Web.HttpContext.Current.Request;
msysmilu

7
जब तक आप पूरी तरह से WebAPI में System.Web का उपयोग न करें।
कुगेल

3
निश्चित बात, System.Web कसकर IIS के लिए युग्मित है। यदि आप OWIN piple लाइन या .net Core के भीतर काम कर रहे हैं, तो लिनक्स या स्व-होस्ट के तहत चलने पर वे API उपलब्ध नहीं होंगे।
कुगेल

2
बहुत बढ़िया जवाब। बस एक विवरण: यदि आप एक HTML पृष्ठ से अपलोड कर रहे हैं, तो <इनपुट प्रकार = "फ़ाइल" /> टैग में "नाम" विशेषता होनी चाहिए , या फ़ाइल HttpContext.Current.Request.Files में मौजूद नहीं होगी।
GBU

17

ASP.NET कोर तरीका अब यहाँ है :

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
    long size = files.Sum(f => f.Length);

    // full path to file in temp location
    var filePath = Path.GetTempFileName();

    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await formFile.CopyToAsync(stream);
            }
        }
    }

    // process uploaded files
    // Don't rely on or trust the FileName property without validation.

    return Ok(new { count = files.Count, size, filePath});
}

16

यहां एक त्वरित और गंदा समाधान है जो HTTP बॉडी से अपलोड की गई फ़ाइल सामग्री लेता है और इसे एक फाइल पर लिखता है। मैंने फ़ाइल अपलोड के लिए "नंगे हड्डियों" HTML / JS स्निपेट को शामिल किया।

वेब एपीआई विधि:

[Route("api/myfileupload")]        
[HttpPost]
public string MyFileUpload()
{
    var request = HttpContext.Current.Request;
    var filePath = "C:\\temp\\" + request.Headers["filename"];
    using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
    {
        request.InputStream.CopyTo(fs);
    }
    return "uploaded";
}

HTML फ़ाइल अपलोड:

<form>
    <input type="file" id="myfile"/>  
    <input type="button" onclick="uploadFile();" value="Upload" />
</form>
<script type="text/javascript">
    function uploadFile() {        
        var xhr = new XMLHttpRequest();                 
        var file = document.getElementById('myfile').files[0];
        xhr.open("POST", "api/myfileupload");
        xhr.setRequestHeader("filename", file.name);
        xhr.send(file);
    }
</script>

हालांकि सावधान रहें कि यह 'सामान्य' मल्टीपार्ट फॉर्म अपलोड के साथ काम नहीं करेगा।
टॉम

3
@ क्या मतलब है?
Chazt3n

इसका अर्थ है कि यह उन ब्राउज़र के साथ संगत नहीं है जहाँ जावास्क्रिप्ट अक्षम है / गैर-मौजूद है, उदाहरण के लिए नेटस्केप 1. *।
मिकेल डूई बोलिंदर

13

इससे पहले कि मैं अपने webapi mvc4 परियोजना में सभी NuGets को अद्यतन करने से पहले मैंने माइक वासन के उत्तर का उपयोग किया। एक बार जब मैंने किया, मुझे फ़ाइल अपलोड कार्रवाई को फिर से लिखना पड़ा:

    public Task<HttpResponseMessage> Upload(int id)
    {
        HttpRequestMessage request = this.Request;
        if (!request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
        }

        string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads");
        var provider = new MultipartFormDataStreamProvider(root);

        var task = request.Content.ReadAsMultipartAsync(provider).
            ContinueWith<HttpResponseMessage>(o =>
            {
                FileInfo finfo = new FileInfo(provider.FileData.First().LocalFileName);

                string guid = Guid.NewGuid().ToString();

                File.Move(finfo.FullName, Path.Combine(root, guid + "_" + provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "")));

                return new HttpResponseMessage()
                {
                    Content = new StringContent("File uploaded.")
                };
            }
        );
        return task;
    }

जाहिरा तौर पर BodyPartFileNames अब MultipartFormDataStreamProvider के भीतर उपलब्ध नहीं है।


WebApi RTM में BodyPartFileNames को FileData में बदल दिया गया है। Asp.net/web-api/overview/working-with-http/…
मार्क वैन स्ट्रैटन

सिर्फ System.Web.HttpContext.Current.Request.Files संग्रह का उपयोग क्यों नहीं किया जाता है?
ADOConnection

मैं 2 आरक्षणों के साथ आपके तरीके का उपयोग करने की सोच रहा हूं: 1) क्या यह दो बार नहीं लिखते हैं: i) में ReadAsMultipartAsyncऔर (ii) में File.Move? 2) क्या आप कर सकते हैं async File.Move?
seebiscuit

1) मेरे पास दो लिखने वाले मुद्दे नहीं थे, क्या यूआरएल को दो बार कहा जा रहा है? 2) आप टास्क कर सकते हैं। () () => {File.Move (src, dest);});
स्टीव स्टोक्स

10

इसी दिशा में, मैं एक क्लाइंट और सर्वर स्निपेट पोस्ट कर रहा हूं जो WebApi, c # 4 का उपयोग करके एक्सेल फाइल भेजते हैं:

public static void SetFile(String serviceUrl, byte[] fileArray, String fileName)
{
    try
    {
        using (var client = new HttpClient())
        {
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                using (var content = new MultipartFormDataContent())
                {
                    var fileContent = new ByteArrayContent(fileArray);//(System.IO.File.ReadAllBytes(fileName));
                    fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                    {
                        FileName = fileName
                    };
                    content.Add(fileContent);
                    var result = client.PostAsync(serviceUrl, content).Result;
                }
        }
    }
    catch (Exception e)
    {
        //Log the exception
    }
}

और सर्वर webapi नियंत्रक:

public Task<IEnumerable<string>> Post()
{
    if (Request.Content.IsMimeMultipartContent())
    {
        string fullPath = HttpContext.Current.Server.MapPath("~/uploads");
        MyMultipartFormDataStreamProvider streamProvider = new MyMultipartFormDataStreamProvider(fullPath);
        var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
                    throw new HttpResponseException(HttpStatusCode.InternalServerError);

            var fileInfo = streamProvider.FileData.Select(i =>
            {
                var info = new FileInfo(i.LocalFileName);
                return "File uploaded as " + info.FullName + " (" + info.Length + ")";
            });
            return fileInfo;

        });
        return task;
    }
    else
    {
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
    }
}

: और कस्टम MyMultipartFormDataStreamProvider, अनुकूलित करने के लिए फ़ाइल नाम की जरूरत

पुनश्च: मैं एक और पद से इस कोड को ले लिया http://www.codeguru.com/csharp/.net/uploading-files-asynchronously-using-asp.net-web-api .htm

public class MyMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
    public MyMultipartFormDataStreamProvider(string path)
        : base(path)
    {

    }

    public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
    {
        string fileName;
        if (!string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName))
        {
            fileName = headers.ContentDisposition.FileName;
        }
        else
        {
            fileName = Guid.NewGuid().ToString() + ".data";
        }
        return fileName.Replace("\"", string.Empty);
    }
}

क्या आप दिखा सकते हैं कि आप static method SetFileअपने नियंत्रक में आपको कैसे बुलाते हैं ?

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

6
[HttpPost]
public JsonResult PostImage(HttpPostedFileBase file)
{
    try
    {
        if (file != null && file.ContentLength > 0 && file.ContentLength<=10485760)
        {
            var fileName = Path.GetFileName(file.FileName);                                        

            var path = Path.Combine(Server.MapPath("~/") + "HisloImages" + "\\", fileName);

            file.SaveAs(path);
            #region MyRegion
            ////save imag in Db
            //using (MemoryStream ms = new MemoryStream())
            //{
            //    file.InputStream.CopyTo(ms);
            //    byte[] array = ms.GetBuffer();
            //} 
            #endregion
            return Json(JsonResponseFactory.SuccessResponse("Status:0 ,Message: OK"), JsonRequestBehavior.AllowGet);
        }
        else
        {
            return Json(JsonResponseFactory.ErrorResponse("Status:1 , Message: Upload Again and File Size Should be Less Than 10MB"), JsonRequestBehavior.AllowGet);
        }
    }
    catch (Exception ex)
    {

        return Json(JsonResponseFactory.ErrorResponse(ex.Message), JsonRequestBehavior.AllowGet);

    }
}

6
मुझे लगता है कि उपयोगकर्ता को कुछ स्पष्टीकरण की आवश्यकता है ...!
कामेश

4

फ़ाइल स्वीकार करने के दो तरीके यहां दिए गए हैं। एक मेमोरी प्रोवाइडर मल्टीपार्टमेमोरीस्ट्रीमप्रोवाइडर में एक और एक मल्‍टीपार्टफॉरमडैटास्‍ट्रीमप्रोवाइडर जो एक डिस्‍क में सेव करता है। ध्यान दें, यह एक समय में केवल एक फ़ाइल अपलोड के लिए है। आप कई फ़ाइलों को सहेजने के लिए निश्चित रूप से इसका विस्तार कर सकते हैं। दूसरा दृष्टिकोण बड़ी फ़ाइलों का समर्थन कर सकता है। मैंने 200MB से अधिक फ़ाइलों का परीक्षण किया है और यह ठीक काम करता है। मेमोरी एप्रोच का उपयोग करने के लिए आपको डिस्क को सहेजने की आवश्यकता नहीं होती है, लेकिन यदि आप एक निश्चित सीमा से अधिक हो जाते हैं तो मेमोरी अपवाद से बाहर निकल जाएंगे।

private async Task<Stream> ReadStream()
{
    Stream stream = null;
    var provider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(provider);
    foreach (var file in provider.Contents)
    {
        var buffer = await file.ReadAsByteArrayAsync();
        stream = new MemoryStream(buffer);
    }

    return stream;
}

private async Task<Stream> ReadLargeStream()
{
    Stream stream = null;
    string root = Path.GetTempPath();
    var provider = new MultipartFormDataStreamProvider(root);
    await Request.Content.ReadAsMultipartAsync(provider);
    foreach (var file in provider.FileData)
    {
        var path = file.LocalFileName;
        byte[] content = File.ReadAllBytes(path);
        File.Delete(path);
        stream = new MemoryStream(content);
    }

    return stream;
}

1

मुझे पूर्वावलोकन वेब एपीआई के लिए एक समान समस्या थी। उस भाग को नए MVC 4 वेब एपीआई के लिए अभी तक पोर्ट नहीं किया था, लेकिन शायद इससे मदद मिलती है:

HESTpRequestMessage या स्ट्रीम के साथ REST फ़ाइल अपलोड?

कृपया मुझे बताएं, कल बैठ सकते हैं और इसे फिर से लागू करने का प्रयास कर सकते हैं।


1

इस सवाल के बहुत सारे अच्छे जवाब हैं। नेट कोर के लिए भी। मैं दोनों फ्रेमवर्क का उपयोग कर रहा था, बशर्ते कोड के नमूने ठीक काम करें। इसलिए मैं इसे नहीं दोहराऊंगा। मेरे मामले में महत्वपूर्ण बात यह थी कि इस तरह से स्वैगर के साथ फाइल अपलोड एक्शन का उपयोग कैसे किया जाए :

स्वैगर में फाइल अपलोड बटन

यहाँ मेरा पुनर्कथन है:

ASP .Net WebAPI 2

.NET कोर


1

एपीआई नियंत्रक:

[HttpPost]
public HttpResponseMessage Post()
{
    var httpRequest = System.Web.HttpContext.Current.Request;

    if (System.Web.HttpContext.Current.Request.Files.Count < 1)
    {
        //TODO
    }
    else
    {

    try
    { 
        foreach (string file in httpRequest.Files)
        { 
            var postedFile = httpRequest.Files[file];
            BinaryReader binReader = new BinaryReader(postedFile.InputStream);
            byte[] byteArray = binReader.ReadBytes(postedFile.ContentLength);

        }

    }
    catch (System.Exception e)
    {
        //TODO
    }

    return Request.CreateResponse(HttpStatusCode.Created);
}

0

मैट फ्रियर के उत्तर को लागू करना - फाइल को सीधे स्ट्रीम से पढ़ना, बिना सेविंग और रीडिंग के पढ़ने के लिए एएसपी नेट कोर विकल्प होगा:

public ActionResult OnPostUpload(List<IFormFile> files)
    {
        try
        {
            var file = files.FirstOrDefault();
            var inputstream = file.OpenReadStream();

            XSSFWorkbook workbook = new XSSFWorkbook(stream);

            var FIRST_ROW_NUMBER = {{firstRowWithValue}};

            ISheet sheet = workbook.GetSheetAt(0);
            // Example: var firstCellRow = (int)sheet.GetRow(0).GetCell(0).NumericCellValue;

            for (int rowIdx = 2; rowIdx <= sheet.LastRowNum; rowIdx++)
               {
                  IRow currentRow = sheet.GetRow(rowIdx);

                  if (currentRow == null || currentRow.Cells == null || currentRow.Cells.Count() < FIRST_ROW_NUMBER) break;

                  var df = new DataFormatter();                

                  for (int cellNumber = {{firstCellWithValue}}; cellNumber < {{lastCellWithValue}}; cellNumber++)
                      {
                         //business logic & saving data to DB                        
                      }               
                }
        }
        catch(Exception ex)
        {
            throw new FileFormatException($"Error on file processing - {ex.Message}");
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.