asp.net - ASP.Net MVC控制器能返回一个图片?

  显示原文与译文双语对照的内容

我可以创建一个只返回图像资产的控制器?

我想通过一个控制器来传送这个逻辑,只要需要以下 url:


www.mywebsite.com/resource/image/topbanner

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

我已经看到了一些示例,你必须创建一个视图- 我不想使用视图。 我想只用控制器来做。

这可能吗?

时间:

使用基本控制器的文件方法。


public ActionResult Image(string id)
{
 var dir = Server.MapPath("/Images");
 var path = Path.Combine(dir, id +".jpg");
 return base.File(path,"image/jpeg");
}

注意,这似乎是相当有效的。 我做了一个测试,我通过控制器请求图像( http://localhost/MyController/Image/MyImage ) 并通过直接 url ( http://localhost/Images/MyImage.jpg ) 和结果是:

  • 的MVC: 每照片 7.6毫秒
  • 磅:每张照片的 6.7毫秒

注意:这是请求的平均时间。 平均数是通过在本地机器上进行数千个请求来计算的,这样总数不应该包括网络延迟或者带宽问题。

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

我显然有一些特定于应用程序的东西在这里关于道路建设,但返回FileStreamResult是很简单的。

我做了一些性能测试关于这对日常调用图像( 跳过控制器) 平均值之间的差异是只有( 控制器平均为 68毫秒,non-controller为 65毫秒) 3毫秒。

我试过一些答案中提到的其他方法和性能影响更显著。 有几个解决方案响应是 6 non-controller ( 其他控制器的avg 340 ms,non-controller 65 ms ) 。

expland dyland略的React:

三个类实现 FileResult 类:


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

它们都是完全自我解释的:

  • 对于磁盘上存在文件的文件路径下载,使用 FilePathResult - 这是最简单的方法,并且避免了使用流。
  • 对于字节 [] 数组( 类似于响应。binarywrite ),使用 FileContentResult
  • 对于要下载文件的字节 [] 数组( content-disposition: 附件),使用 FileStreamResult 以类似的方式使用,但使用 MemoryStreamGetBuffer()
  • FileStreamResultStreams 使用。被称为FileStreamResult但需要 Stream 所以我会猜 MemoryStream 它的工作原理。

下面是使用content-disposition技术( 未测试)的示例:


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

你可以直接写入响应,但它不可测试。 首选返回延迟执行的ActionResult 。 以下是我的Resusable 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);
 }
}

我在这里问了一个类似的问题 http://stackoverflow.com/questions/155906/creating-a-private-photo-gallery-using-aspnet-mvc,最后找到了一个很棒的指南来做这个。

我在本指南之后创建了一个ImageResult类。 http://blog.maartenballiauw.be/post/2008/05/ASPNET-MVC-custom-ActionResult.aspx

为什么不简单地使用 tilde ~ 操作符?


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

我有一个更好的答案 !


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(); 
 if (ImageFormat.Equals(ImageFormat.Jpeg)) context.HttpContext.Response.ContentType ="image/jpeg";
 Image.Save(context.HttpContext.Response.OutputStream, ImageFormat);
 }
}
public ActionResult Index()
 {
 return new ImageResult { Image = image, ImageFormat = ImageFormat.Jpeg };
 }
 <%=Html.Image<MukachevoNET.Controllers.CapchaController>(c => c.Index(), 120, 30,"Current time")%>

的更新:有比我原来的答案更好的选项。 这在MVC之外工作得很好,但最好是使用内置的返回图像内容的方法。 查看up-voted答案。

你当然可以。请尝试以下步骤:

  1. 将图像从磁盘加载到字节数组
  2. 缓存图像,以防你期望对图像有更多的请求,并且不希望磁盘i/o ( 我的示例不在下面缓存)
  3. 通过 Response.ContentType 更改mime类型
  4. Response.BinaryWrite 输出图像字节数组

下面是一些示例代码:


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

希望有帮助!

查看 ContentResult 。这将返回一个字符串,但可以用来创建你自己的BinaryResult-like类。

...