単に画像アセットを返すControllerを作成できますか?
次のようなURLが要求されたときはいつでも、私はコントローラを通してこのロジックをルーティングしたいです。
www.mywebsite.com/resource/image/topbanner
コントローラはtopbanner.png
を検索し、そのイメージを直接クライアントに送り返します。
私はあなたがビューを作成しなければならないところでこの例を見ました - 私はビューを使いたくありません。私はコントローラーだけでそれをすべてやりたい。
これは可能ですか?
基本コントローラーの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のリリースバージョンを使用して、これが私がしていることです:
[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)でした。
Dylandの反応について少し説明すると:
3つのクラスが FileResult クラスを実装しています。
System.Web.Mvc.FileResult
System.Web.Mvc.FileContentResult
System.Web.Mvc.FilePathResult
System.Web.Mvc.FileStreamResult
それらはすべてかなり自明です。
FilePathResult
name__を使用します - これが最も簡単な方法で、Streamsを使用する必要がなくなります。FileContentResult
name__を使用します。FileStreamResult
name__を使用し、GetBuffer()
を使用して、MemoryStream
name__を以下のように使用します。Streams
name__にはFileStreamResult
name__を使用してください。これはFileStreamResultと呼ばれますが、Stream
name__を取るので、推測するとMemoryStream
name__で動作します。以下は、コンテンツ配置手法(未テスト)の使用例です。
[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");
}
あなたはあなた自身のエクステンションを作成してこの方法をとることができます。
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")%>
あなたは直接応答に書くことができますが、それからそれはテストできません。実行が延期された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("~/Content/images/topbanner.png", "image/png");
}
更新:私の最初の答えより良い選択肢があります。これはMVCの外では非常にうまく機能しますが、画像コンテンツを返す組み込みメソッドを使い続ける方が良いでしょう。投票した回答を見る
あなたは確かにできます。以下の手順を試してください。
ここにいくつかのサンプルコードがあります:
string pathToFile = @"C:\Documents and Settings\some_path.jpg";
byte[] imageData = File.ReadAllBytes(pathToFile);
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageData);
それが役立つことを願っています!
これは私のために働きました。私は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; }
}
解決策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 {[email protected]})}
このアクション結果からレンダリングされた画像を任意のHTMLで使用するには、次のようにします。
<img src="http://something.com/image/view?id={imageid}>
ContentResultを見てください。これは文字列を返しますが、あなた自身のBinaryResultのようなクラスを作るために使うことができます。
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>"); }
}
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
の場合 - Dylanが推奨しているようにFileContentResult
またはFileStreamResult
を使用します。
2つの選択肢があります。
1)独自のIViewEngineを実装し、使用しているControllerのViewEngineプロパティを目的の "image"メソッドでImageViewEngineに設定します。
2)ビューを使用してください:-)コンテンツの種類などを変更するだけです。
HttpContext.Responseを使用して直接コンテンツを書き込み(WriteFile()でうまくいくかもしれません)、ActionResultではなくContentResultをアクションから返すことができます。
免責事項:私はこれを試していない、それは利用可能なAPIを調べることに基づいています。 :-)
同様の要件もありましたが、
そのため、私の場合、イメージフォルダーパスを使用してControllerにリクエストを行い、その結果、ImageResultオブジェクトが返されます。
次のコードスニペットは、作業を示しています。
var src = string.Format("/GenericGrid.mvc/DocumentPreviewImageLink?fullpath={0}&routingId={1}&siteCode={2}", fullFilePath, metaInfo.RoutingId, da.SiteCode);
if (enlarged)
result = "<a class='thumbnail' href='#thumb'>" +
"<img src='" + src + "' height='66px' border='0' />" +
"<span><img src='" + src + "' /></span>" +
"</a>";
else
result = "<span><img src='" + src + "' height='150px' border='0' /></span>";
そして、画像パスからコントローラーで画像を生成し、呼び出し元に返します
try
{
var file = new FileInfo(fullpath);
if (!file.Exists)
return string.Empty;
var image = new WebImage(fullpath);
return new ImageResult(new MemoryStream(image.GetBytes()), "image/jpg");
}
catch(Exception ex)
{
return "File Error : "+ex.ToString();
}