asp.net - with - produces asp net core




Kann ein ASP.NET MVC-Controller ein Image zurückgeben? (11)

Kann ich einen Controller erstellen, der einfach ein Image-Asset zurückgibt?

Ich möchte diese Logik durch einen Controller weiterleiten, wenn eine URL wie die folgende angefordert wird:

www.mywebsite.com/resource/image/topbanner

Der Controller sucht topbanner.png und sendet dieses Bild direkt an den Client zurück.

Ich habe Beispiele dafür gesehen, wo Sie eine Ansicht erstellen müssen - ich möchte keine Ansicht verwenden. Ich möchte alles nur mit dem Controller machen.

Ist das möglich?


Das hat für mich funktioniert. Da ich Bilder in einer SQL Server-Datenbank speichern.

    [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;
    }

Im obigen _db.ImageFiles.Find(uuid) sucht _db.ImageFiles.Find(uuid) nach dem Image-Datei-Record in der db (EF-Kontext). Sie gibt ein FileImage-Objekt zurück, das nur eine benutzerdefinierte Klasse ist, die ich für das Modell erstellt habe, und verwendet es dann als FileContentResult.

public class FileImage {
   public string Uuid { get; set; }
   public byte[] Data { get; set; }
   public string ContentType { get; set; }
}

Dies kann hilfreich sein, wenn Sie das Bild vor der Rückgabe modifizieren möchten:

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


Mit der Release-Version von MVC, hier ist, was ich tue:

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

Ich habe offensichtlich einige anwendungsspezifische Dinge hier bezüglich der Pfadkonstruktion, aber die Rückgabe des FileStreamResult ist nett und einfach.

Ich habe einige Performance-Tests in Bezug auf diese Aktion gegen Ihren täglichen Aufruf an das Bild (unter Umgehung des Controllers) durchgeführt und der Unterschied zwischen den Durchschnitten betrug nur ca. 3 Millisekunden (Controller-Durchschnitt 68ms, Nicht-Controller 65ms).

Ich hatte einige der anderen in den Antworten erwähnten Methoden ausprobiert und der Performance-Hit war viel dramatischer ... einige der Lösungsantworten waren sechsmal so groß wie der Nicht-Controller (andere Controller durchschnittlich 340ms, Nicht-Controller 65ms).


Sie können Datei verwenden, um eine Datei wie Ansicht, Inhalt usw. zurückzugeben

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

            }

Sie können Ihre eigene Erweiterung erstellen und so machen.

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")%>

Sie könnten die HttpContext.Response verwenden und den Inhalt direkt darauf schreiben (WriteFile () könnte für Sie arbeiten) und dann ContentResult von Ihrer Aktion anstelle von ActionResult zurückgeben.

Disclaimer: Ich habe das nicht versucht, es basiert auf dem Blick auf die verfügbaren APIs. :-)


Um auf Dylands Antwort etwas zu erklären:

Drei Klassen implementieren die FileResult Klasse:

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

Sie sind alle ziemlich selbsterklärend:

  • Für Dateipfad-Downloads, bei denen die Datei auf der Festplatte vorhanden ist, verwenden Sie FilePathResult - dies ist der einfachste Weg und vermeidet die Verwendung von Streams.
  • Verwenden Sie FileContentResult Arrays vom FileContentResult Byte [] (ähnlich wie Response.BinaryWrite).
  • Für Byte [] -Arrays, bei denen die Datei heruntergeladen werden soll (content-disposition: Anhang), verwenden Sie FileStreamResult auf ähnliche Weise wie unten, jedoch mit einem MemoryStream und mit GetBuffer() .
  • Verwenden FileStreamResult für Streams FileStreamResult . Es heißt FileStreamResult, aber es braucht einen Stream also würde ich vermuten, dass es mit einem MemoryStream funktioniert.

Im Folgenden finden Sie ein Beispiel für die Verwendung der Content-Disposition-Technik (nicht getestet):

    [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;
    }

Warum nicht einfach gehen und den Tilde ~ Operator benutzen?

public FileResult TopBanner() {
  return File("~/Content/images/topbanner.png", "image/png");
}

Lösung 1: Um ein Bild in einer Ansicht von einer Bild-URL zu rendern

Sie können Ihre eigene Erweiterungsmethode erstellen:

public static MvcHtmlString Image(this HtmlHelper helper,string imageUrl)
{
   string tag = "<img src='{0}'/>";
   tag = string.Format(tag,imageUrl);
   return MvcHtmlString.Create(tag);
}

Dann benutze es wie:

@Html.Image(@Model.ImagePath);

Lösung 2: Bild von der Datenbank rendern

Erstellen Sie eine Controller-Methode, die Bilddaten wie folgt zurückgibt

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

Und benutze es in einer Ansicht wie:

@ { Html.RenderAction("View","Image",new {[email protected]})}

Um ein Bild zu verwenden, das von diesem actionresult in irgendeinem HTML gerendert wird, verwenden Sie

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

if (!System.IO.File.Exists(filePath))
    return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
    return new FilePathResult(filePath, contentType);

SomeHelper.EmptyImageResult() sollte FileResult mit vorhandenem Bild zurückgeben ( FileResult 1x1 transparent).

Dies ist am einfachsten, wenn Dateien auf dem lokalen Laufwerk gespeichert sind. Wenn Dateien byte[] oder stream verwenden Sie FileContentResult oder FileStreamResult wie es Dylan vorgeschlagen hat.





controller