472

単純に画像アセットを返すコントローラーを作成できますか?

次のような URL が要求されるたびに、コントローラーを介してこのロジックをルーティングしたいと思います。

www.mywebsite.com/resource/image/topbanner

コントローラーはtopbanner.pngその画像を検索して、クライアントに直接送り返します。

ビューを作成しなければならない例を見てきました - 私はビューを使いたくありません。コントローラーだけで全部やりたい。

これは可能ですか?

4

20 に答える 20

548

ベース コントローラのファイル メソッドを使用します。

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 ミリ秒
  • 直接:写真あたり 6.7 ミリ秒

注: これはリクエストの平均時間です。平均は、ローカル マシンで数千の要求を行うことによって計算されたため、合計にはネットワーク レイテンシや帯域幅の問題は含まれません。

于 2009-08-28T20:58:45.000 に答える
133

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ミリ秒)。

于 2009-04-15T16:23:19.960 に答える
103

ダイランドの反応を少し説明するには:

3つのクラスがFileResultクラスを実装します。

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

それらはすべてかなり自明です:

  • ファイルがディスク上に存在するファイルパスのダウンロードには、FilePathResult次を使用します。これが最も簡単な方法であり、Streamsを使用する必要がありません。
  • byte []配列(Response.BinaryWriteに類似)には、を使用しますFileContentResult
  • ファイルをダウンロードするbyte[]配列(content-disposition:attachment)の場合FileStreamResultは、以下と同様の方法で使用しますが、aMemoryStreamとを使用し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;
    }
于 2009-09-29T21:59:17.987 に答える
75

これは、画像を返す前に画像を変更したい場合に役立つことがあります。

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");
}
于 2011-03-28T11:06:27.377 に答える
12

独自の拡張機能を作成して、このようにすることができます。

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")%>
于 2011-06-09T06:16:04.700 に答える
11

シンプルにチルダ~演算子を使用してみませんか?

public FileResult TopBanner() {
  return File("~/Content/images/topbanner.png", "image/png");
}
于 2011-10-31T23:47:03.073 に答える
10

応答に直接書き込むことはできますが、テストできません。実行を延期した 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);
    }
}
于 2008-10-09T20:22:52.803 に答える
6

更新: 元の回答よりも優れたオプションがあります。これは MVC の外部では非常にうまく機能しますが、画像コンテンツを返す組み込みのメソッドに固執することをお勧めします。賛成票の回答を参照してください。

確かにできます。次の手順を試してください。

  1. ディスクからバイト配列にイメージをロードします
  2. イメージに対するより多くのリクエストが予想され、ディスク I/O が必要ない場合に備えて、イメージをキャッシュします (私のサンプルでは以下にキャッシュしません)。
  3. Response.ContentType を介して MIME タイプを変更します
  4. Response.Binary画像のバイト配列を書き出す

サンプルコードは次のとおりです。

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

それが役立つことを願っています!

于 2008-10-09T06:28:47.603 に答える
5

解決策 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})}

この actionresult からレンダリングされた画像を任意の HTML で使用するには、次を使用します。

<img src="http://something.com/image/view?id={imageid}>
于 2014-07-06T06:26:29.367 に答える
4

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

            }
于 2016-03-16T14:23:33.780 に答える
3

ContentResult を見てください。これは文字列を返しますが、独自の BinaryResult のようなクラスを作成するために使用できます。

于 2008-10-09T06:27:57.900 に答える
2
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[]orの場合は、ディランが提案したようにorをstream使用します。FileContentResultFileStreamResult

于 2010-02-18T12:58:51.327 に答える
1

2 つのオプションが表示されます。

1) 独自の IViewEngine を実装し、使用しているコントローラーの ViewEngine プロパティを、目的の「イメージ」メソッドで ImageViewEngine に設定します。

2)ビューを使用してください:-)。コンテンツタイプなどを変更するだけです。

于 2008-10-09T06:26:59.197 に答える
1

HttpContext.Response を使用してコンテンツを直接書き込み (WriteFile() が機能する場合があります)、ActionResult の代わりにアクションから ContentResult を返すことができます。

免責事項: 私はこれを試していません。利用可能な API を調べた結果に基づいています。:-)

于 2008-10-09T06:28:39.880 に答える