具有相同动作名称的多个动作
Multiple actions with same action name
我的控制器中有多个这样的操作
public ActionResult Verify(String email, String name ){
ViewBag.email = email;
ViewBag.name = name;
return View();
}
[HttpGet]
public ActionResult Verify(String uId){
User user = TippNett.Core.User.Get(uId);
user.Active = true;
user.Save();
Auth.Authenticate(user, false);
return RedirectToAction("Index", "Home");
}
第一个动作是用户注册时给他看注册信息,请验证邮箱,我是这样称呼的
return RedirectToAction("Verify", "Account", new { email = email, name = user.FirstName});
当用户点击验证时调用第二个动作link。
问题是下面的函数总是被调用。即使我也将电子邮件和名称作为参数传递。
任何人都可以解释为什么会发生这种情况并可能解决这个问题吗?
您应该使用 HttpPost 属性,请参阅:
了解更多信息。
您可以使用:
[ActionName("MyOverloadedName")]
或
method overloading based on attribute:
[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }
[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
public RequireRequestValueAttribute(string valueName) {
ValueName = valueName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
return (controllerContext.HttpContext.Request[ValueName] != null);
}
public string ValueName { get; private set; }
}
但是,对于同一个 http 方法,您必须使用不同的操作名称 您只能在使用不同的 http 方法时使用相同的方法。
喜欢:
[HttpPost]
public ActionResult Verify(String email, String name ){
}
[HttpGet]
public ActionResult Verify(String uId){
User user = TippNett.Core.User.Get(uId);
user.Active = true;
user.Save();
Auth.Authenticate(user, false);
return RedirectToAction("Index", "Home");
}
最近我借此机会进一步完善@Tushar 的伟大 RequireRequestValueAttribute
以使其支持更多场景,例如多参数支持和会触发它的不同类型的匹配:所有给定参数,任何其中之一甚至 none.
我调用了新版本 RequiredParameterAttribute
,并且在我最终使用的所有 MVC 项目中都使用了它。
完整的源代码如下:
/// <summary>
/// Flags an Action Method valid for any incoming request only if all, any or none of the given HTTP parameter(s) are set,
/// enabling the use of multiple Action Methods with the same name (and different signatures) within the same MVC Controller.
/// </summary>
public class RequireParameterAttribute : ActionMethodSelectorAttribute
{
public RequireParameterAttribute(string parameterName) : this(new[] { parameterName })
{
}
public RequireParameterAttribute(params string[] parameterNames)
{
ParameterNames = parameterNames;
IncludeGET = true;
IncludePOST = true;
IncludeCookies = false;
Mode = MatchMode.All;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
switch (Mode)
{
case MatchMode.All:
default:
return (
(IncludeGET && ParameterNames.All(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
|| (IncludePOST && ParameterNames.All(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
|| (IncludeCookies && ParameterNames.All(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
case MatchMode.Any:
return (
(IncludeGET && ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
|| (IncludePOST && ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
|| (IncludeCookies && ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
case MatchMode.None:
return (
(!IncludeGET || !ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
&& (!IncludePOST || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
&& (!IncludeCookies || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
}
}
public string[] ParameterNames { get; private set; }
/// <summary>
/// Set it to TRUE to include GET (QueryStirng) parameters, FALSE to exclude them:
/// default is TRUE.
/// </summary>
public bool IncludeGET { get; set; }
/// <summary>
/// Set it to TRUE to include POST (Form) parameters, FALSE to exclude them:
/// default is TRUE.
/// </summary>
public bool IncludePOST { get; set; }
/// <summary>
/// Set it to TRUE to include parameters from Cookies, FALSE to exclude them:
/// default is FALSE.
/// </summary>
public bool IncludeCookies { get; set; }
/// <summary>
/// Use MatchMode.All to invalidate the method unless all the given parameters are set (default).
/// Use MatchMode.Any to invalidate the method unless any of the given parameters is set.
/// Use MatchMode.None to invalidate the method unless none of the given parameters is set.
/// </summary>
public MatchMode Mode { get; set; }
public enum MatchMode : int
{
All,
Any,
None
}
}
我保留了 "old" 签名,因此它可以像上一期一样使用。
有关更多信息和一些实施示例,请查看我就此主题撰写的 this blog post。
我的控制器中有多个这样的操作
public ActionResult Verify(String email, String name ){
ViewBag.email = email;
ViewBag.name = name;
return View();
}
[HttpGet]
public ActionResult Verify(String uId){
User user = TippNett.Core.User.Get(uId);
user.Active = true;
user.Save();
Auth.Authenticate(user, false);
return RedirectToAction("Index", "Home");
}
第一个动作是用户注册时给他看注册信息,请验证邮箱,我是这样称呼的
return RedirectToAction("Verify", "Account", new { email = email, name = user.FirstName});
当用户点击验证时调用第二个动作link。 问题是下面的函数总是被调用。即使我也将电子邮件和名称作为参数传递。
任何人都可以解释为什么会发生这种情况并可能解决这个问题吗?
您应该使用 HttpPost 属性,请参阅:
了解更多信息。
您可以使用:
[ActionName("MyOverloadedName")]
或
method overloading based on attribute:
[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }
[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
public RequireRequestValueAttribute(string valueName) {
ValueName = valueName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
return (controllerContext.HttpContext.Request[ValueName] != null);
}
public string ValueName { get; private set; }
}
但是,对于同一个 http 方法,您必须使用不同的操作名称 您只能在使用不同的 http 方法时使用相同的方法。 喜欢:
[HttpPost]
public ActionResult Verify(String email, String name ){
}
[HttpGet]
public ActionResult Verify(String uId){
User user = TippNett.Core.User.Get(uId);
user.Active = true;
user.Save();
Auth.Authenticate(user, false);
return RedirectToAction("Index", "Home");
}
最近我借此机会进一步完善@Tushar 的伟大 RequireRequestValueAttribute
以使其支持更多场景,例如多参数支持和会触发它的不同类型的匹配:所有给定参数,任何其中之一甚至 none.
我调用了新版本 RequiredParameterAttribute
,并且在我最终使用的所有 MVC 项目中都使用了它。
完整的源代码如下:
/// <summary>
/// Flags an Action Method valid for any incoming request only if all, any or none of the given HTTP parameter(s) are set,
/// enabling the use of multiple Action Methods with the same name (and different signatures) within the same MVC Controller.
/// </summary>
public class RequireParameterAttribute : ActionMethodSelectorAttribute
{
public RequireParameterAttribute(string parameterName) : this(new[] { parameterName })
{
}
public RequireParameterAttribute(params string[] parameterNames)
{
ParameterNames = parameterNames;
IncludeGET = true;
IncludePOST = true;
IncludeCookies = false;
Mode = MatchMode.All;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
switch (Mode)
{
case MatchMode.All:
default:
return (
(IncludeGET && ParameterNames.All(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
|| (IncludePOST && ParameterNames.All(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
|| (IncludeCookies && ParameterNames.All(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
case MatchMode.Any:
return (
(IncludeGET && ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
|| (IncludePOST && ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
|| (IncludeCookies && ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
case MatchMode.None:
return (
(!IncludeGET || !ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
&& (!IncludePOST || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
&& (!IncludeCookies || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
);
}
}
public string[] ParameterNames { get; private set; }
/// <summary>
/// Set it to TRUE to include GET (QueryStirng) parameters, FALSE to exclude them:
/// default is TRUE.
/// </summary>
public bool IncludeGET { get; set; }
/// <summary>
/// Set it to TRUE to include POST (Form) parameters, FALSE to exclude them:
/// default is TRUE.
/// </summary>
public bool IncludePOST { get; set; }
/// <summary>
/// Set it to TRUE to include parameters from Cookies, FALSE to exclude them:
/// default is FALSE.
/// </summary>
public bool IncludeCookies { get; set; }
/// <summary>
/// Use MatchMode.All to invalidate the method unless all the given parameters are set (default).
/// Use MatchMode.Any to invalidate the method unless any of the given parameters is set.
/// Use MatchMode.None to invalidate the method unless none of the given parameters is set.
/// </summary>
public MatchMode Mode { get; set; }
public enum MatchMode : int
{
All,
Any,
None
}
}
我保留了 "old" 签名,因此它可以像上一期一样使用。
有关更多信息和一些实施示例,请查看我就此主题撰写的 this blog post。