2010-02-01 4 views
5

Ich habe eine ASP.NET MVC-Anwendung, wo ich Bilder anzeigen.ASP.NET MVC Dynamisch generierte Bild URLs

Diese Bilder können sich im Dateisystem oder in einer Datenbank befinden. Dies ist in Ordnung, da ich Url.Action in meinem Bild verwenden kann, die Aktion auf meinem Controller aufrufen und das Bild von dem relevanten Ort zurückgeben.

Ich möchte jedoch in Amazon S3 gespeicherte Bilder unterstützen können. In diesem Fall möchte ich nicht, dass meine Controlleraktion das Bild zurückgibt, stattdessen sollte eine Bild-URL für Amazon S3 generiert werden.

Obwohl ich diese Logik nur in meiner Ansicht z.

<% if (Model.Images [0] == .ImageLocation ImageLocation.AmazonS3) {%> // machen amazon Bild

ich brauche, um sicherzustellen, dass das Bild zuerst existiert.

Im Wesentlichen muss ich einen Größenwert an meinen Controller übergeben, damit ich überprüfen kann, ob das Bild in dieser Größe existiert (ob in der Datenbank, im Dateisystem oder in Amazon S3). Sobald ich sicher bin, dass das Bild existiert, gebe ich die URL zurück.

Hoffnung, die Sinn macht,

Ben

Antwort

2

Versuchen Sie den folgenden Ansatz.

Eine Modellklasse für ein Image-Tag.

public class ImageModel 
{ 
    public String Source { get; set; } 
    public String Title { get; set; } 
} 

Helper

public static String Image(this HtmlHelper helper, String source, String title) 
{ 
    var builder = new TagBuilder("img"); 
    builder.MergeAttribute("src", source); 
    builder.MergeAttribute("title", title); 
    return builder.ToString(); 
} 

Ansicht mit Model.Images vom Typ IEnumerable<ImageModel>

...  
<%= Html.Image(Model.Images[0].Source, Model.Images[0].Title) %> 

Aktion

public ActionResult ActionName(/*whatever*/) 
{ 
    // ... 
    var model = ...; 
    //... 

    var model0 = ImageModel(); 
    if (Image0.ImageLocation == ImageLocation.AmazonS3) 
     model0.Source = "an amazon url"; 
    else 
     model0.Source = Url.Action("GetImageFromDatabaseOrFileSystem", "MyController", new { Id = Image0.Id }); 
    model0.Title = "some title"; 
    model.Images.Add(model0); 
    // ... 
    return View(model); 
} 

Eine Aktion ist eine Art von Pseudo-Code aber die Idee sollte klar sein.

+0

Dank Anton, das ist eine gute Vorgehensweise. Ich denke, ich werde ein neues ViewModel dafür erstellen, da mein aktuelles Modell ein IList mit IList ist. Scheint besser, dies in ein neues Ansichtsmodell zu zerlegen, wo ich Dinge wie die benötigte Bildgröße definieren kann und nur ein einziges Bild pro Produkt habe (was ich aus meiner Sicht brauche). Ich poste meinen Code einmal fertig. –

-1

können Sie ein HttpWebRequest erstellen um das Bild zu laden. Überprüfen Sie die Kopfzeile in der Antwort, wenn es 200 ist, bedeutet das, dass es erfolgreich war, andernfalls ging etwas schief.

+0

Hallo, die wichtigste Voraussetzung ist, dass ich in der Lage bin die URL dynamisch auf der Basis zu konstruieren, in dem das Bild „sollte“ befinden. Ich muss keine HttpWebRequest verwenden, um zu überprüfen, ob das Image vorhanden ist. Ich kann hierfür System.IO.File.Exists verwenden oder den Amazon S3-Bucket überprüfen. Danke Ben –

1

Nach mehreren Iterationen habe ich eine praktikable Lösung gefunden, obwohl ich immer noch nicht überzeugt bin, dass es die beste Lösung ist.

Ursprünglich folgte ich dem Vorschlag von Anton und setzte die Bild-URL entsprechend in meine Controller-Aktion. Das war einfach genug, um mit dem folgenden Code:

 products.ForEach(p => 
     { 
      p.Images[0].Url = _mediaService.GetImageUrl(p.Images[0], 200); 
     }); 

Aber ich fand bald, dass dieser Ansatz mir nicht gab die Flexibilität, die ich brauchte. Oft muss ich Bilder in verschiedenen Größen anzeigen, und ich möchte dafür keine Eigenschaften meines Modells verwenden, z. B. Product.FullSizeImageUrl, Product.ThumbnailImageUrl.

Soweit "Produkt" betroffen ist, weiß es nur über die Bilder, die ursprünglich hochgeladen wurden.Es muss nicht wissen, wie wir sie manipulieren und anzeigen oder ob wir sie in Amazon S3 zwischenspeichern.

In Webformularen kann ich ein Benutzersteuerelement verwenden, um Produktdetails anzuzeigen, und dann ein Repeater-Steuerelement verwenden, um Bilder anzuzeigen und die Bild-URLs programmatisch im Code festzulegen.

fand ich, dass die Verwendung von Render in ASP.NET MVC gab mir eine ähnliche Flexibilität:

Controller Aktion:

[ChildActionOnly] 
    public ActionResult CatalogImage(CatalogImage image, int targetSize) 
    { 
     image.Url = _mediaService.GetImageUrl(image, targetSize); 
     return PartialView(image); 
    } 

Media Service:

  public MediaCacheLocation CacheLocation { get; set; } 

    public string GetImageUrl(CatalogImage image, int targetSize) 
    { 
     string imageUrl; 

     // check image exists 
     // if not exist, load original image from store (fs or db) 
     // resize and cache to relevant cache location 

     switch (this.CacheLocation) { 
      case MediaCacheLocation.FileSystem: 
       imageUrl = GetFileSystemImageUrl(image, targetSize); 
       break; 
      case MediaCacheLocation.AmazonS3: 
       imageUrl = GetAmazonS3ImageUrl(image, targetSize); 
       break; 
      default: 
       imageUrl = GetDefaultImageUrl(); 
       break; 
     } 

     return imageUrl; 
    } 

Html-Helfer:

 public static void RenderCatalogImage(this HtmlHelper helper, CatalogImage src, int size) { 
     helper.RenderAction("CatalogImage", "Catalog", new { image = src, targetSize = size }); 
    } 

Verbrauch:

<%Html.RenderCatalogImage(Model.Images[0], 200); %> 

Die jetzt gibt mir die Flexibilität, die wir benötigen und sowohl das Zwischenspeichern die verkleinerten Bilder auf der Festplatte oder das Speichern auf Amazon S3 unterstützen.

Könnte mit einigen URL-Hilfsmethoden tun, um sicherzustellen, dass die generierte Bild-URL SSL/virtuelle Ordner unterstützt - ich verwende derzeit VirtualPathUtility.

Dank Ben