development

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

big-blog 2020. 2. 17. 22:19
반응형

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)만큼 6 배나 많았습니다.


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

업데이트 : 원래 답변보다 더 나은 옵션이 있습니다. 이것은 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);

희망이 도움이됩니다!


해결 방법 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로 사용하려면

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

이것은 나를 위해 일했습니다. 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; }
}

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

            }

ContentResult를보십시오. 문자열을 반환하지만 고유 한 BinaryResult와 같은 클래스를 만드는 데 사용할 수 있습니다.


두 가지 옵션이 있습니다.

1) 자신의 IViewEngine을 구현하고 사용중인 컨트롤러의 ViewEngine 속성을 원하는 "image"방법으로 ImageViewEngine에 설정하십시오.

2)보기를 사용하십시오 :-). 컨텐츠 유형 등을 변경하십시오.


HttpContext.Response를 사용하여 직접 컨텐츠를 작성하고 (WriteFile ()이 효과가있을 수 있음) ActionResult 대신 조치에서 ContentResult를 리턴 할 수 있습니다.

면책 조항 : 나는 이것을 시도하지 않았으며 사용 가능한 API를 살펴 보았습니다. :-)


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-인 경우 FileContentResult또는 FileStreamResultDylan이 제안한대로 또는를 사용하십시오 .


또한 비슷한 요구 사항이 발생했습니다.

따라서 필자의 경우 이미지 폴더 경로를 사용하여 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();
}

참고 URL : https://stackoverflow.com/questions/186062/can-an-asp-net-mvc-controller-return-an-image



도와주세요.
반응형