简体   繁体   中英

Returning a file from ASP.Net Web API

I am trying to return a file from an ASP API method.

The strange thing is, it works in IE (It has been a long time since I have said that).

In other browsers (Chrome and Firefox) it repeats the call continuously (a breakpoint in the method gets hit multiple times)

Has anybody ever has anything like this, or does anyone know what might be causing this.

The code:

public async Task<HttpResponseMessage> GetExcel()
{
            var stream = await MakeReport();                
            var result = Request.CreateResponse(HttpStatusCode.OK);
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel");
            result.Content.Headers.ContentLength = stream.Length;
            result.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddDays(-1));
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("Attachment") { FileName = "Report.xlsx" };    
            return result;
}

I have also tried loading the stream into a byte array, and using a ByteArrayContent . I have checked the position of stream while in breat mode. Since id does work in IE I don't think there is anything wrong with the stream.

Incase one of these is doing something funny and instructing the browser to try again, this is a list of headers returned:

Access-Control-Allow-Credentials → true
Access-Control-Allow-Headers → X-Requested-With, origin, content-type, accept
Access-Control-Allow-Methods → GET, PUT, POST, DELETE, HEAD, OPTIONS
Access-Control-Allow-Origin → *
Cache-Control → no-cache
Content-Disposition → Attachment; filename=Report.xlsx
Content-Length → 16702
Content-Type → application/vnd.ms-excel
Date → Wed, 07 Feb 2018 06:08:17 GMT
Expires → -1
Pragma → no-cache
Request-Context → appId=cid-v1:8fcfeca5-8450-44d8-a0de-35724f4e81f3
Server → Microsoft-IIS/10.0
X-AspNet-Version → 4.0.30319
X-Powered-By → ASP.NET
X-SourceFiles → =?UTF-8?B?QzpcVXNlcnNcbWVcU291cmNlXFJlcG9zXE11c2tldGVlclxJR1NcYXBpXEV4Y2VsKDEwMjgyLDAsMCwwKQ==?=
X-StackifyID → V1|80000015-0002-f500-b63f-84710c7967bb|

Any ideas would be appreciated.

Try using a filestream result

public FileStreamResult GetExcel(){
    var memoryStream = new MemoryStream(stream);            
    string filename = "Report.xlsx";
    return new FileStreamResult(memoryStream, "application/vnd.ms-excel") { 
        FileDownloadName = filename };
}

Try, if this helps.

    public async Task<HttpResponseMessage> GetExcel()
    {
     var stream = await MakeReport();
        var result = Request.CreateResponse(HttpStatusCode.OK);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel");
        result.Content.Headers.ContentLength = stream.Length;
        result.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddDays(-1));
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("Attachment") { FileName = "Report.xlsx" };
        WriteFileToResponse(stream, result);
        return result;
    }

    protected override void WriteFileToResponse(Stream _stream, Response _response)
    {
        Stream _responseStream = _response.OutputStream;
        byte[] buffer = new byte[4096];
        while (true)
        {
            int num = this._stream.Read(buffer, 0, 4096);
            if (num == 0)
            {
                break;
            }
            _responseStream.Write(buffer, 0, num);
        }
    }

You should send the file as an binary file with the media type "application/octet-stream". This works in most browsers and when the attachment has a filename extension associated with it, the browser will try to resolve how to open the content by itself

protected async Task<HttpResponseMessage> GetExcel()
{
    var stream = await MakeReport();
    var byteArray = ToByteArray(stream);
    var result = new HttpResponseMessage(HttpStatusCode.OK);
    result.Content = new ByteArrayContent(byteArray);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); //attachment will force download
    result.Content.Headers.ContentDisposition.FileName = "Report.xlsx";
    return result;
}

public static byte[] ToByteArray(Stream input)
{
    using (MemoryStream ms = new MemoryStream())
    {
        input.CopyTo(ms);
        return ms.ToArray();
    }
}

You should care about MakeReport method, MemoryStream may help, like this:

    private async Task<Stream> MakeReport()
    {
        using (var file = new FileStream(@"[file path]", FileMode.Open))
        {
            var stream = new MemoryStream();
            await file.CopyToAsync(stream);
            return stream;
        }
    }

The method GetExcel looks good. (Tested with Chrome: file auto downloaded)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM