Frage

Kann ich erstelle einen Controller, der gibt einfach ein Bild Asset?

Ich mag diese Logik über einen Controller zu routen, wann immer eine URL wie die folgenden angefordert:

www.mywebsite.com/resource/image/topbanner

Der Controller topbanner.png nachschlägt und das Bild senden direkt an den Client zurück.

Ich habe Beispiele gesehen, wo Sie einen Blick zu schaffen haben - ich will nicht eine Ansicht verwenden. Ich will sie alle nur mit dem Controller tun.

Ist das möglich?

War es hilfreich?

Lösung

, um die Basis-Controller Datei-Methode verwenden.

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

Als Hinweis, scheint dies ziemlich effizient. Ich habe einen Test, wo ich das Bild, das durch die Steuerung (http://localhost/MyController/Image/MyImage) angefordert und durch die direkte URL (http://localhost/Images/MyImage.jpg) und die Ergebnisse waren:

  • MVC: 7,6 Millisekunden pro Foto
  • Direct: 6,7 Millisekunden pro Foto

Hinweis: Dies ist die durchschnittliche Zeit eines Ersuchens. Der Mittelwert wurde berechnet, indem Tausende von Anfragen auf der lokalen Maschine zu machen, so dass die Summen nicht die Netzwerk-Latenz oder Bandbreite Probleme sind.

Andere Tipps

die Release-Version von MVC verwenden, hier ist das, 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 Sachen in der hier in Bezug auf den Wegebau, aber den Filestreamresult der Rückkehr ist schön und einfach.

Ich habe einige Performance-Tests in Bezug auf diese Aktion gegen den täglichen Anruf zu dem Bild (unter Umgehung der Steuerung) und die Differenz zwischen den Mittelwerten wurde nur etwa 3 Millisekunden (Controller avg war 68ms, nicht-Controller war 65ms).

Ich hatte hier in Antworten erwähnt einige der anderen Methoden ausprobiert und die Performance-Einbußen war viel dramatischer ... einige der Lösungen Antworten so viel wie 6x waren die Nicht-Controller (andere Steuerungen avg 340ms, nicht-Controller 65ms ).

Um auf Dyland Antwort expland leicht:

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, wo die Datei auf der Festplatte vorhanden ist, verwendet FilePathResult - das ist der einfachste Weg ist, und vermeidet man mit Streams verwenden,
  • .
  • Für byte [] Arrays (ähnlich Response.BinaryWrite), verwenden FileContentResult.
  • Für byte [] Arrays, wo Sie die Datei herunterladen möchten (Content-Disposition: attachment)., Verwendung FileStreamResult in ähnlicher Weise wie unten, aber mit einem MemoryStream und mit GetBuffer()
  • Für Streams Verwendung FileStreamResult. Es ist ein Filestreamresult genannt, aber es dauert eine Stream so würde ich erraten mit einem MemoryStream funktioniert.

Im Folgenden ist 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;
    }

Dies kann hilfreich sein, wenn Sie das Bild ändern möchten, bevor es zurückkehrt:

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

Sie können Ihre eigene Erweiterung und machen auf diese Weise erstellen.

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önnen direkt auf die Antwort schreiben, aber dann ist es nicht prüfbar. Es wird bevorzugt, eine Actionzurückzugeben, die Ausführung zurückgestellt. Hier ist mein resusable Stream:

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

Warum nicht einfach gehen und die Tilde ~ Operator verwenden?

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

UPDATE: Es gibt bessere Optionen als meine ursprüngliche Antwort. Dies funktioniert außerhalb von MVC ganz gut, aber es ist besser, mit den integrierten Methoden Stick Bildinhalt zurück. Siehe oben gestimmt Antworten.

Sie sicherlich können. Probieren Sie die folgenden Schritte:

  1. Laden das Bild von der Festplatte in einen Byte-Array
  2. das Bild im Fall cachen Sie mehr Anfragen für das Bild erwarten und wollen nicht auf die Disk-I / O (meine Probe nicht unter nicht-Cache)
  3. Ändern Sie den MIME-Typ über den Response.ContentType
  4. Response.BinaryWrite aus dem Bild Byte-Array

Hier ist ein Beispielcode:

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

Ich hoffe, das hilft!

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

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 verwenden Sie es mögen:

@Html.Image(@Model.ImagePath);

Lösung 2: Um das Bild aus der Datenbank zu machen

Erstellen Sie eine Controller-Methode, die Bilddaten wie unten zurück

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 es in einer Ansicht verwenden wie:

@ { Html.RenderAction("View","Image",new {id=@Model.ImageId})}

ein Bild aus dieser Action in jedem beliebigen HTML gerendert zu verwenden, verwendet

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

Das funktionierte für mich. Da ich Bilder auf einer SQL Server-Datenbank zu 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;
    }

In dem Schnipsel oben _db.ImageFiles.Find(uuid) wird für die Bilddatei Datensatz in der db (EF Kontext) zu suchen. Es gibt ein FileImage Objekt, das nur eine benutzerdefinierte Klasse, die ich für das Modell gemacht und dann nutzt es als Filecontentresult.

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

Sehen Sie in Content. Dies liefert einen String, kann aber verwendet werden, um Ihre eigene BinaryResult artige Klasse zu machen.

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

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

            }

Ich sehe zwei Möglichkeiten:

1) Implementieren Sie Ihre eigene IViewEngine und stellen Sie die Eigenschaft Viewengine des Controllers Sie Ihre ImageViewEngine verwenden in Ihrem gewünschten „Bild“ -Methode.

2) Verwenden Sie einen Blick :-). Ändern Sie einfach den Inhaltstyp etc.

Sie können die HttpContext.Response verwenden und direkt auf den Inhalt, um es (Writefile () könnte für Sie arbeiten) schreiben und dann wieder aus dem Content Aktion statt Action.

Disclaimer: Ich habe nicht versucht, es basiert auf dem verfügbaren APIs auf der Suche. : -)

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

SomeHelper.EmptyImageResult() sollte FileResult Rückkehr mit vorhandenem Bild (1x1 transparent, zum Beispiel).

Dies ist am einfachsten Weg, wenn Sie Dateien auf dem lokalen Laufwerk gespeichert haben. Wenn Dateien byte[] oder stream sind -. Dann verwenden FileContentResult oder FileStreamResult als Dylan vorgeschlagen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top