Cách đặt tên tệp tải xuống trong ASP.NET Web API


140

Trong lớp ApiControll của tôi, tôi có phương pháp sau để tải xuống một tệp được tạo bởi máy chủ.

public HttpResponseMessage Get(int id)
{
    try
    {
        string dir = HttpContext.Current.Server.MapPath("~"); //location of the template file
        Stream file = new MemoryStream();
        Stream result = _service.GetMyForm(id, dir, file);
        if (result == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        result.Position = 0;
        HttpResponseMessage response = new HttpResponseMessage();
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new StreamContent(result);
        return response;
    }
    catch (IOException)
    {
        return Request.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

Mọi thứ đều hoạt động hoàn hảo ngoại trừ tên tệp tải xuống mặc định là id của nó, vì vậy người dùng có thể phải nhập tên tệp của chính mình vào lưu dưới dạng hộp thoại mỗi lần. Có cách nào để đặt tên tệp mặc định trong mã ở trên không?


1
bạn có thể chia sẻ mã mà bạn đã sử dụng để gọi phương thức này không?
Yasser Shaikh

@Yasser - đây là một phương thức điều khiển API web - có thể nó được gọi thông qua các yêu cầu HTTP đến IIS và phân tích cú pháp chúng và tìm các tuyến đường và API web gọi phương thức này (và tất nhiên, nó cũng được gọi bằng các thử nghiệm).
Dave Rael

chuyện gì đang xảy ra bên trong GetMyForm ()? Chuyển đổi các tập tin thành luồng byte?
MSIslam

@MSIslam Sắp xếp của. Hàm lấy thông tin từ biểu mẫu của người dùng và tạo một tệp trước khi chuyển đổi thành luồng kết quả.
Tae-Sung Shin

Câu trả lời:


288

Bạn cần đặt Content-Dispositiontiêu đề trên HttpResponseMessage:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(result);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = "foo.txt"
};

21
Đối với bất kỳ ai tò mò về loại bố trí "tệp đính kèm", danh sách đầy đủ các loại sắp xếp có tại iana.org/assignments/cont-disp/cont-disp.xhtml
sfuqua

1
Bạn có một câu trả lời khác để tải xuống một tập tin ở đây. Có vấn đề gì cho dù bạn sử dụng System.Net.Mime.ContentDispositionhay ContentDispositionHeaderValue? Là một trong những hiện tại và được ưa thích hơn so với cái khác?
Sáng

@ Một câu trả lời là dành cho ActionResult, một choHttpResponseMessage
weston

@weston câu trả lời của bạn không trả lời câu hỏi của tôi.
Sáng

4
@Lum "Có vấn đề gì không" và "Có phải cái này hiện tại và được ưa thích hơn cái kia không?" Không và không. Một là cho MVC ActionResultvà một dành cho WebApi HttpResponseMessage.
weston

27

EDIT: Như đã đề cập trong một bình luận, Câu trả lời của tôi không giải thích cho các ký tự cần được thoát như a ;. Bạn nên sử dụng câu trả lời được chấp nhận mà Darin đưa ra nếu tên tệp của bạn có thể chứa dấu chấm phẩy.

Thêm một phản hồi. Thêm địa chỉ để đặt tên tệp

Response.AddHeader("Content-Disposition", "attachment; filename=*FILE_NAME*");

Chỉ cần thay đổi FILE_NAME thành tên của tệp.


2
Điều này tỏ ra hữu ích cho tôi trong việc giải quyết một vấn đề tương tự với người hỏi. Trong trường hợp của tôi, tôi cũng thấy hữu ích khi thay đổi "tệp đính kèm" thành "nội tuyến" để IE8 sẽ cung cấp cho tôi tùy chọn để luôn mở loại tệp được đề cập.
Scott

2
Không bao gồm thoát. Điều gì nếu tên tập tin bao gồm một ;hoặc một cái gì đó khác có ý nghĩa đặc biệt?
Sam

Sam, tại thời điểm tôi viết câu trả lời này 3 năm trước, tôi đã không nhận ra câu trả lời của mình là cần thiết để xử lý việc trốn thoát. Cảm ơn bạn đã chỉ ra điều này cho tôi, tôi đã chỉnh sửa câu trả lời của mình để giải thích câu trả lời của tôi không có tài khoản để thoát. Nhưng giữ câu trả lời của tôi như vậy vì nó dường như đã giúp mọi người.
KingPancake

8

Nếu bạn muốn đảm bảo rằng tên tệp được mã hóa chính xác nhưng cũng tránh được httpResponseMessage của WebApi, bạn có thể sử dụng như sau:

Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition("attachment") { FileName = "foo.txt" }.ToString());

Bạn có thể sử dụng ContentDisposeition hoặc ContentDisposeitionHeaderValue. Gọi ToString theo một ví dụ của một trong hai sẽ thực hiện mã hóa tên tệp cho bạn.


6

Tôi nghĩ rằng điều này có thể hữu ích cho bạn.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)

4
Không bao gồm thoát. Điều gì nếu tên tập tin bao gồm một ;hoặc một cái gì đó khác có ý nghĩa đặc biệt?
Sam

3

Bạn cần thêm tiêu đề xử lý nội dung vào phản hồi:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;

3
Không bao gồm thoát. Điều gì nếu tên tập tin bao gồm một ;hoặc một cái gì đó khác có ý nghĩa đặc biệt?
Sam

3

Nếu bạn đang sử dụng ASP.NET Core MVC, các câu trả lời ở trên sẽ bị thay đổi một chút ...

Trong phương thức hành động của tôi (trả về async Task<JsonResult>) tôi thêm dòng (bất cứ nơi nào trước câu lệnh return):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");

Không bao gồm thoát. Nếu tên tệp bao gồm a; hoặc một cái gì đó khác với một ý nghĩa đặc biệt?
KoalaBear

2

Điều này nên làm:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)

2
Không bao gồm thoát. Điều gì nếu tên tập tin bao gồm một ;hoặc một cái gì đó khác có ý nghĩa đặc biệt?
Sam

0

Lưu ý: Dòng cuối cùng là bắt buộc.

Nếu chúng tôi không chỉ định Tiêu đề kiểm soát truy cập , chúng tôi sẽ không nhận được Tên tệp trong giao diện người dùng.

FileInfo file = new FileInfo(FILEPATH);

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = file.Name
};
response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

0

Xem xét các câu trả lời trước đó, cần phải cẩn thận với các ký tự toàn cầu hóa.

Giả sử tên của tệp là: " Esdrújula prenda ñame - güena.jpg "

Kết quả thô để tải xuống: "Esdrújula prenda à ± ame - güena.jpg" [Xấu xí]

Kết quả HtmlEncode để tải xuống: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Xấu xí]

Kết quả UrlEncode để tải xuống: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

Sau đó, bạn cần hầu như luôn luôn sử dụng UrlEncode trên tên tệp . Hơn nữa, nếu bạn đặt tiêu đề sắp xếp nội dung thành chuỗi trực tiếp, thì bạn cần đảm bảo bao quanh với dấu ngoặc kép để tránh các vấn đề tương thích trình duyệt.

Response.AddHeader("Content-Disposition", $"attachment; filename=\"{HttpUtility.UrlEncode(YourFilename)}\"");

hoặc với sự trợ giúp của lớp học:

var cd = new ContentDisposition("attachment") { FileName = HttpUtility.UrlEncode(resultFileName) };
Response.AddHeader("Content-Disposition", cd.ToString());

System.Net.Mime. Lớp ContentDisposeition chăm sóc dấu ngoặc kép.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.