【问题标题】:ASP.NET MVC - ActionFilterAttribute to validate POST dataASP.NET MVC - ActionFilterAttribute 验证 POST 数据
【发布时间】:2009-10-21 14:47:25
【问题描述】:

实际上,我有一个应用程序正在使用 WebService 来检索一些客户信息。 因此,我正在验证 ActionResult 中的登录信息,例如:

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

其中 Client.Validate() 是一种根据 POST 用户名和密码提供的信息返回布尔值的方法

但是我改变了主意,我想在方法的开头使用那个不错的 ActionFilterAttributes,这样它只会在 Client.validate() 返回 true 时呈现,就像 [Authorize] 一样,但使用我的自定义webservice,所以我会有类似的东西:

[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')
}

然后在 ValidateAsClient 里面我会有类似的东西:

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

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

所以我的问题是,我不知道如何让它工作,因为我不知道如何将 POSTED 信息传递给 [ValidateAsClient(username=postedUsername,password=postedPassword)] 还有,我怎样才能使函数 ValidateAsClient 正常工作?

我希望这很容易理解 提前致谢

【问题讨论】:

    标签: asp.net-mvc post httprequest actionfilterattribute


    【解决方案1】:

    大概是这样的:

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

    并像这样使用它:

    [ValidateAsClient(HttpContext.Request.Form)]
    

    【讨论】:

    • 我认为您可以使用 filterContext.HttpContext.Request.Form 访问表单集合,而不是传递它。
    • 感谢HeavyWave 非常好,另外一个问题:在这种情况下使用ActionExecutingContext 和ActionExecutedContext 有什么区别吗?谢谢
    • ActionExecutedContext 应该用在 OnActionExecuted 方法中,该方法在控制器的 action 方法之后执行。因此,在 ActionExecutedContext 中,您可以访问某些执行结果。只需使用 IntelliSense 即可。
    【解决方案2】:

    您应该重写以下方法。

    public override void OnActionExecuting(ActionExecutingContext context)
    

    然后从上下文对象中访问您的帖子数据。

    【讨论】:

    • 检查ActionExecutingContext.RequestContext.HttpContext.Request.Form,你应该可以在那里获取post值。
    【解决方案3】:

    我认为在这种情况下使用ActionFilterAttribute 不是一个好主意。而且你想做的绝对和Authorize属性不一样。

    Authorize 属性只是将通用逻辑注入到控制器/动作中。这是:

    如果用户未登录,则重定向到登录页面。否则让操作被执行。

    您的ClientLogin 操作正在执行它目前应该执行的操作。
    将这种逻辑转移到ActionFilterAttribute 将是一个糟糕的设计。

    【讨论】:

    • 你是对的,将只应该由一个Action使用的东西变成一个属性不是一个好主意。 Authorize表示Action需要用户授权,不包含任何逻辑。
    • 是的,我明白你的意思,实际上问题是我会在整个应用程序中由客户端执行几个不同的操作,否则这将需要客户端登录它会将他重定向到登录页面。所以我认为在每个方法的开头放置一个 [ValidateAsClient] 可能会更容易和美观(因为我是 ASP.NET 的初学者,所以很抱歉应用了任何错误)。但我不确定这是否正确,感谢您的输入
    • 嗯,按照你的方式去做不会破坏任何东西。 :) 以这种方式使用属性并不完全自然。就是这样。
    【解决方案4】:

    我会在 ASP.NET MVC 中使用自定义绑定器来解决这个问题。

    假设您的操作将具有以下签名。

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

    MyParam 类:

        public class MyParameter
        {
          public string UserName{get;set;}
          public string Password {get;set;}
    
          public bool isValid
          {
            //check if password and username is valid.
          }
    
    }
    

    然后是自定义活页夹

    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.
            }
    }
    

    【讨论】:

    • 这是一个简单任务的过度设计。 @HeavyWave 提供了一个出色而简单的解决方案。
    • Tss ...我只是不知道其他方法:)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    相关资源
    最近更新 更多