我可以创建一个简单地返回图像资产的控制器吗?
我想通过控制器路由这个逻辑,每当请求如下URL时:
www.mywebsite.com/resource/image/topbanner
控制器将查找topbanner.png并将图像直接发送回客户端。
我见过这样的例子,你必须创建一个视图-我不想使用视图。我想只用控制器来做。
这可能吗?
我可以创建一个简单地返回图像资产的控制器吗?
我想通过控制器路由这个逻辑,每当请求如下URL时:
www.mywebsite.com/resource/image/topbanner
控制器将查找topbanner.png并将图像直接发送回客户端。
我见过这样的例子,你必须创建一个视图-我不想使用视图。我想只用控制器来做。
这可能吗?
当前回答
稍微解释一下迪兰的回应:
有三个类实现了FileResult类:
System.Web.Mvc.FileResult
System.Web.Mvc.FileContentResult
System.Web.Mvc.FilePathResult
System.Web.Mvc.FileStreamResult
它们都是不言自明的:
For file path downloads where the file exists on disk, use FilePathResult - this is the easiest way and avoids you having to use Streams. For byte[] arrays (akin to Response.BinaryWrite), use FileContentResult. For byte[] arrays where you want the file to download (content-disposition: attachment), use FileStreamResult in a similar way to below, but with a MemoryStream and using GetBuffer(). For Streams use FileStreamResult. It's called a FileStreamResult but it takes a Stream so I'd guess it works with a 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;
}
其他回答
解决方案1:从图像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);
解决方案2:从数据库中渲染图像
创建一个返回图像数据的控制器方法,如下所示
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}>
您可以直接写入响应,但这样它就不可测试了。最好返回一个延迟执行的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);
}
}
使用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毫秒(控制器的平均值为68ms,非控制器的平均值为65ms)。
我尝试了答案中提到的其他一些方法,性能的影响要大得多……一些解决方案的响应高达非控制器的6倍(其他控制器平均340ms,非控制器65ms)。
if (!System.IO.File.Exists(filePath))
return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
return new FilePathResult(filePath, contentType);
SomeHelper.EmptyImageResult()应该返回具有现有图像的FileResult(例如1x1透明)。
这是最简单的方法,如果你有文件存储在本地驱动器。 如果文件是字节[]或流-然后使用FileContentResult或FileStreamResult Dylan建议。
为什么不简单一点,使用波浪号~操作符呢?
public FileResult TopBanner() {
return File("~/Content/images/topbanner.png", "image/png");
}