asp.net mvc - net - Manera recomendada para crear un ActionResult con una extensión de archivo
asp.net mvc form (4)
Así es como estoy haciendo algo similar. Lo estoy tratando como una descarga:
var disposition = String.Format(
"attachment;filename=/"{0}.csv/"", this.Model.Name);
Response.AddHeader("content-disposition", disposition);
Esto debería aparecer en el navegador como una descarga de archivos con el nombre de archivo dado.
Sin embargo, no puedo pensar en una razón por la cual el tuyo no funcionaría.
Necesito crear un ActionResult en una aplicación MVC de ASP.NET que tenga un tipo de archivo .csv.
Proporcionaré una lista de correo electrónico de "no llamar" a mis socios comerciales y quiero que tenga una extensión .csv en el tipo de archivo. Entonces se abrirá automáticamente en Excel.
http://www.example.com/mailinglist/donotemaillist.csv?password=12334
He hecho esto con éxito de la siguiente manera, pero quiero asegurarme de que esta sea la mejor manera y la mejor forma de hacerlo.
[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"
};
}
Este método de acción responderá bien al enlace anterior.
Me pregunto si existe alguna posibilidad de que surja un conflicto inesperado de tener una extensión de archivo como esta con una versión diferente de IIS, cualquier tipo de filtro ISAPI o cualquier otra cosa que no pueda imaginar ahora.
Necesito estar 100% seguro porque se lo proporcionaré a socios externos y no quiero tener que cambiar de opinión más adelante. Realmente no puedo ver ningún problema, pero tal vez haya algo oscuro, u otra forma más "MVC" de hacerlo.
Creo que su respuesta DEBE contener el encabezado "Disposición de contenido" en este caso. Crea ActionResult personalizado como este:
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);
}
}
}
Y úselo en su Acción en lugar de ContentResult:
return new MyCsvResult {
Content = Emails.Aggregate((a,b) => a + Environment.NewLine + b)
/* Optional
* , ContentEncoding = ""
* , Name = "DoNotEmailList.csv"
*/
};
La respuesta que aceptó es suficiente, pero mantiene el contenido de la salida en la memoria a medida que la genera. ¿Qué pasa si el archivo que genera es bastante grande? Por ejemplo, cuando vuelca un contenido de la tabla SQL. Su aplicación podría quedarse sin memoria. Lo que sí desea en este caso es usar FileStreamResult. Una forma de introducir los datos en el flujo podría ser usar tubería, como describí aquí
Utilicé la acción FileContentResult para hacer algo similar.
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");
}
Agregará el encabezado de disposición de contenido para usted.