mohsinali1317
mohsinali1317

Reputation: 4425

Multiple actions with same action name

I have multiple action in my controller like this

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

The first action is when the user registers to show him the registration message that please verify the email and I am calling it like this

return RedirectToAction("Verify", "Account", new { email = email, name = user.FirstName});

The second action is being called when the user clicks on the verification link. The issue is this that the below function is being called always. Even when I pass email and name as parameters as well.

Can anyone explain why this happens and possibly a work around this?

Upvotes: 2

Views: 4887

Answers (3)

Darkseal
Darkseal

Reputation: 9564

Recently I took the chance to further refine @Tushar's great RequireRequestValueAttribute to make it support additional scenarios, such as multiple parameter support and different kind of matches that would trigger it: all of the given parameters, any one of them or even none.

I called the new version RequiredParameterAttribute and I'm using it in all MVC projects I end up working with.

Here's the full source code:

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

I kept the "old" signature so it can be used just like the previous installment.

For further info and some implementation samples check out this blog post that I wrote on this topic.

Upvotes: 0

Tushar Gupta
Tushar Gupta

Reputation: 15913

You can use:

[ActionName("MyOverloadedName")]

or

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

But, you'll have to use a different action name for the same http method as you can only have the same method when using different http methods. Like:

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

Upvotes: 2

Dujskan
Dujskan

Reputation: 125

You should use the HttpPost attribute see:

HttpPost vs HttpGet attributes in MVC: Why use HttpPost?

for more information.

Upvotes: -1

Related Questions