Arif YILMAZ
Arif YILMAZ

Reputation: 5876

how to overload controllers in MVC

I am trying to overload the MVC controllers, how can I overload it properly?

I want to list all companies in my website in a ListCompanies() controller like below

http://localhost:21047/Home/ListCompanies

and I want to add search criteria if user makes a search like below

http://localhost:21047/Home/ListCompanies/sera

"sera" is my search criteria. if search criteria exist, I want to filter my search result according to the search criteria.

here are my controllers

public ActionResult ListCompanies()
{
   return View(db.AY_COMPANIES);
}

[ActionName("ListCompaniesFilter")]
public ActionResult ListCompanies(string filter)
{
    var filtredCompanies = from c in db.AY_COMPANIES
                  where c.COMPANY_FULL_NAME.StartsWith(filter)
                               select c;
    return View(filtredCompanies);
}

and here is my ROUTING which behaves not correctly.

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Home", // Route name
            "{controller}/{action}/{filter}", // URL with parameters
            new { controller = "Home", action = "ListCompanies", filter = UrlParameter.Optional} // Parameter defaults
        );
    }

My MapRoutes are not correct because it doesnt get the search criteria properly. how can I fix this?

Upvotes: 0

Views: 542

Answers (3)

Erik Philips
Erik Philips

Reputation: 54656

First these routes are exactly the same:

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index",
              id = UrlParameter.Optional } // Parameter defaults
    );

    routes.MapRoute(
        "Home", // Route name
        "{controller}/{action}/{filter}", // URL with parameters
        new { controller = "Home", action = "ListCompanies", 
              filter = UrlParameter.Optional} // Parameter defaults
    );

They are exactly the same because the number of parameters exactly match (what you name parameters nor the parameter type does not change the signature of the http request method).

There are few different ways to make this work. You could write a MapRoute Constraint for Default that would prevent it from working if the controller/action/id matched a specific set of criteria. Probably not the best course of action.

Since

http://localhost:21047/Home/ListCompanies http://localhost:21047/Home/ListCompanies/sera http://localhost:21047/Home/ListCompanies/text http://localhost:21047/Home/ListCompanies/search

are programmatically the same request with {id} having a null value for your method ListCompanies() I would probably write it like:

public ActionResult ListCompanies(string id)
{
  var query = db.AY_COMPANIES;

  if (!string.IsNullOrWhiteSpace(id))
  {
    query.Where(c => c.COMPANY_FULL_NAME.StartsWith(id))
  }

  var model = query.ToList();

  return View(model);
}

And remove your "Home" MapRoute, it won't be needed.

Upvotes: 2

Tillman Dickson
Tillman Dickson

Reputation: 36

You can't overload in this manner because there is dispatch issue due to two routes on having the same three parts, they are essentially the same.

"{controller}/{action}/{id}"

and

"{controller}/{action}/{filter}"

One way is to collapse the two action methods into one

public ActionResult ListCompanies(string filter)

then if filter is null return the full list else return the filtered list. I am not fond of this approach.

A better yet simple way to fix this is:

1) remove the second route (the one with the filter)

2) change the signature of the action method from

public ActionResult ListCompanies(string filter)

to

public ActionResult ListCompanies(string id)

allowing the first route to match the parameter on name.

3) Since you can't overload methods you'll need to use your ActionName when requesting the filtered result,

 http://localhost:21047/Home/ListCompaniesFilter/sera

Upvotes: 2

DixonD
DixonD

Reputation: 6638

What happens if you have only one action with an optional parameter? Something like as the following:

public ActionResult ListCompanies(string filter = null)
{
    var filteredCompanies = string.IsNullOrEmpty(filter)
         ? db.AY_COMPANIES
         : from c in db.AY_COMPANIES
           where c.COMPANY_FULL_NAME.StartsWith(filter)
           select c;
    return View(filteredCompanies);
}

Upvotes: 1

Related Questions