Подтвердить что ты не робот

Рекомендуемый способ создания ActionResult с расширением файла

Мне нужно создать ActionResult в приложении ASP.NET MVC с файлом типа .csv.

Я предоставлю список адресов электронной почты "не звоню" моим партнерам по маркетингу, и я хочу, чтобы у него было расширение .csv в файле. Затем он автоматически откроется в Excel.

 http://www.example.com/mailinglist/donotemaillist.csv?password=12334

Я успешно сделал это следующим образом, но я хочу убедиться, что это самый лучший и рекомендуемый способ сделать это.

    [ActionName("DoNotEmailList.csv")]
    public ContentResult DoNotEmailList(string username, string password)
    {
            return new ContentResult()
            {
                Content = Emails.Aggregate((a,b)=>a+Environment.NewLine + b), 
                ContentType = "text/csv"
            };
    }

Этот ActionMethod будет отлично реагировать на указанную ссылку.

Мне просто интересно, есть ли какие-либо неожиданные конфликты с тем, что расширение файла похоже на любую другую версию IIS, любой фильтр ISAPI или что-то еще, о чем я не могу сейчас думать.

Мне нужно быть на 100% уверенным, потому что я буду предоставлять это внешним партнерам и не хочу менять свое мнение позже. Я действительно не вижу никаких проблем, но, возможно, что-то неявное - или еще один "MVC", как способ сделать это.

4b9b3361

Ответ 1

Я думаю, что ваш ответ должен содержать заголовок Content-Disposition в этом случае. Создайте собственный ActionResult следующим образом:

public class MyCsvResult : ActionResult {

    public string Content {
        get;
        set;
    }

    public Encoding ContentEncoding {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }

    public override void ExecuteResult(ControllerContext context) {
        if (context == null) {
            throw new ArgumentNullException("context");
        }

        HttpResponseBase response = context.HttpContext.Response;

        response.ContentType = "text/csv";

        if (ContentEncoding != null) {
            response.ContentEncoding = ContentEncoding;
        }

        var fileName = "file.csv";

        if(!String.IsNullOrEmpty(Name)) {
            fileName = Name.Contains('.') ? Name : Name + ".csv";
        }

        response.AddHeader("Content-Disposition",
            String.Format("attachment; filename={0}", fileName));

        if (Content != null) {
            response.Write(Content);
        }
    }
}

И используйте его в своем Action вместо ContentResult:

return new MyCsvResult {
    Content = Emails.Aggregate((a,b) => a + Environment.NewLine + b)
    /* Optional
     * , ContentEncoding = ""
     * , Name = "DoNotEmailList.csv"
     */
};

Ответ 2

Я использовал действие FileContentResult, чтобы сделать что-то подобное.

public FileContentResult DoNotEmailList(string username, string password)
{
        string csv = Emails.Aggregate((a,b)=>a+Environment.NewLine + b);
        byte[] csvBytes = ASCIIEncoding.ASCII.GetBytes( csv );
        return File(csvBytes, "text/csv", "DoNotEmailList.csv")
}

Он добавит вам заголовок содержимого.

Ответ 3

Вот как я делаю что-то подобное. Я рассматриваю его как загрузку:

var disposition = String.Format(
  "attachment;filename=\"{0}.csv\"", this.Model.Name);
Response.AddHeader("content-disposition", disposition);

Это должно отображаться в браузере в виде загрузки файла с заданным именем файла.

Я не могу думать о причине, почему твоя работа не будет работать.

Ответ 4

Ответ, который вы приняли, достаточно хорош, но он сохраняет содержимое вывода в памяти, когда он выводит его. Что делать, если файл, который он создает, довольно большой? Например, когда вы выгружаете содержимое таблицы SQL. У вашего приложения может быть нехватка памяти. В этом случае вы хотите использовать FileStreamResult. Один из способов подачи данных в поток мог бы использовать pipe, как я описал здесь