ASP.NET WebAPI में किसी फाइल (FileContentResult) को कैसे लौटाएं


173

एक नियमित MVC कंट्रोलर में, हम pdf को a के साथ आउटपुट कर सकते हैं FileContentResult

public FileContentResult Test(TestViewModel vm)
{
    var stream = new MemoryStream();
    //... add content to the stream.

    return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}

लेकिन हम इसे एक में कैसे बदल सकते हैं ApiController?

[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
     //...
     return Ok(pdfOutput);
}

यहाँ मैंने कोशिश की है, लेकिन यह काम नहीं कर रहा है।

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();
    //...
    var content = new StreamContent(stream);
    content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    content.Headers.ContentLength = stream.GetBuffer().Length;
    return Ok(content);            
}

ब्राउज़र में प्रदर्शित रिटर्न परिणाम है:

{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}

और SO पर एक समान पोस्ट है: ASP.NET वेब एपीआई में नियंत्रक से बाइनरी फ़ाइल लौटाता है । यह एक मौजूदा फ़ाइल आउटपुट के बारे में बात करता है। लेकिन मैं इसे एक धारा के साथ काम नहीं कर सका।

कोई सुझाव?


1
इस पोस्ट ने मेरी मदद की: stackoverflow.com/a/23768883/585552
ग्रेग

जवाबों:


199

के StreamContentरूप में लौटने के बजाय Content, मैं इसके साथ काम कर सकता हूं ByteArrayContent

[HttpGet]
public HttpResponseMessage Generate()
{
    var stream = new MemoryStream();
    // processing the stream.

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.ToArray())
    };
    result.Content.Headers.ContentDisposition =
        new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "CertificationCard.pdf"
    };
    result.Content.Headers.ContentType =
        new MediaTypeHeaderValue("application/octet-stream");

    return result;
}

2
यदि शीर्ष आधा आपके प्रश्न का उत्तर देता है, तो कृपया केवल एक उत्तर के रूप में पोस्ट करें। दूसरी छमाही एक अलग प्रश्न प्रतीत होता है - उसके लिए एक नया प्रश्न पोस्ट करें।
गन्र

3
नमस्ते, साझा करने के लिए धन्यवाद, एक सरल प्रश्न मिला (मुझे लगता है)। मेरे पास एक C # फ्रंट एंड है जो कि रिप्रेस्पोंसमेसेज प्राप्त करता है। मैं स्ट्रीमकंटेंट कैसे निकालूं और इसे उपलब्ध कराऊं ताकि उपयोगकर्ता इसे डिस्क या कुछ और (और मैं वास्तविक फ़ाइल प्राप्त कर सके) को बचा सके? धन्यवाद!
रोनाल्ड

7
मैं एक स्व-निर्मित एक्सेल फ़ाइल डाउनलोड करने का प्रयास कर रहा था। स्ट्रीम का उपयोग करना। GetBuffer () हमेशा एक दूषित एक्सेल लौटा। अगर इसके बजाय मैं स्ट्रीम का उपयोग करता हूं। तोरेर () फ़ाइल बिना किसी समस्या के उत्पन्न होती है। आशा है कि यह किसी की मदद करता है।
afnpires 15

4
@AlexandrePires ऐसा इसलिए है क्योंकि MemoryStream.GetBuffer()वास्तव में मेमोरीस्ट्रीम का बफर वापस आ जाता है, जो आम तौर पर स्ट्रीम की सामग्री (प्रविष्टि को कुशल बनाने के लिए) से बड़ा होता है। MemoryStream.ToArray()सामग्री के आकार में छोटा बफ़र लौटाता है।
M.Stramm

19
कृपया ऐसा करना बंद करें। इस तरह के मेमोरीस्ट्रीम के दुरुपयोग का कारण बनता है, अस्थिर कोड और धाराओं के उद्देश्य को पूरी तरह से अनदेखा करता है। सोचिये: byte[]बफ़र्स की जगह सबकुछ उजागर क्यों नहीं हुआ ? आपके उपयोगकर्ता आपके एप्लिकेशन को मेमोरी से आसानी से चला सकते हैं।
मकदूमि

97

यदि आप लौटना IHttpActionResultचाहते हैं तो आप इसे इस तरह से कर सकते हैं:

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.GetBuffer())
    };
    result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "test.pdf"
    };
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

    var response = ResponseMessage(result);

    return response;
}

3
IHttpActionResult वापसी प्रकार दिखाने के लिए अच्छा अद्यतन। इस कोड का एक रिफ्लेक्टर कॉल करने के लिए होगा एक कस्टम IHttpActionResult जैसे कि इसमें सूचीबद्ध है: stackoverflow.com/questions/23768596/…
जोश

यह पोस्ट एक अच्छा साफ एकल उपयोग कार्यान्वयन को प्रदर्शित करता है। मेरे मामले में, उपरोक्त लिंक में सूचीबद्ध सहायक विधि अधिक सहायक साबित हुई
हेंज़ोलो

45

इस सवाल ने मेरी मदद की।

तो, यह प्रयास करें:

नियंत्रक कोड:

[HttpGet]
public HttpResponseMessage Test()
{
    var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");;
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentLength = stream.Length;
    return result;          
}

Html मार्कअप देखें (क्लिक इवेंट और सरल यूआरएल के साथ):

<script type="text/javascript">
    $(document).ready(function () {
        $("#btn").click(function () {
            // httproute = "" - using this to construct proper web api links.
            window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })";
        });
    });
</script>


<button id="btn">
    Button text
</button>

<a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>

1
यहां आप FileStreamसर्वर पर मौजूदा फाइल के लिए उपयोग कर रहे हैं । यह थोड़ा अलग है MemoryStream। लेकिन इनपुट के लिए धन्यवाद।
ब्लेज़

4
यदि आप एक वेब सर्वर पर एक फ़ाइल से पढ़ते हैं, तो FileShare.Read के लिए अधिभार का उपयोग करना सुनिश्चित करें, अन्यथा आप उपयोग अपवादों में फ़ाइल का सामना कर सकते हैं।
जेरेमी बेल

यदि आप इसे मेमोरी स्ट्रीम से बदल देते हैं तो यह काम नहीं करेगा?
आलेहा

@JeremyBell यह सिर्फ एक अनुकरणीय उदाहरण है, कोई भी यहां उत्पादन और असफल-सुरक्षित संस्करण के बारे में बात नहीं करता है।
आले

1
@ इस कोड के साथ काम करता है, FileStreamलेकिन इसके साथ विफल रहता है के लिए नीचे देखें MemoryStream। यह मूल रूप से स्ट्रीम के साथ करने के लिए मिला है Position
एम। श्रमम

9

यहां एक कार्यान्वयन है जो फ़ाइल की सामग्री को बफरिंग के बिना स्ट्रीम करता है (बाइट में बफ़र करना] [] / MemoryStream, आदि यदि यह एक बड़ी फ़ाइल है तो सर्वर की समस्या हो सकती है।

public class FileResult : IHttpActionResult
{
    public FileResult(string filePath)
    {
        if (filePath == null)
            throw new ArgumentNullException(nameof(filePath));

        FilePath = filePath;
    }

    public string FilePath { get; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StreamContent(File.OpenRead(FilePath));
        var contentType = MimeMapping.GetMimeMapping(Path.GetExtension(FilePath));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        return Task.FromResult(response);
    }
}

यह बस इस तरह से इस्तेमाल किया जा सकता है:

public class MyController : ApiController
{
    public IHttpActionResult Get()
    {
        string filePath = GetSomeValidFilePath();
        return new FileResult(filePath);
    }
}

डाउनलोड हो जाने के बाद आप फ़ाइल को कैसे हटाएंगे? क्या डाउनलोड समाप्त होने पर अधिसूचित होने के लिए कोई हुक हैं?
कोस्टा

ठीक है, उत्तर एक्शन फ़िल्टर विशेषता को लागू करने और OnActionExecuted विधि में फ़ाइल को हटाने के लिए लगता है।
कोस्टा

5
इस पोस्ट को मिला Risord का जवाब: stackoverflow.com/questions/2041717/… । एक के var fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);बजाय इस लाइन का उपयोग कर सकते हैंFile.OpenRead(FilePath)
कोस्टा

7

मुझे बिल्कुल यकीन नहीं है कि किस हिस्से को दोष देना है, लेकिन यहां MemoryStreamआपके लिए क्यों काम नहीं करता है:

जैसा कि आप लिखते हैं MemoryStream, यह वृद्धि की Positionसंपत्ति है। निर्माणकर्ता StreamContentधारा की धारा को ध्यान में रखता हैPosition । इसलिए यदि आप स्ट्रीम को लिखते हैं, तो इसे पास करें StreamContent, स्ट्रीम के अंत में कुछ भी नहीं होने से प्रतिक्रिया शुरू हो जाएगी।

इसे ठीक करने के दो तरीके हैं:

1) निर्माण सामग्री, स्ट्रीम करने के लिए लिखें

[HttpGet]
public HttpResponseMessage Test()
{
    var stream = new MemoryStream();
    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StreamContent(stream);
    // ...
    // stream.Write(...);
    // ...
    return response;
}

2) स्ट्रीम, रिसेट पोजिशन, कंस्ट्रक्शन कंटेंट के लिए लिखें

[HttpGet]
public HttpResponseMessage Test()
{
    var stream = new MemoryStream();
    // ...
    // stream.Write(...);
    // ...
    stream.Position = 0;

    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StreamContent(stream);
    return response;
}

2) थोड़ा अच्छा लगता है यदि आपके पास एक ताजा स्ट्रीम है, तो 1) सरल है यदि आपकी धारा 0 पर शुरू नहीं होती है


यह कोड वास्तव में समस्या का कोई समाधान प्रदान नहीं करता है, क्योंकि यह उसी दृष्टिकोण का उपयोग करता है जिसका उल्लेख प्रश्न में किया गया था। प्रश्न पहले से ही बताता है कि यह काम नहीं करता है, और मैं इसकी पुष्टि कर सकता हूं। रिटर्न ओके (नया स्ट्रीमकंटेंट (स्ट्रीम)) JSON को स्ट्रीमकंटेंट का प्रतिनिधित्व देता है।
दिमित्रो ज़खरोव

कोड अपडेट किया गया। यह जवाब वास्तव में वेबएपी में फाइल को वापस करने के बजाय 'क्यों फाइलस्ट्रीम के साथ सरल समाधान काम करता है लेकिन मेमोरीस्ट्रीम नहीं' के अधिक सूक्ष्म सवाल का जवाब देता है।
M.Stramm

3

मेरे लिए यह अंतर था

var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

तथा

var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

पहला स्टिंगकॉन्टेंट का JSON प्रतिनिधित्व वापस कर रहा था: {"हेडर्स": [{"की": "कंटेंट-टाइप", "वैल्यू": ["एप्लिकेशन / ऑक्टेट-स्ट्रीम; charset = utf-8"]}};

जबकि दूसरा व्यक्ति उचित तरीके से फाइल लौटा रहा था।

ऐसा लगता है कि Request.CreateResponse में एक अधिभार है जो एक स्ट्रिंग को दूसरे पैरामीटर के रूप में लेता है और ऐसा लगता है कि वास्तविक सामग्री के बजाय, स्ट्रिंग स्ट्रिंग कंटेंट को स्वयं स्ट्रिंग के रूप में प्रस्तुत करने का कारण बन रहा था।

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