2009-10-21 23 views
5

En fait, j'ai une application qui utilise un WebService pour récupérer des informations sur certains clients. Je validais les informations de connexion dans mon ActionResult comme:ASP.NET MVC - ActionFilterAttribute pour valider les données POST

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult ClientLogin(FormCollection collection) 
{ 
    if(Client.validate(collection["username"], collection["password"])) 
    { 
     Session["username"] = collection["username"]; 
     Session["password"] = collection["password"]; 
     return View("valid"); 
    } 
    else 
    { 
     Session["username"] = ""; 
     Session["password"] = ""; 
     return View("invalid"); 
    } 
} 

Où Client.Validate() est une méthode qui retourne un booléen sur la base des informations fournies sur le nom d'utilisateur et mot de passe POST

Mais je J'ai changé d'avis et je voudrais utiliser ce bon ActionFilterAttributes au début de la méthode pour qu'il soit rendu si le Client.validate() renvoie true, juste le même que [Authorize] mais avec mon webservice personnalisé, donc je le ferais avoir quelque chose comme:

[AcceptVerbs(HttpVerbs.Post)] 
[ValidateAsClient(username=postedUsername,password=postedPassword)] 
//Pass Posted username and password to ValidateAsClient Class 
//If returns true render the view 
public ActionResult ClientLogin() 
{ 
    return View('valid') 
} 

puis à l'intérieur du ValidateAsClient j'aurais quelque chose comme:

public class ValidateAsClient : ActionFilterAttribute 
{ 
    public string username { get; set; } 
    public string password { get; set; } 

    public Boolean ValidateAsClient() 
    { 
     return Client.validate(username,password); 
    } 
} 

Donc mon problème est, je ne sais pas exactement comment le faire fonctionner, parce que je ne sais pas comment transmettre l'information figurant sur le [ValidateAsClient (nom d'utilisateur = nomUtilisateur, motdepasse = motPosté)] et aussi, comment pourrais-je faire fonctionner la fonction ValidateAsClient correctement?

J'espère que cela est facile à comprendre Merci à l'avance

Répondre

7

Quelque chose comme ça probablement:

[AttributeUsage(AttributeTargets.All)] 
public sealed class ValidateAsClientAttribute : ActionFilterAttribute 
{ 
    private readonly NameValueCollection formData; 
    public NameValueCollection FormData{ get { return formData; } } 

    public ValidateAsClientAttribute (NameValueCollection formData) 
    { 
     this.formData = formData; 
    } 

    public override void OnActionExecuting 
       (ActionExecutingContext filterContext) 
    { 
     string username = formData["username"]; 
     if (string.IsNullOrEmpty(username)) 
     { 
      filterContext.Controller.ViewData.ModelState.AddModelError("username"); 
     } 
     // you get the idea 
    } 
} 

Et l'utiliser comme ceci:

[ValidateAsClient(HttpContext.Request.Form)] 
+10

Je pense que vous pouvez accéder à la collection de formulaires avec 'filterContext.HttpContext.Request.Form', au lieu de le passer. –

+0

merci pour ce HeavyWave très bon, une autre question: Y at-il une différence entre utiliser ActionExecutingContext et ActionExecutedContext dans ce cas? Merci – zanona

+0

ActionExecutedContext est censé être utilisé dans la méthode OnActionExecuted, qui s'exécute après la méthode d'action du contrôleur. Ainsi, dans ActionExecutedContext, vous avez accès à certains des résultats de l'exécution. Jouez juste avec IntelliSense. –

5

Vous devez remplacer la méthode suivante.

public override void OnActionExecuting(ActionExecutingContext context) 

Et à partir de l'objet de contexte, accédez à vos données de publication.

+0

Cochez ActionExecutingContext.RequestContext.HttpContext.Request.Form et vous devriez être en mesure d'y saisir la valeur du message. –

1

Je résoudrais ce problème avec un classeur personnalisé dans ASP.NET MVC.

Supposons que votre action aura la signature suivante.

public ActionResult MyAction(MyParameter param) 
{ 
    if(param.isValid) 
    return View("valid"); 
    else 
    return View("invalid"); 
} 

classe MyParam:

public class MyParameter 
    { 
     public string UserName{get;set;} 
     public string Password {get;set;} 

     public bool isValid 
     { 
     //check if password and username is valid. 
     } 

} 

Un puis le liant personnalisé

public class CustomBinder:IModelBinder 
{ 
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
     { 
      var p = new MyParam(); 
      // extract necessary data from the bindingcontext like 
      p.UserName = bindingContext.ValueProvider["username"] != null 
         ? bindingContext.ValueProvider["username"].AttemptedValue 
         : ""; 
      //initialize other attributes. 
     } 
} 
+0

c'est un over design pour une tâche simple. @HeavyWave fourni une solution excellente et simple. – reflog

+0

Tss ... Je ne savais pas simple d'autres façons de le faire :). –

3

Je ne pense pas que ce soit une bonne idée d'utiliser un ActionFilterAttribute dans ce cas. Et ce que vous voulez faire n'est certainement pas la même chose que l'attribut Authorize.

L'attribut Authorize injecte simplement une logique commune dans un contrôleur/une action. Lequel est:

Rediriger vers la page de connexion, si l'utilisateur n'est pas connecté. Sinon, laissez l'action s'exécuter.

Votre action ClientLogin fait exactement ce qu'il est censé faire en ce moment.
Ce serait une mauvaise conception de porter cette logique sur un ActionFilterAttribute.

+0

Vous avez raison, ce n'est pas une bonne idée de transformer quelque chose qui ne devrait être utilisé que par une action dans un attribut. Autoriser indique que l'action nécessite que l'utilisateur soit autorisé, il ne contient aucune logique. –

+0

Oui, je comprends que vous pointez, en fait le problème est que j'aurais quelques actions différentes à effectuer par le client partout dans l'application, et cela nécessiterait le client d'être connecté sinon il serait le rediriger vers un page de connexion. Donc je pensais que cela pourrait être beaucoup plus facile et beau (comme je peux le dire pour le moment puisque je suis un ASP.NET commencé, désolé pour tout ce qui est faux) de mettre un [ValidateAsClient] au début de chaque méthode . Mais je ne suis pas sûr que ce soit correct, merci pour vos entrées – zanona

+0

Eh bien, ça ne casserait rien pour le faire à votre façon. :) Juste pas tout à fait naturel d'utiliser l'attribut de cette façon. C'est tout. –