2

I've got a simple question about the behavior of ActionResult in ASP.NET MVC.

I need to have two action result with the same name but different parameters. In particular I want this:

public class CarController : Controller
{
    [AuthorizeUser(AccessLevel = "New")]
    public ActionResult New()
    {
       return View("New");
    }

    [AuthorizeUser(AccessLevel = "New?type=2")]
    public ActionResult New(string type)
    {
       return View("NewCarType2");
    }
}

I know that I can rename the second action result with a different name, but if I want to keep it to "new"?

I've tried with route.maps without success. I've think to do this:

 public class CarController : Controller
{
    public ActionResult New (string type) {
        if(!string.IsNullOrEmpty(type) && type.Equals("2")) {
            return NewCarType2()
        else
            return New()
        }
    }
    [AuthorizeUser(AccessLevel = "New?type=2")]
    private ActionResult NewCarType2()
    {
        return View("NewCarType2");
    }
    [AuthorizeUser(AccessLevel = "New")]
    private ActionResult New()
    {
        return View("New");
    }
}

but the attribute for the user's authorization is ignored.. also with the method's signature public and the attribute [NoAction].

The only way that I find to do what I want is with a class inheritance:

public class CarController : Controller
{
    public virtual ActionResult New(string type)
    {
        if (!string.IsNullOrEmpty(type) && type.Equals("2"))
            return RedirectToAction("NewCarType2", "CarOverride");
        else
            return RedirectToAction("New", "CarOverride");
    }
}  
public class CarOverrideController : CarController
{
    [AuthorizeUser(AccessLevel = "New?type=2")]
    public ActionResult NewCarType2(string type)
    {
        return View("NewCarType2");
    }
    [AuthorizeUser(AccessLevel = "New")]
    public override ActionResult New(string type)
    {
        return View("New");
    }
 }

But is this the correct way to manage this situation (a part write the name of the ActionResults all different)?

Tetsujin no Oni
  • 7,300
  • 2
  • 29
  • 46
lele.lic
  • 23
  • 1
  • 3
  • Actually this is the concept of method overloading http://stackoverflow.com/a/436935/3354492 This post will answer your questions. – Puneet Mar 25 '15 at 13:32
  • Another way to manage this could be to define one as an [HttpGet] action and the other as an [HttpPost] action note: not sure that's what you want here but it works this way (anyway, parameters have to be differents) – Emmanuel M. Mar 25 '15 at 13:33
  • 2
    Definitely suggest NOT using inheritance here – timothyclifford Mar 25 '15 at 13:46
  • What logic is your AuthorizeUser attribute performing? – timothyclifford Mar 25 '15 at 13:55
  • @timothyclifford with the AuthorizeUser attribute I check the role of the user and if he has the right to display the page (with IsInRole method) – lele.lic Mar 25 '15 at 14:28

2 Answers2

1

There are 2 possibilities to do what you want.

As Puneet replied in the comment, you can overload the method in the controller as mentioned in this post.

[ActionName("MyOverloadedName")]

or

You can define a Route attribute on the controller method and route the action from a different URL to this method. For further explanation go to the ASP.NET Tutorial.

 [Route("URL")]
public ActionResult New(string type) { ... }
Community
  • 1
  • 1
greenhoorn
  • 1,601
  • 2
  • 15
  • 39
  • But with the first possibility I must to call 2 different URL ("new" and "newOverloaded"), right? Can i have the same URL ("new") and the choise will done about the presence or less of the parameter? – lele.lic Mar 25 '15 at 14:24
  • 1
    Another possibility is to define 1 method with an optional parameter. So you just have 1 action in your controller and either your parameter is null or set as default (if the user provides no data). Is this what you want? https://msdn.microsoft.com/en-us/library/dd410269%28v=vs.100%29.aspx – greenhoorn Mar 25 '15 at 14:38
  • Yes, i think is a way.. I'll do one method with optional parameter and if the value will be empty I will check the authorization for one role, otherwise for another. If the check result will be true i'll show the page. Instead with [Route("URL")] I can specify an url like 'Car/New?type=2' and the Action associated responds only at this? – lele.lic Mar 25 '15 at 15:22
  • @DanieleLicini Yes, that's what I meant. Hope it'll work for you :) – greenhoorn Mar 25 '15 at 15:24
0

I would question why you need two routes with the same name which are doing two different things?

If all your AuthorizeUser attribute is doing is checking the user's role, why not do something similar to:

public ActionResult New(string type)
{
    if (!string.IsNullOrWhiteSpace(type) && User.IsInRole("YOUR-ROLE-HERE"))
    {
        // Display NewCarType2 view if type requested and user is in correct role
        return View("NewCarType2");
    }

    // Default to New view if no type requested or user not in role
    return View("New");
}

This will catch both /new and /new?type=foo requests.

timothyclifford
  • 6,799
  • 7
  • 57
  • 85
  • The two routes do almost the same things: for example the visualization of the content is different. Your answer is what I have think to do, but the only difference is that AuthorizeUser's attribute not only checks the user's role with IsInRole. I will take the logic of this Authorization in a method and I will use it in the ActionResult. – lele.lic Mar 30 '15 at 07:30
  • If they're doing almost the same thing then you could probably argue they should be in the same route. Are you saying this answers your question or is there more information you need? – timothyclifford Mar 30 '15 at 13:15