首页 文章

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

提问于
浏览
420

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

我想通过控制器路由此逻辑,只要请求以下URL:

www.mywebsite.com/resource/image/topbanner

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

我已经看到了这个例子,你必须创建一个View - 我不想使用View . 我想用Controller完成所有操作 .

这可能吗?

15 回答

  • 4

    为什么不简单并使用波浪号 ~ 运算符?

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

    我看到两个选择:

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

    2)使用视图:-) . 只需更改内容类型等 .

  • 68

    看看ContentResult . 这将返回一个字符串,但可用于创建自己的BinaryResult类 .

  • 119

    您可以直接写入响应,但它不可测试 . 最好返回具有延迟执行的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);
        }
    }
    
  • 2

    您可以创建自己的扩展并以此方式执行 .

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

    您可以使用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>"); }
    
                }
    
  • 0

    UPDATE: There are better options than my original answer. This works outside of MVC quite well but it's better to stick with the built-in methods of returning image content. See up-voted answers.

    你当然可以 . 尝试以下步骤:

    • 将映像从磁盘加载到字节数组中
      如果您期望对图像发出更多请求,请

    • 缓存图像,并在下面缓存它 .

    • 通过Response.ContentType更改mime类型

    • Response.BinaryWrite out图像字节数组

    这是一些示例代码:

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

    希望有所帮助!

  • 495

    Solution 1: To render an image in a view from an image URL

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

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

    Solution 2: To render image from database

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

    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中使用从此actionresult渲染的图像,请使用

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

    稍微解释一下Dyland的反应:

    三个类实现FileResult类:

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

    他们都是相当自我解释的:

    • 对于文件存在于磁盘上的文件路径下载,请使用 FilePathResult - 这是最简单的方法,避免使用Streams .

    • 对于byte []数组(类似于Response.BinaryWrite),请使用 FileContentResult .

    • 对于您希望文件下载的byte []数组(内容处理:附件),请使用 FileStreamResult ,方法与下面类似,但使用 MemoryStream 并使用 GetBuffer() .

    • 对于 Streams 使用 FileStreamResult . 它被称为FileStreamResult,但需要 Stream 所以我猜它适用于 MemoryStream .

    下面是使用内容处理技术(未测试)的示例:

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

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

    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");
    }
    
  • 1
    if (!System.IO.File.Exists(filePath))
        return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
    else
        return new FilePathResult(filePath, contentType);
    

    SomeHelper.EmptyImageResult() 应该使用现有图像返回 FileResult (例如,1x1透明) .

    如果您将文件存储在本地驱动器上,这是最简单的方法 . 如果文件是 byte[]stream - 则使用 FileContentResultFileStreamResult 作为Dylan建议 .

  • 1

    使用基本控制器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");
    }
    

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

    • MVC: 每张照片7.6毫秒

    • Direct: 每张照片6.7毫秒

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

  • 3

    这对我有用 . 因为我将图像存储在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;
        }
    

    在上面的代码片段中, _db.ImageFiles.Find(uuid) 正在db(EF上下文)中搜索图像文件记录 . 它返回一个FileImage对象,它只是我为模型制作的自定义类,然后将其用作FileContentResult .

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

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

    免责声明:我没有尝试过这个,它基于查看可用的API . :-)

  • 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的返回很简单 .

    我针对您每天对图像的调用(绕过控制器)执行了一些性能测试,平均值之间的差异仅为3毫秒(控制器平均值为68毫秒,非控制器为65毫秒) .

    我已经尝试过这里的答案中提到的其他一些方法,性能影响要大得多......几个解决方案的响应是非控制器的6倍(其他控制器平均340毫秒,非控制器65毫秒) .

相关问题