我对MVC很新,正在寻找一些急需的指导。
目标是确定用户何时针对任何给定操作敲打墙壁,并将其重定向到包含“帮助台”联系信息的其他页面。
我的代码功能齐全但丑陋且不太可重用。 (验证在ViewModel中处理):
[HttpPost]
public ActionResult MyForm(MyForm model)
{....
if (ModelState.IsValid){..... return RedirectToAction("Success")}
var attempts = Convert.ToInt32(TempData["Attempts"]);
if (attempts >= 3)
{
TempData["LocalMessages"] = new Message
{
Class = "Alert",
Text =
"It looks like you are having trouble ...Please Contact...."
};
return RedirectToAction("HelpDesk");
}
attempts += 1;
TempData["Attempts"] = attempts;
return View(model);
理想的解决方案是利用动作过滤器等功能,以便我可以针对任何给定的操作执行以下操作:
[HttpPost, MaximumAttemptBeforeRedirect(4, "HelpDesk")]
public ActionResult MyForm(MyForm model)
非常感谢任何帮助。
答案 0 :(得分:1)
您可以将尝试次数包括为视图模型的属性:
[HttpPost]
public ActionResult MyForm(MyForm model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Success");
}
ModelState.Remove("Attempts");
model.Attempts++;
if (model.Attempts >= 3)
{
TempData["LocalMessages"] = new Message
{
Class = "Alert",
Text = "It looks like you are having trouble ...Please Contact...."
};
return RedirectToAction("HelpDesk");
}
return View(model);
}
并在表单中包含尝试作为隐藏字段的次数:
<%= Html.HiddenFor(x => x.Attempts) %>
答案 1 :(得分:1)
我找到了我想要的东西(我在博客文章http://bradwilson.typepad.com/blog/2011/02/advanced-aspnet-mvc-3-presentation.html中使用了Brian Wilson的Stateful Storage课程):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MaximumAttemptBeforeRedirectAttribute : FilterAttribute, IActionFilter
{
readonly IStatefulStorage _storage = StatefulStorage.PerSession;
private readonly int _maxAttempt;
private readonly RedirectToRouteResult _newRoute;
private string _keyName;
public MaximumAttemptBeforeRedirectAttribute(int attempts, string controller, string action)
{
_maxAttempt = attempts;
var rvDic = new RouteValueDictionary {{"action", action}, {"controller", controller}};
_newRoute = new RedirectToRouteResult(rvDic);
}
Attempts GetCount(string name)
{
return _storage.GetOrAdd(name, () => new Attempts());
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
_keyName = string.Format("{0}{1}Attempts",
filterContext.RouteData.Values["controller"],
filterContext.RouteData.Values["action"]
);
var errCount = filterContext.Controller.ViewData.ModelState.Values.Where(v => v.Errors.Count != 0).Count();
if (errCount > 0) //If errors, increment attempt count by 1
{
GetCount(_keyName).Increment();
}
else //If no errors, reset attempt count.
{
GetCount(_keyName).Reset();
}
if (GetCount(_keyName).Number < _maxAttempt) return; //user is within allowed threshold for validation attempts so stop here.
//Do we give the user the opportunity to navigate back to the page and try again in durring life of current session?
GetCount(_keyName).Reset(); //user can now go back to the page again and try another x times.
var route = string.Format("{0}/{1}", filterContext.RouteData.Values["controller"],
filterContext.RouteData.Values["action"]);
Logger.WarnFormat("Max Attempts were reached for {0}/{1}", filterContext.RouteData.Values["controller"], filterContext.RouteData.Values["action"]);
filterContext.Controller.TempData["LocalMessages"] = new Message
{
Class = "Alert",
Text = "You have exceeded the allowed number of attempts for " + route
};
filterContext.Result = _newRoute;
}
}
这允许我将以下内容添加到我的ActionResult或我的控制器:
[HttpPost, MaximumAttemptBeforeRedirect(4, "MyController", "SomeAction")]