tutorial net mvc asp asp.net asp.net-mvc image controller

asp.net - net - web forms c#



¿Puede un controlador MVC de ASP.NET devolver una imagen? (15)

¿Puedo crear un controlador que simplemente devuelva un activo de imagen?

Me gustaría enrutar esta lógica a través de un controlador, siempre que se solicite una URL como la siguiente:

www.mywebsite.com/resource/image/topbanner

El controlador buscará topbanner.png y enviará esa imagen directamente al cliente.

He visto ejemplos de esto en los que tiene que crear una Vista, no quiero usar una Vista. Quiero hacerlo todo solo con el controlador.

es posible?


¿Por qué no ir simple y usar el operador tilde ~ ?

public FileResult TopBanner() { return File("~/Content/images/topbanner.png", "image/png"); }


Esto funcionó para mí. Desde que estoy almacenando imágenes en una base de datos de SQL Server.

[HttpGet("/image/{uuid}")] public IActionResult GetImageFile(string uuid) { ActionResult actionResult = new NotFoundResult(); var fileImage = _db.ImageFiles.Find(uuid); if (fileImage != null) { actionResult = new FileContentResult(fileImage.Data, fileImage.ContentType); } return actionResult; }

En el fragmento de _db.ImageFiles.Find(uuid) anterior _db.ImageFiles.Find(uuid) está buscando el registro del archivo de imagen en la base de datos (contexto EF). Devuelve un objeto FileImage que es solo una clase personalizada que hice para el modelo y luego lo usa como FileContentResult.

public class FileImage { public string Uuid { get; set; } public byte[] Data { get; set; } public string ContentType { get; set; } }


Esto podría ser útil si desea modificar la imagen antes de devolverla:

public ActionResult GetModifiedImage() { Image image = Image.FromFile(Path.Combine(Server.MapPath("/Content/images"), "image.png")); using (Graphics g = Graphics.FromImage(image)) { // do something with the Graphics (eg. write "Hello World!") string text = "Hello World!"; // Create font and brush. Font drawFont = new Font("Arial", 10); SolidBrush drawBrush = new SolidBrush(Color.Black); // Create point for upper-left corner of drawing. PointF stringPoint = new PointF(0, 0); g.DrawString(text, drawFont, drawBrush, stringPoint); } MemoryStream ms = new MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); return File(ms.ToArray(), "image/png"); }


Mira a ContentResult. Esto devuelve una cadena, pero se puede usar para hacer su propia clase BinaryResult-like.


Para explandir ligeramente la respuesta de Dyland:

Tres clases implementan la clase FileResult :

System.Web.Mvc.FileResult System.Web.Mvc.FileContentResult System.Web.Mvc.FilePathResult System.Web.Mvc.FileStreamResult

Todos son bastante auto explicativos:

  • Para las descargas de rutas de archivos donde el archivo existe en el disco, use FilePathResult , esta es la forma más fácil y evita tener que usar Streams.
  • Para las matrices de bytes [] (similar a Response.BinaryWrite), use FileContentResult .
  • Para las matrices de bytes [] donde desea que se descargue el archivo (content-disposition: attachment), use FileStreamResult de forma similar a la de abajo, pero con MemoryStream y usando GetBuffer() .
  • Para Streams use FileStreamResult . Se llama FileStreamResult pero toma un Stream así que supongo que funciona con un MemoryStream .

A continuación se muestra un ejemplo del uso de la técnica de disposición de contenido (no probada):

[AcceptVerbs(HttpVerbs.Post)] public ActionResult GetFile() { // No need to dispose the stream, MVC does it for you string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "myimage.png"); FileStream stream = new FileStream(path, FileMode.Open); FileStreamResult result = new FileStreamResult(stream, "image/png"); result.FileDownloadName = "image.png"; return result; }


Puede usar HttpContext.Response y escribir directamente el contenido (WriteFile () podría funcionar para usted) y luego devolver ContentResult de su acción en lugar de ActionResult.

Descargo de responsabilidad: no he intentado esto, se basa en observar las API disponibles. :-)


Puedes crear tu propia extensión y hacerlo de esta manera.

public static class ImageResultHelper { public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height) where T : Controller { return ImageResultHelper.Image<T>(helper, action, width, height, ""); } public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height, string alt) where T : Controller { var expression = action.Body as MethodCallExpression; string actionMethodName = string.Empty; if (expression != null) { actionMethodName = expression.Method.Name; } string url = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection).Action(actionMethodName, typeof(T).Name.Remove(typeof(T).Name.IndexOf("Controller"))).ToString(); //string url = LinkBuilder.BuildUrlFromExpression<T>(helper.ViewContext.RequestContext, helper.RouteCollection, action); return string.Format("<img src=/"{0}/" width=/"{1}/" height=/"{2}/" alt=/"{3}/" />", url, width, height, alt); } } public class ImageResult : ActionResult { public ImageResult() { } public Image Image { get; set; } public ImageFormat ImageFormat { get; set; } public override void ExecuteResult(ControllerContext context) { // verify properties if (Image == null) { throw new ArgumentNullException("Image"); } if (ImageFormat == null) { throw new ArgumentNullException("ImageFormat"); } // output context.HttpContext.Response.Clear(); context.HttpContext.Response.ContentType = GetMimeType(ImageFormat); Image.Save(context.HttpContext.Response.OutputStream, ImageFormat); } private static string GetMimeType(ImageFormat imageFormat) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); return codecs.First(codec => codec.FormatID == imageFormat.Guid).MimeType; } } public ActionResult Index() { return new ImageResult { Image = image, ImageFormat = ImageFormat.Jpeg }; } <%=Html.Image<CapchaController>(c => c.Index(), 120, 30, "Current time")%>


Puedes escribir directamente a la respuesta, pero entonces no es comprobable. Es preferible devolver un ActionResult que tenga ejecución diferida. Aquí está mi StreamResult resusable:

public class StreamResult : ViewResult { public Stream Stream { get; set; } public string ContentType { get; set; } public string ETag { get; set; } public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.ContentType = ContentType; if (ETag != null) context.HttpContext.Response.AddHeader("ETag", ETag); const int size = 4096; byte[] bytes = new byte[size]; int numBytes; while ((numBytes = Stream.Read(bytes, 0, size)) > 0) context.HttpContext.Response.OutputStream.Write(bytes, 0, numBytes); } }


Usando la versión de lanzamiento de MVC, esto es lo que hago:

[AcceptVerbs(HttpVerbs.Get)] [OutputCache(CacheProfile = "CustomerImages")] public FileResult Show(int customerId, string imageName) { var path = string.Concat(ConfigData.ImagesDirectory, customerId, "//", imageName); return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg"); }

Obviamente tengo algunas aplicaciones específicas aquí en relación con la construcción de la ruta, pero la devolución de FileStreamResult es agradable y simple.

Hice algunas pruebas de rendimiento con respecto a esta acción contra su llamada diaria a la imagen (sin pasar por el controlador) y la diferencia entre los promedios fue de solo 3 milisegundos (el promedio del controlador fue de 68 ms, el no controlador fue de 65 ms).

Intenté algunos de los otros métodos mencionados en las respuestas aquí y el impacto en el rendimiento fue mucho más dramático ... varias de las respuestas de las soluciones fueron 6 veces más que el no controlador (otros controladores avg 340ms, no controlador 65ms).


Utilice el método de archivo de controladores base.

public ActionResult Image(string id) { var dir = Server.MapPath("/Images"); var path = Path.Combine(dir, id + ".jpg"); //validate the path for security or use other means to generate the path. return base.File(path, "image/jpeg"); }

Como nota, esto parece ser bastante eficiente. Hice una prueba en la que solicité la imagen a través del controlador ( http://localhost/MyController/Image/MyImage ) y a través de la URL directa ( http://localhost/Images/MyImage.jpg ) y los resultados fueron:

  • MVC: 7.6 milisegundos por foto.
  • Directo: 6,7 milisegundos por foto.

Nota: este es el tiempo promedio de una solicitud. El promedio se calculó realizando miles de solicitudes en la máquina local, por lo que los totales no deberían incluir problemas de latencia de red o de ancho de banda.


Veo dos opciones:

1) Implemente su propio IViewEngine y establezca la propiedad ViewEngine del controlador que está utilizando para su ImageViewEngine en el método de "imagen" que desee.

2) Usa una vista :-). Solo cambia el tipo de contenido etc.


puede utilizar Archivo para devolver un archivo como Ver, Contenido, etc.

public ActionResult PrintDocInfo(string Attachment) { string test = Attachment; if (test != string.Empty || test != "" || test != null) { string filename = Attachment.Split(''//').Last(); string filepath = Attachment; byte[] filedata = System.IO.File.ReadAllBytes(Attachment); string contentType = MimeMapping.GetMimeMapping(Attachment); System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition { FileName = filename, Inline = true, }; Response.AppendHeader("Content-Disposition", cd.ToString()); return File(filedata, contentType); } else { return Content("<h3> Patient Clinical Document Not Uploaded</h3>"); } }


ACTUALIZACIÓN: hay mejores opciones que mi respuesta original. Esto funciona fuera de MVC bastante bien, pero es mejor atenerse a los métodos integrados para devolver contenido de imagen. Ver las respuestas más votadas.

Ciertamente puedes. Pruebe estos pasos:

  1. Cargue la imagen del disco en una matriz de bytes.
  2. almacene en caché la imagen en el caso de que espere más solicitudes de la imagen y no desee la E / S del disco (mi muestra no la almacena a continuación)
  3. Cambie el tipo mime a través de Response.ContentType
  4. Response.BinaryEscribe la matriz de bytes de la imagen

Aquí hay un código de ejemplo:

string pathToFile = @"C:/Documents and Settings/some_path.jpg"; byte[] imageData = File.ReadAllBytes(pathToFile); Response.ContentType = "image/jpg"; Response.BinaryWrite(imageData);

¡Espero que ayude!


Solución 1: para representar una imagen en una vista desde una URL de imagen

Puedes crear tu propio método de extensión:

public static MvcHtmlString Image(this HtmlHelper helper,string imageUrl) { string tag = "<img src=''{0}''/>"; tag = string.Format(tag,imageUrl); return MvcHtmlString.Create(tag); }

Entonces úsalo como:

@Html.Image(@Model.ImagePath);

Solución 2: Renderizar imagen desde base de datos.

Cree un método de controlador que devuelva datos de imagen como a continuación

public sealed class ImageController : Controller { public ActionResult View(string id) { var image = _images.LoadImage(id); //Pull image from the database. if (image == null) return HttpNotFound(); return File(image.Data, image.Mime); } }

Y úsalo en una vista como:

@ { Html.RenderAction("View","Image",new {[email protected]})}

Para usar una imagen renderizada de este resultado de acción en cualquier HTML, use

<img src="http://something.com/image/view?id={imageid}>


if (!System.IO.File.Exists(filePath)) return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception else return new FilePathResult(filePath, contentType);

SomeHelper.EmptyImageResult() debe devolver FileResult con una imagen existente (1x1 transparente, por ejemplo).

Esta es la forma más fácil si tiene archivos almacenados en el disco local. Si los archivos son byte[] o stream , use FileContentResult o FileStreamResult como Dylan sugirió.