2010-02-01 8 views
5

J'ai une application ASP.NET MVC dans laquelle j'affiche des images.ASP.NET MVC URL d'image générées dynamiquement

Ces images peuvent être situées sur le système de fichiers ou dans une base de données. C'est très bien car je peux utiliser Url.Action dans mon image, appeler l'action sur mon contrôleur et renvoyer l'image depuis l'emplacement approprié.

Cependant, je veux être en mesure de prendre en charge les images stockées dans Amazon S3. Dans ce cas, je ne veux pas que mon action de contrôleur retourne l'image, elle devrait plutôt générer une URL d'image pour Amazon S3.

Bien que je puisse simplement exécuter cette logique à l'intérieur de ma vue, par ex.

<% si (Model.Images [0] == .ImageLocation ImageLocation.AmazonS3) {%> // rend l'image amazone

Je dois veiller à ce que l'image existe d'abord. Essentiellement, j'ai besoin de passer une valeur de taille à mon contrôleur afin que je puisse vérifier que l'image existe dans cette taille (que ce soit dans la base de données, le système de fichiers ou amazon s3). Une fois que je suis sûr que l'image existe, je lui renvoie l'URL.

espoir qui fait sens,

Ben

Répondre

2

Essayez l'approche suivante.

Classe de modèle pour une étiquette d'image.

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

Aide

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

Voir avec Model.Images de type IEnumerable<ImageModel>

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

action

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

Une action est une sorte d'un code pseudo Cependant, l'idée devrait être claire.

+0

Merci Anton, c'est une bonne approche. Je pense que je vais créer un nouveau ViewModel pour cela car mon modèle actuel est un IList ayant IList . Il me semble préférable de mettre cela dans un nouveau modèle de vue où je peux définir des choses comme la taille d'image requise et avoir une seule image par produit (ce qui est tout ce dont j'ai besoin à mon avis). Je posterai mon code une fois terminé. –

-1

Vous pouvez créer un HttpWebRequest pour charger l'image. Vérifiez l'en-tête dans la réponse, si c'est 200, cela signifie qu'il a réussi, sinon quelque chose s'est mal passé.

+0

Salut, la principale exigence est que je suis en mesure de construire l'URL dynamique en fonction de l'où l'image « devrait » être situé. Je n'ai pas besoin d'utiliser HttpWebRequest pour vérifier que l'image existe, je peux utiliser System.IO.File.Exists pour cela ou vérifier le compartiment Amazon S3. Merci Ben –

1

Après plusieurs itérations, j'ai trouvé une solution réalisable, même si je ne suis toujours pas convaincu que c'est la meilleure solution.

À l'origine, j'ai suivi la suggestion d'Anton et j'ai simplement réglé l'URL de l'image en conséquence dans l'action de mon contrôleur. Ce fut assez simple avec le code suivant:

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

Cependant, je me suis vite trouvé que cette approche ne m'a pas donné la flexibilité dont je avais besoin. Souvent, j'ai besoin d'afficher des images de tailles différentes et je ne veux pas utiliser les propriétés de mon modèle comme Product.FullSizeImageUrl, Product.ThumbnailImageUrl.

En ce qui concerne «Produit», il ne connaît que les images qui ont été initialement téléchargées.Il n'a pas besoin de savoir comment nous les manipulons et les affichons, ou si nous les mettons en cache dans Amazon S3.

Dans les formulaires Web, je peux utiliser un contrôle utilisateur pour afficher les détails du produit, puis utiliser un contrôle répéteur pour afficher les images, en définissant les URLs de l'image dans le code par derrière.

Je trouve que l'utilisation de RenderAction dans ASP.NET MVC m'a donné une flexibilité similaire:

action Contrôleur:

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

aide Html:

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

Utilisation:

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

Cela me donne maintenant la flexibilité et je requiers soutiendra la mise en cache à la fois les images redimensionnées sur le disque ou enregistrer sur Amazon S3. Pourrait faire avec certaines méthodes d'utilitaire url pour s'assurer que l'URL de l'image générée prend en charge SSL/dossiers virtuels - J'utilise actuellement VirtualPathUtility.

Merci Ben