2010-08-05 7 views
2

Est-ce une odeur de code à avoir à suivre modèle, compte tenu du code suivant (très simplifié pour aller droit au but)?HtmlHelper construire une liste déroulante, en utilisant ServiceLocator: odeur de code?

Les modèles:

class Product 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Category Cat { get; set; } 
} 

class Category 
{ 
    public int Id { get; set; } 
    public string Label { get; set; } 
} 

La vue de modifier un produit:

<% =Html.EditorFor(x => x.Name) %> 
<% =Html.EditorFor(x => x.Category) %> 

Le EditorTemplate pour la catégorie

<% =Html.DropDownList<Category>() %> 

La méthode HtmlHelper

public static MvcHtmlString DropDownList<TEntity>(this HtmlHelper helper) 
    where TEntity : Entity 
{ 
    var selectList = new SelectList(
     ServiceLocator.GetInstance<SomethingGivingMe<TEntity>>().GetAll(), 
     "Id", "Label"); 

    return SelectExtensions.DropDownList(helper, "List", selectList, null, null); 
} 

Pour plus d'informations, la mise en œuvre réelle de la méthode d'assistance prend quelques lambdas pour obtenir les noms DataTextField et DataValueField, la valeur sélectionnée, etc.

Le point qui me tracasse avec une ServiceLocator à l'intérieur du HtmlHelper. Je pense que je devrais avoir une propriété AllCategories dans mon modèle de produit, mais je devrais être rempli dans le contrôleur chaque fois que j'en ai besoin. Donc je pense que la solution que j'utilise est plus simple, car la méthode auxiliaire est générique (et le modelbinder n'est pas inclus ici). Donc je dois juste créer un EditorTemplate pour chaque type qui a besoin d'une DropDownList.

Un conseil?

Répondre

-1

à mon humble avis, je laisserais la façon dont il est, la même chose dans un autre projet. Mais l'emplacement du service me dérangeait aussi donc pour un autre projet j'ai fait cette partie d'un ActionFilter qui scanne un modèle, trouve toutes les listes déroulantes anticipées et fait un chargement par lots dans ViewData. Comme le ServiceLocator ou le Repository/Context/whatever est déjà injecté dans le Controller, vous n'avez pas à étendre votre emplacement de service partout.

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    foreach(var anticipated in SomeDetectionMethod()) 
    { 
      var selectList = new SelectList(
    ServiceLocator.GetInstance<SomethingGivingMe<TEntity>>().GetAll(), 
    "Id", "Label"); 

     ViewData["SelectList." + anticipated.Label/Name/Description"] = selectList; 
    } 
} 

Dans la vue, vous pouvez alors faire une aide pour charger les listes déroulantes via un modèle d'éditeur personnalisé ou une autre méthode.

+0

Idée semble bien, a juste besoin d'un peu de code de l'infrastructure. Pourquoi les downvotes? – mathieu

+0

Wow. Tout le monde que j'ai montré cette technique aussi est étonné par cela. Je ne suis pas sûr de savoir quel est le problème ici. – jfar

-1

conseil: regardez l'exemple d'application mvc asp.net d'ici: http://valueinjecter.codeplex.com/ bonne chance;)

Voici comment l'exemple d'application de ValueInjecter pourrait obtenir les listes déroulantes: (mais il ne le fait pas en ce moment parce que je « m ok avec la chose Resolve)

public class CountryToLookup : LoopValueInjection<Country, object> 
{ 
    ICountryRepo _repo; 

    public CountryToLookup(ICountryRepository repo) 
    { 
     _repo = repo; 
    } 

    protected override object SetValue(Country sourcePropertyValue) 
    { 
     var value = sourcePropertyValue ?? new Country(); 
     var countries = _repo.GetAll().ToArray(); 
     return 
      countries.Select(
       o => new SelectListItem 
         { 
          Text = o.Name, 
          Value = o.Id.ToString(), 
          Selected = value.Id == o.Id 
         }); 
    } 
} 
+0

Comment ValueInjector se rapporte-t-il à cette question? – jfar

+0

@jfar Je parlais de l'application exemple, qui est faite sur asp.net-mvc et a beaucoup de dropdwons – Omu

+0

@Omu, chaque application n'a pas beaucoup de listes déroulantes? ;) – jfar