ASP.NET MVC控制器可以返回一个图像吗?

我可以创build一个简单地返回图像资源的控制器吗?

我想通过一个控制器路由这个逻辑,每当一个URL如下所示:

www.mywebsite.com/resource/image/topbanner 

控制器将查找topbanner.png并将该图像直接发送回客户端。

我见过这个例子,你必须创build一个视图 – 我不想使用视图。 我只想用Controller来完成这一切。

这可能吗?

使用基本控制器File方法。

 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"); } 

作为一个说明,这似乎是相当有效的。 我做了一个testing,通过控制器( http://localhost/MyController/Image/MyImage )和直接URL( http://localhost/Images/MyImage.jpg )请求图像,结果如下:

  • MVC:每张照片7.6毫秒
  • 直接:每张照片6.7毫秒

注意:这是请求的平均时间。 平均值是通过在本地计算机上发出数千个请求来计算的,因此总计不应包含networking延迟或带宽问题。

使用MVC的发布版本,这是我做的:

 [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"); } 

我在这里显然有一些关于path构造的应用程序特定的东西,但是FileStreamResult的返回很好,很简单。

我做了一些关于这个动作的性能testing,针对你每天调用的图像(绕过控制器),平均值之间的差异只有大约3毫秒(控制器avg是68ms,非控制器是65ms)。

我已经尝试了一些在这里回答中提到的其他方法,性能的影响更戏剧性…几个解决scheme的反应是非控制器(其他控制器avg 340ms,非控制器65ms)的6倍。

稍作解释Dyland的回应:

三个类实现FileResult类:

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

他们都相当自我解释:

  • 对于文件存在于磁盘上的文件path下载,使用FilePathResult – 这是最简单的方法,避免了使用Streams。
  • 对于byte []数组(类似于Response.BinaryWrite),使用FileContentResult
  • 对于要下载文件的字节[]数组(content-disposition:attachment),请使用类似于下面的方法使用FileStreamResult ,但使用MemoryStream并使用GetBuffer()
  • 对于Streams使用FileStreamResult 。 这就是所谓的FileStreamResult,但它需要一个Stream所以我猜想它与一个MemoryStream作品。

以下是使用内容处置技术(未testing)的示例:

  [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; } 

如果您想在返回之前修改图像,这可能会有所帮助:

 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"); } 

你可以创build你自己的扩展,这样做。

 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")%> 

我在这里问了一个类似的问题创build一个私人照片库使用Asp.Net MVC,并最终find一个伟大的指导做到这一点。

我按照这个指南创build了一个ImageResult类。 https://blog.maartenballiauw.be/post/2008/05/13/aspnet-mvc-custom-actionresult.html

您可以直接写入响应,但不能testing。 最好返回一个延迟执行的ActionResult。 这里是我可重用的StreamResult:

 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); } } 

为什么不简单使用波浪号~操作符?

 public FileResult TopBanner() { return File("~/Contenthttp://img.dovov.comtopbanner.png", "image/png"); } 

更新:有比我原来的答案更好的select。 这在MVC之外很好运行,但最好还是坚持使用内置的返回图像内容的方法。 看到最新的答案。

你当然可以。 试试这些步骤:

  1. 从磁盘加载图像到一个字节数组
  2. caching的图像,你希望更多的图像请求的情况下,不希望磁盘I / O(我的示例不caching下面)
  3. 通过Response.ContentType更改MIMEtypes
  4. Response.Binary写出图像字节数组

以下是一些示例代码:

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

希望有所帮助!

看看ContentResult。 这将返回一个string,但可以用来制作自己的BinaryResult类。

解决scheme1:从图片url呈现视图中的图片

您可以创build自己的扩展方法:

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

然后像这样使用它:

 @Html.Image(@Model.ImagePath); 

解决scheme2:从数据库呈现图像

创build一个返回如下图像数据的控制器方法

 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); } } 

并在一个视图中使用它:

 @ { Html.RenderAction("View","Image",new {id=@Model.ImageId})} 

要在任何HTML中使用此操作结果呈现的图像,请使用

 <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()应该返回FileResult与现有的图像(例如1×1透明)。

如果您的文件存储在本地驱动器上,这是最简单的方法。 如果文件是byte[]stream – 然后使用FileContentResultFileStreamResult Dylanbuild议。

我看到两个选项:

1)实现您自己的IViewEngine,并将您正在使用的Controller的ViewEngine属性设置为您所需的“图像”方法中的ImageViewEngine。

2)使用视图:-)。 只需更改内容types等

您可以使用HttpContext.Response并直接写入内容(WriteFile()可能适用于您),然后从您的操作返回ContentResult而不是ActionResult。

免责声明:我没有尝试过,它是基于查看可用的API。 🙂

你可以使用File返回一个像View,Content等文件

  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>"); } }