2009-11-01 13 views
1

Tenir compte de cette MapRoute:objets personnalisés comme arguments dans les méthodes de régulation définies par MapRoutes

MapRoute(
    "ResultFormat", 
    "{controller}/{action}/{id}.{resultFormat}", 
    new { controller = "Home", action = "Index", id = 0, resultFormat = "json" } 
); 

Et c'est la méthode de commande:

public ActionResult Index(Int32 id, String resultFormat) 
{ 
    var dc = new Models.DataContext(); 

    var messages = from m in dc.Messages where m.MessageId == id select m; 

    if (resultFormat == "json") 
    { 
     return Json(messages, JsonRequestBehavior.AllowGet); // case 2 
    } 
    else 
    { 
     return View(messages); // case 1 
    } 
} 

Voici les scénarios d'URL

  • Home/Index/1 ira à case 1
  • Home/Index/1.html ira au cas 1
  • Home/Index/1.json ira au cas 2

Cela fonctionne bien. Mais je déteste vérifier pour les chaînes. Comment implémenter un enum à utiliser comme paramètre resultFormat dans la méthode du contrôleur?


Certains pseudo-code pour expliquer l'idée de base:

namespace Models 
{ 
    public enum ResponseType 
    { 
     HTML = 0, 
     JSON = 1, 
     Text = 2 
    } 
} 

Le MapRoute:

MapRoute(
    "ResultFormat", 
    "{controller}/{action}/{id}.{resultFormat}", 
    new { 
     controller = "Home", 
     action = "Index", 
     id = 0, 
     resultFormat = Models.ResultFormat.HTML 
    } 
); 

La signature de la méthode de commande:

public ActionResult Index(Int32 id, Models.ResultFormat resultFormat) 

Répondre

0

C'est le ActionFilter je suis venu avec:

public sealed class AlternateOutputAttribute : 
        ActionFilterAttribute, IActionFilter 
{ 
    void IActionFilter.OnActionExecuted(ActionExecutedContext aec) 
    { 
     ViewResult vr = aec.Result as ViewResult; 

     if (vr == null) return; 

     var aof = aec.RouteData.Values["alternateOutputFormat"] as String; 

     if (aof == "json") aec.Result = new JsonResult 
     { 
      JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
      Data = vr.ViewData.Model, 
      ContentType = "application/json", 
      ContentEncoding = Encoding.UTF8 
     }; 
    } 
} 
3

à mon humble avis le format de réponse est préoccupation transversale et ce n'est pas le contrôleur de jouer avec elle. Je vous suggère d'écrire un ActionFilter pour ce poste:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
public sealed class RespondToAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     var resultFormat = filterContext.RouteData.Values["resultFormat"] as string ?? "html"; 
     ViewResult viewResult = filterContext.Result as ViewResult; 
     if (viewResult == null) 
     { 
      // The controller action did not return a view, probably it redirected 
      return; 
     } 
     var model = viewResult.ViewData.Model; 
     if (string.Equals("json", resultFormat, StringComparison.OrdinalIgnoreCase)) 
     { 
      filterContext.Result = new JsonResult { Data = model }; 
     } 
     // TODO: you could add some other response types you would like to handle 
    } 
} 

qui simplifie alors votre action du contrôleur un peu:

[RespondTo] 
public ActionResult Index(int id) 
{ 
    var messages = new string[0]; 
    if (id > 0) 
    { 
     // TODO: Fetch messages from somewhere 
     messages = new[] { "message1", "message2" }; 
    } 
    return View(messages); 
} 

Le ActionFilter est un composant réutilisable que vous pouvez appliquer à d'autres actions.

+0

Je ne peux pas travailler votre exemple de code. J'ai posté une nouvelle question ici: http://stackoverflow.com/questions/1662216/return-jsonresult-using-an-actionfilter-on-a-controller Serait génial si vous jetez un coup d'oeil – roosteronacid

+0

Quels problèmes particuliers aviez-vous? Comme suggéré comme réponse dans votre autre question, vous devez remplacer la méthode OnActionExecuted au lieu de OnResultExecuting, car cette dernière s'exécute avant l'action du contrôleur et le modèle sera toujours 'null'. –

0

Votre pseudo code fonctionnera correctement. ModelBinder par défaut convertit automatiquement la chaîne dans l'URL en Models.ResultFormat enum. Mais il serait préférable de faire ActionFilter, comme l'a dit Darin Dimitrov.