[asp.net] ASP.NET MVC 컨트롤러가 이미지를 반환 할 수 있습니까?

단순히 이미지 자산을 반환하는 컨트롤러를 만들 수 있습니까?

다음과 같은 URL이 요청 될 때마다 컨트롤러를 통해이 논리를 라우팅하고 싶습니다.

www.mywebsite.com/resource/image/topbanner

컨트롤러는 topbanner.png해당 이미지를 찾아 클라이언트로 직접 보냅니다.

View를 작성 해야하는 곳의 예를 보았습니다 .View를 사용하고 싶지 않습니다. 컨트롤러만으로 모든 것을하고 싶습니다.

이것이 가능한가?



답변

기본 컨트롤러 파일 방법을 사용하십시오.

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 밀리 초

참고 : 이것은 평균 요청 시간입니다. 평균은 로컬 컴퓨터에서 수천 건의 요청을 수행하여 계산되었으므로 총계에는 네트워크 대기 시간이나 대역폭 문제가 포함되지 않아야합니다.


답변

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의 응답을 약간 넓히려면 :

세 가지 클래스가 FileResult 클래스를 구현합니다 .

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

그들은 모두 상당히 설명이 필요합니다.

  • 파일이 디스크에있는 파일 경로 다운로드의 경우 다음을 사용하십시오 FilePathResult. 이것이 가장 쉬운 방법이며 스트림을 사용하지 않아도됩니다.
  • byte [] 배열 (Response.BinaryWrite에 영향을 미침)에는을 사용하십시오 FileContentResult.
  • 파일을 다운로드하려는 byte [] 배열 (content-disposition : attachment)의 경우 FileStreamResult아래와 비슷한 방식으로 a MemoryStream및 using을 사용하십시오 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;
    }


답변

이미지를 반환하기 전에 수정하려는 경우에 도움이 될 수 있습니다.

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